written at 20:45 by faberman
CSS/JS minify

In need of a simple JS/CSS comment and white space stripper, I found not one useable tool. So, as usual, I wrote my own to strip and pack all CSS/JS into convenient archives. Not only does it reduce page load time and thus improve the user experience, it reduces traffic payload and the number of requests - a small step towards more sustainability for web pages.


minify -js [<JS-File>..] minify -css [<CSS-File>..] minify (<file.js> [<file.js>..])|(<file.css> [<file.css>..])

If there are no file names given in -js or -css mode, stdin is used as input.

I use a make target in my projects to create minified and precompressed versions of the JS/CSS files:

minify: rm css/all.css* || true minify -css css/* > css/all.css gzip -fc9 css/all.css > css/all.css.gz rm js/all.js* || true minify -js js/* > js/all.js gzip -fc9 js/all.js > js/all.js.gz


minify_v2.tgz v2, 2020-11-28
written at 19:48 by faberman
Vegan Recipe Database

Corona lockdown.. finally some time to build a recipe database for my collection of vegan recipes with a query system similar to that I built 20 years ago for a friend's organic store in Marburg:


German only (for the moment :).

written at 23:01 by faberman

I needed a watchdog with variable timeouts during the lifecycle of the supervised process - longer timeouts during startup/initialisation, shorter during interactive operation. Since I could not find one, I wrote my own:

  • no library dependencies (except libc)
  • no config files, single binary
  • ideal for embedded systems
  • support for kernel watchdogs
  • permission check via UID and program name
  • millisecond precision

I find it so easy to use that I also run it on my web servers to monitor my daemons.


A process that wants to be monitored creates a file with unique filename (e.g. command name + pid) in /run/watchdog. The file contains the following three lines:

<command name> <pid> <timeout>
  • command name is the name of the running process as in /proc/<PID>/command,
  • pid is the PID of the process, and
  • timeout is the timeout in milliseconds.
If the file has not been updated before last modification time + timeout has passed, the process is sent a KILL signal ONLY IF
  1. the program name given in the file in /run/watchdog matches the name in /proc/<PID>/comm, and
  2. the EUID of the process (as in /proc/<PID>/status) is the same as the UID of the file in /run/watchdog


All watchdogs in /dev/watchdogX are pinged every WATCHDOGTIMEOUT ms and will receive the "Magic Close" upon exit of watchdogd.





make; make install


Simply run 'watchdogd' at startup. If /var/run/watchdog does not exist, it will be created.


Send the process a SIGINT or SIGTERM to exit. These signals are caught, watchdogd writes the magic close byte to all system watchdogs and exits gracefully. Any files in /var/run/watchdog are kept in place, so after a restart of watchdogd it will resume operation immediately.


All starts, shutdowns, process killings and errors are logged via syslog and stdout/stderr.


To use watchdogd in your program, simply include watchdogd.h and call watchdog_update() before any previous timeout runs out. To turn off the watchdog, call watchdog_disable():

#include "watchdogd.h" ... watchdog_update("myapp", getpid(), 5000); // 5s timeout during startup ... main_loop { ... watchdog_update("myapp", getpid(), 1000); // 1s during normal operation }

Make sure that "myapp" is the EXACT command name of your application as it appears in /proc/<PID>/comm.


  • /var/run should be tmpfs so you do not wear out your flash
  • if you cache your pid make sure to reset it in the child process after fork()ing


written at 21:19 by faberman
GPIO detection

If you should ever be in a situation where you have a piece of hardware on your bench without schematics, nobody to answer questions and you have to figure out where those pins are connected to.. gpiofinder to the rescue!

gpiofinder utilizes all GPIOs not already in use (e.g. because configured as dedicated periphery) and performs a binary search, so within log2(N) steps you should have your pin identified.

Why not as shell script? Embedded systems often have minimal shells with very limited features. Before building a full featured bash, hacking together a small C program seemed more feasable.


  1. Connect an oscilloscope or level meter to the GPO you are identifying
  2. Run gpiofinder with the maximum number of gpios as argument, e.g. 223 on the i.MX6
  3. Answer the questions with y/n:
    $ ./gpiofinder 223 Initializing all GPOs to 0.. Is the level you are looking for currently low? (y/n) y Beginning search.. Enabling 0..111..did the level go up? (y/n) y Enabling 0..55..did the level go up? (y/n) y Enabling 0..27..did the level go up? (y/n) y Enabling 0..13..did the level go up? (y/n) n Enabling 14..27..did the level go up? (y/n) y Enabling 14..20..did the level go up? (y/n) y Enabling 14..17..did the level go up? (y/n) n Enabling 18..20..did the level go up? (y/n) y Enabling 18..19..did the level go up? (y/n) y Enabling 18..18..did the level go up? (y/n) n Enabling 19..19..did the level go up? (y/n) y GPIO=19


written at 19:11 by faberman
Offline Ubuntu Docker Image Creation

This script expects an Ubuntu version (YY.MM or name) as argument, pulls the files and creates a docker image. This comes in handy if your company's firewall policy forbids access to docker repositories or you want to build your own base images.

Make sure your version of debootstrap supports the Ubuntu versions you want to install.

$ ./create_image.sh focal


create_image.sh v1, 2019-11-12
written at 20:52 by faberman
Monkey Typer

For automated tests of user input, not connected input boards or buttons that are not there yet, I wrote this small tool to inject keypresses in the event system.


$ keysim KEY_F1 KEY_A KEY_B KEY_C

Will enter F1 a b c with a 200ms delay. For a list of all supported key names please look in the source, you can easily add new keys or other events.


A kernel with CONFIG_INPUT_UINPUT support.


written at 22:02 by faberman
IMX.6 PWM Configuration

To experiment with different PWM configurations to reduce display flickering I wrote this little tool. It reads and writes the IMX.6 registers and bypasses the Linux drivers.


$ pwmconfig -h Usage: pwmconfig [-r] ([-f val] [-d <val>]) | ([-p <val>] [-s <val>] [-P <val>] [-S <val>]) <pwmid>] -r show the register contents Automatic PWM configuration: -f set the PWM frequency for the given PWM -d set the duty cycle, 0..100 Manual PWM configuration: -p set the period value for the given PWM -s set the sample value for the given PWM -P sets the clock prescaler, 0..4095 -S sets the clock source, 0..3

Example: To set the PWM clock of PWM 1 to 15 kHz and the duty cycle to 50%, run

$ pwmconfig -f 15000 -d 50 1

To read the registers of a PWM peripheral, run

$ pwmconfig -r 1 *** PWM1 Registers PWMCR 0x03c20001 FWM FIFO Water Mark : 0 STOPEN Stop Mode Enable : 1 DOZEN Doze Mode Enable : 1 WAITEN Wait Mode Enable : 1 DBGEN Debug Mode Enable : 1 BCTR Byte Data Swap Control : 0 HCTR Half-word Data Swap Control : 0 POUTC PWM Output Configuration : 0 CLKSRC Select Clock Source : 2 PRESCALER Counter Clock Prescaler: 0 SWR Software Reset : 0 REPEAT Sample Repeat : 0 EN PWM Enable : 1 PWMSR 0x00000038 FWE FIFO Write Error Status : 0 CMP Compare Status : 1 ROV Roll-over Status : 1 FE FIFO Empy Status Bit : 1 FIFOAV FIFO Available : 0 PWMIR 0x00000000 CIE Compare Interrupt Enable : 0 RIE Roll-over Interrupt Enable : 0 FIE FIFO Empty Interrupt Enable : 0 PWMSAR 0x00001104 SAMPLE: 0x1104 (4356) PWMPR 0x00001102 PERIOD: 0x1102 (4354) PWMCNR 0x0000042d COUNT: 0x0cea (3306) *** PWM1 Configuration Period : 4354 Duty cycle : 4356/4354 = 100% PWM clock rate: 66000000 Hz PWM prescaler : 1 PWM frequency : 15158 Hz


written at 12:00 by faberman
GPI automation

A client wanted to build a push button board connected to a rpi to trigger scripts in order to automate scene recall, audio routing and quick switching of setups. This is accomplished by this small daemon that listens to GPI changes and runs scripts depending on the type of the event.


$ gpiod <gpi> [<gpi> ..]


$ gpiod 4 17 22 10 9 11

If you want to have to use a GPI, create one or more scripts in /var/lib/gpiod/scripts with the following name(s):

  • <GPI>.sh for raising or falling edge (any change triggers the script)
  • <GPI>_up.sh for raising edge
  • <GPI>_down.sh for falling edge
The scripts will be invoked with two parameters, 1. the GPI id and 2. the new level (0 or 1).


As usual, the GPIOs have to be configured in the system in order to use them. You can do this yourself (by writing the necessery values to /sys/class/gpio/...) or use the scripts provided in the archive:

  1. edit gpiod.conf so the list of GPIs and GPOs reflect your hardware setup
  2. run create_gpios.sh and run_gpiod.sh at startup (in that order!)


gpiod_v1.tgz 2013-09-04