Sysadmin is an essential skill for game development. These blogposts are my thoughts or my finding about sysadmin that I couldn't find on the internet.

Recent Blogposts of Sysadmin

Whack-a-mole over Telephone: Part 2 - Technical Details

Jan. 14, 2017, 6:20 p.m. Behind the Scenes Sysadmin WhackAMole

Hey guys! Finally I got time to blog about the technical details behind the whack-a-mole game.

Click here to view the previous part of this blog post, which is a release announcement of this game.


The game is powered by Dinbo Prototype A, which is a telephone system that I developed using SIM900A module with Raspberry Pi 3.

The schematics diagram of the system is shown below:


I knew. This system is stupid. Instead of connecting the mic and speaker of SIM900A with Raspberry Pi, GPIO is used for voice communication between them. To make the thing even funnier, an ATtiny13 is used as an ADC.

Anyway, this is just an early prototype. I just wanted to tinker around with the electronic parts that I have. And this design suits the purpose very well. More importantly, this system works. :P

Here is how does the SIM900A and ATtiny13 look like after everything is connected:

Connected circuit

As shown above, the entire system is deployed on a breadboard.

Due to the high current requirement, multiple breadboard wires is required for the power supply of SIM900A. A capacitor is also connected between VCC and GND to smooth the voltage level over time(not shown on the outdated photo above).


Many programs were written for this system. They are ATtiny13 ADC program, serial multiplexer program, voice to socket program, and the whack-a-mole program. All of these programs are written in C.

The ATtiny13 ADC program, as its name suggests, is a program installed on the microcontoller for the purpose of converting the analog voice signal from SIM900A to time-based digital signal. When a "get sample" signal is received by PB1, it will read the analog input of PB3 send a digitized signal via PB4 to Raspberry Pi. This is the first non-Arduino embedded program I have ever developed. I had some fun on reading the specification of ATtiny13. The library avr-libc was used.

The voice to socket program is a program that converts the digitized audio signal received from the ATtiny, then send it to the whack-a-mole program using unix socket file. This is the first real time program I have developed in my life. To achieve real time execution of code, a CPU core is reserved solely for the linux process of this program.

The serial multiplexer allows multiple programs write to the serial interface of SIM900A. It redirects all of the data received from socket to the serial interface. It is adapted from this program found on Stack Overflow.

The Whack-a-mole program works by communicating with the serial multiplexer as well as the voice to socket program. It also detects DTMF tones by processing the audio signal received. Other than that, it is just like other C programs.

The source code of these programs are poorly organized. I still don't have time to package them. There are also some copyright issue on the serial multiplexer because majority of code is taken from the Stack Overflow answer with unspecified license. Therefore, I cannot release these programs too publicly. However, a copy of source code can be requested by email and they are considered on case-by-case basis.

Future Development

For the final year project of my college, the development of Dinbo Prototype B is started, which will be a successor of the current system. Standard analog audio interface will be used(instead of doing the analog<->digital conversion hack using GPIOs). I also plan to solder it on a perfboard.

The library will be written in Python, which is much more flexible than C. It will be mainly designed for non-game telephone systems. However, it should be possible to make a game with it. After the completion of the library, I'll port this game to Dinbo Prototype B. I will update you guys about any news on it.

Solution to CUPS Claiming Print Job Completed Despite Printing Nothing

May 10, 2016, 1:42 p.m. Sysadmin


The system runs out of RAM


Kill RAM intensive processes, or use swap.

How Did I Run into This Problem?

I have installed CUPS on my Raspberry Pi. It was connected to a USB printer and made it accessible via my LAN. It had been working very well until the recent. In these few weeks, somehow the printer does not print.

I entered the CUPS web interface of my Raspberry Pi and tried printing a test page. Funny enough. It claimed that the print job was completed, despite that the printer did nothing.

Then I dig up /var/log/cups/access_log. Here is what's inside.

localhost - - [10/May/2016:14:37:12 +0800] "POST /printers/Canon_MG2400_series HTTP/1.1" 200 422 Print-Job successful-ok

It claimed that the print is a success. Obviously that's not true!

Then I dig up /var/log/cups/error_log. Unfortunately, there was nothing inside.

Then I started trying stuffs like:

  • Reconnecting the printer
  • Restarting CUPS
  • Using another USB Cable
  • Rebooting the printer

None worked! :(

Then I figured out that there is something called LogLevel in CUPS config. I modified it as follows:

LogLevel debug

And I restarted CUPS. Then I noticed the following messages appeared in /var/log/cups/error_log:

D [10/May/2016:14:37:20 +0800] [Job 136] Error: /undefined in --setpagedevice--
D [10/May/2016:14:37:20 +0800] [Job 136] Last OS error: Cannot allocate memory
D [10/May/2016:14:37:20 +0800] [Job 136] GPL Ghostscript 9.05: Unrecoverable error, exit code 1
I [10/May/2016:14:37:22 +0800] [Job 136] Job completed.

What? Obviously something went wrong! How on the earth could the level of that message merely be a debug? I think that should be at least a warn! More importantly, how come it is called "Job completed"? I think that should be "Job Failed" instead! :<

After that, I increased the swap space. And remote printing starts working again. :D

Took me a few hours to figure that out. I couldn't find this solution in Google. That's why I blog about this. Hopefully someone somewhere would somehow find this blogpost helpful.

UPDATE: I've filed a bug report to the CUPS developers. Hopefully it will be fixed soon.

Nginx Caching with uwsgi

Oct. 25, 2015, 5:17 a.m. Sysadmin

First sysadmin post!

I'm using Django and nginx with uwsgi for this webste. Right after the update of this site, I used PageSpeed Insights to check for the issues. It reports that my server is responding very slow(2 seconds!).

By googling around, I found that nginx has good caching support. With the use of both client cache and server cache, the rendering time of the cached pages can be reduced. Here is what I do to solve this problem:

#16m being size of cache key, 1m cache key can store 8k cache entities.
#60m being the inactivity invalidation time of cache
uwsgi_cache_path /var/www-newSite/serverCache levels=1:2 keys_zone=foo:16m inactive=60m;
server {
    # Django media
    location /media  {
        expires 1h;
        alias /var/www-newSite/media;  # your Django project's media files - amend as required
    location /static {
        expires 1h;
        alias /var/www-newSite/static; # your Django project's static files - amend as required
    location / {
        uwsgi_pass unix:///path/to/django_site.sock;
        include /etc/nginx/uwsgi_params;

        #client cache
        expires 5m; #Or whatever value you want

        #server cache
        uwsgi_cache foo;
        uwsgi_cache_key $uri;
        uwsgi_cache_valid any 1h; #Or whatever value you want

You may refer to the documentation of the nginx module ngx_http_uwsgi_module for what does the directives do.

Before caching, it takes two seconds to render a page. After caching, it only take ~20 ms.

The downside of this approach is that if the database is updated, the cache isn't invalidated immediately. It probably isn't an issue for this site. In case it's a problem for you, you may want to read a bit about Django’s cache framework.