6 ways to communicate with stm32, part 2. UART and GDB

This post is part of a series: how to talk to the stm32 in 6 different ways as well as some interesting things to do with each method. The code mentioned in this post, a working example, can be found in my github.

In my last post, I talked about how to start from zero to the point where you can blink a light on the cheap stm32f103c8t6 “blue pill” board.

This image came from here: https://developer.mbed.org/users/hudakz/code/STM32F103C8T6_Hello/

In that post (and its associated video), I showed how to use:

  • STMCubeMX to get the basic register settings,
  • the additional code needed to blink an LED,
  • how to compile (including where to get the compiler),
  • and how to upload to the module via GDB/OpenOCD

In this post, I build on that to show how to talk to the module via the UART from a terminal window on your computer. Topics/steps I’ll cover:

  • Needed changes in STMCubeMX
  • Some tips on reading the HAL manual published by ST corp.
  • How to send UART messages using two available methods. (polling and interrupt)
  • How to receive these messages using the minicom terminal
  • Bonus: how to unbrick an unresponsive module using the stm32flash utility

This video shows many of the concepts of this post, more details below.

GDB is an important communication channel

Before I go into UART, I want to emphasize the importance of GDB as a communication channel1 GDB is an important, perhaps the main, reason that I don’t just do everything in the Arduino environment.

Throughout my career, it seems that a large portion of software developers I worked with were content to debug only with printfs. I don’t know how they do it. Some/many of them are even very good, but without the use of a debugger, I’d feel crippled. It’s such an important tool. Writing code is one thing, but what about getting it to work? What if you need to understand old or someone else’s code? Nothing beats stepping through it.

In my last post about stm32, I use gdb as my programming utility. Once it’s done reprogramming the module, I have a debug prompt. It’s all done in a .gdbinit file, which can be found on my github.

To recap the gdb commands I use, to connect to openocd:


#export GDBEXEC=/bubba/electronicsDS/stm32/gcc/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-gdb-py
#export OPENOCD=/bubba/electronicsDS/stm32/openocd-0.10.0/install
file build/basic_uart.elf
target remote | $OPENOCD/bin/openocd -f $OPENOCD/share/openocd/scripts/interface/stlink-v2.cfg -f $OPENOCD/share/openocd/scripts/target/stm32f1x.cfg -c "gdb_port pipe; log_output openocd.log"

To reprogram:

define reload
  monitor reset halt
  monitor stm32f1x mass_erase 0
  monitor program build/basic_uart.elf verify
  monitor reset halt
end

To reboot/reset:

define restart
  monitor reset halt
end

And that’s what I have to say about that.

Needed hardware

Beyond the stm32f103c8t6 module and stlink-v2 programmer (each <$2 on AliExpress/Ebay), to replicate this post you will need an FTDI usb adapter and some dupont cables (also <$2 each)

Getting additional boilerplate using STMCubeMX

Beyond the blinky project, you’ll want to make a couple changes:

  • In the pinout tab, activate the USART1 feature by setting it to asynchronous.2
  • (optional but recommended) If you want to use the interrupt based RX/TX features, in the configuration tab, click USART1 and enable the USART1 global interupt in the NVIC sub-tab.
  • (optional) also in the tab, under USART1 the baud rate and related can be selected under the parameters sub-tab.
  • (optional but recommended) in project settings->code generator select “generate peripheral initialization as a pair of .c/.h files.
  • If using DMA based RX. under USART1 -> DMA Settings -> Add -> DMA request = USART1_RX. Also set mode to circular

Click “generate source” icon. The results can be found here.

Understanding the HAL documentation

Section 41.2 of the HAL documentation (UM1850) describes how to use ST’s HAL to use the UART. The documentation is mostly pretty good. The main thing I wish they’d provide is the specific code needed to do what’s described. STMCubeMX gives you this code, but it’s sometimes confusing to know which parts you still need to add.

In the case of UART, everything described in the reference manuals “how to use this driver” (page 599) is provided by the STMCubeMX output. You only need to add calls to the polling/interrupt IO functions.

I’ve found UM1850 to be the most useful document on understanding my devices.

Sending UART messages without interrupts

You have the option of sending messages in polling mode via a blocking call; it doesn’t return until the message is sent.

    HAL_UART_StateTypeDef state = HAL_UART_GetState(&huart1);
    if (state == HAL_UART_STATE_READY ||
        state == HAL_UART_STATE_BUSY_RX) {
      HAL_StatusTypeDef tstate;
      tstate = HAL_UART_Transmit(&huart1, themessage, sizeof(themessage), HAL_MAX_DELAY);
      state = HAL_UART_GetState(&huart1);
    }

Sending UART message with interrupts

The other way of sending UART messages it to send them and forget them, optionally giving an interrupt callback to the system to let you know when transmision is complete. Note that for HAL_UART_Transmit_IT to work, UART global interrupts must be enabled. This is true, even if you don’t care about message completion interrupts. Even if you just want to send the message and forget about it.

    HAL_UART_StateTypeDef state = HAL_UART_GetState(&huart1);
    if (state == HAL_UART_STATE_READY ||
        state == HAL_UART_STATE_BUSY_RX) {   
      HAL_StatusTypeDef tstate;
      tstate = HAL_UART_Transmit_IT(&huart1, theothermessage, sizeof(theothermessage)); 
      state = HAL_UART_GetState(&huart1);
    }

If you want to be notified when the message is finished

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_StateTypeDef state = HAL_UART_GetState(huart);
  if (state == HAL_UART_STATE_READY ||
      state == HAL_UART_STATE_BUSY_RX) {

  } else {

  }
}

Receiving UART

Receiving is a little trickier. The APIs want you to tell them how many bytes you want to receive. If you’re getting typed input, then

  1. you don’t know how long the message will be and
  2. you want to process data as it’s received

One way of doing this is by having the incoming data stored in a circular/ring buffer and regularly checking the read position via polling.

I’ll show two ways of implementing this buffer3.

  1. Direct interrupt based UART and
  2. DMA4 based UART

For both methods, I define a global to hold the buffer as well as a circle count. The latter is to help you know if the data has wrapped since you last looked.

uint8_t received[] = "           \n\r";
uint8_t num_rx_rounds = 0;

In the beginning of main, I initiate receiving. Note that I reduce the size by three. This is to maintain the printability of the string when debugging. \r,\n, and null termination.

// -3 because of \n \r and 0x0 to end the string
if (use_dma) {
  HAL_UART_Receive_DMA(&huart1, received, sizeof(received)-3);
} else { 
  HAL_UART_Receive_IT(&huart1, received, sizeof(received)-3);
}

And the interrupt callback. In DMA mode, just increment the counter. If using Interrupt based, I restart the buffer whenever it’s full.

void HAL_UART_RxCpltCallback (UART_HandleTypeDef *huart)
{
  num_rx_rounds++;

  if (use_dma) {
    // don't need to do anything. DMA is circular
  } else {
    __attribute__((unused)) HAL_StatusTypeDef state;
 
    // -3 because of \n \r and 0x0 to end the string
    state = HAL_UART_Receive_IT(&uart1, received, sizeof(received)-3);
  }
}

Also, when transmitting, you’ll need to check for RX in addition to ready. For example:

if (state == HAL_UART_STATE_READY || state == HAL_UART_STATE_BUSY_RX) {

Knowing how far along you are

With both DMA and interrupt based receive, unless you’re only giving a single byte buffer, you’ll want to know what’s been received so far. That information is accessed by reading the CNDTR control register. You can read more about it in RM0008 section 13.4.4:

// this register tells you how many bytes the receive function 
// is still waiting for.
huart1.hdmarx->Instance->CNDTR;

Send/receiving from your computer

Now that the device is reading/writing (we hope), how do we connect to it from a computer? Simple

  • connect the stm32 to an ftdi adapter,
  • plug the usb part of the adapter to your computer
  • use a terminal program like minicom, screen, or picocom to talk.

Connecting the module to ftdi adapter

this image comes from http://www.arduinesp.com/getting-started

You only need two wire connections:

  • stm32 pin A9 to FTDI RX
  • stm32 pin A10 to FTDI TX
  • GND to GND
  • optionally, you can connect Vcc. It’s safest to only power the stm32 module in one way. If it’s also connected to st-link, it’s probably getting power from it. If not, the ftdi adapter can provide power. pick just one to be safest.

Another good how-to can be found here. It’s a good link if you want to try using these modules in the arduino environment. 5

Minicom and hardware flow control


minicom --baudrate 115200 --device /dev/ttyUSB0

By default, minicom has hardware flow control turned on. In this mode, you’ll find that letters typed in the terminal don’t reach your module. You can turn it off.

ctrl-A -> O -> serial port setup -> F

Credit goes to this stackoverflow answer: https://stackoverflow.com/a/7876053/23630

Bonus item – unbricking

I’ve had it happen that my modules can become unresponsive to reprogramming. The STLink just couldn’t talk to it. Most of the time, this was due to bugs in STMCubeMX generated code. As of late, it hasn’t happened much; the bugs seem to have been fixed. In any case, if you find that your stm32 module is not responding to anything, the solution may be pretty easy.

Built into the STM32 is a hardware bootloader which you can access via UART (one of the reasons I’m talking about it in this post). There are two steps required

  • change the header option on the module to active the bootloader
  • use the stm32flash utility
To use the bootloader, move the header jumper next to the pin header. See red circle in the picture. Click to get a larger version of this image.
sudo apt install stm32flash
// the -o option says to erase everything.
stm32flash /dev/ttyUSB0 -o

 

I hope you found this post useful, see my other stm32 videos here.


  1. GDB is the second of the six ways I’m covering. Blinking is the first and UART is the third. I summarize all six on this page.

  2. there are several other options, but I haven’t used them and don’t know why one would choose them

  3. The HAL also provides the function HAL_UART_Receive, but I don’t see it as usable. This function only returns when data is received and the processor does nothing else in the mean time. It’s a blocking function.

  4. Don’t forget to add DMA in STMCubeMX above

  5. Again, the main thing I don’t like about arduino env is the inability to use a proper debugger like GDB. To be fair, this is more of a criticism of AVR. You can also use the arduino env on the stm32 module I’m using and then debug. That would be outside of arduino. Since arduino has more tutorials and demo code, I find it’s a useful place to steal code.

6 ways to communicate with STM32F103C8T6. Part 1. Zero to blinking an led

This image came from here: https://developer.mbed.org/users/hudakz/code/STM32F103C8T6_Hello/

This is the first in a series of posts about 6 ways to communicate with the stm32f103c8t6. In each of the posts, I will talk about a way to communicate with the part as well as something interesting that can be done with that mode of communication.

I have a video for this post:

The first way is to blink an LED on the stm32. To do this, you need a couple things:

  • Two cheap pieces of hardware
  • To generate boilerplate code which sets up the runtime environment, initializes the clock and some other low level stuff
  • To add code that blinks the LED pin
  • To compile the resulting code
  • To transfer the binary to the board

This post describes how to do these in the linux environment.

Needed hardware

To reproduce what I do in this post, you’ll need two things:

  1. stm32f103c8t6 board from aliexpress/ebay. <$2
  2. st-link v2 programmer. Also from aliexpress/ebay. <$2
click to enlarge

Boilerplate with STMCubeMX

Getting a microcontroller up and moving is actually fairly involved. There’s a ton of stuff that needs to happen after plugging in the power before any real work begins to happen. The ST company has produced a software package than can deal with a lot of this for you. 1

To install it, go to http://www.st.com/en/development-tools/stm32cubemx.html, scroll to the bottom and click to download. You’ll need to give an email address and all that, but then they email you a link to a page that includes windows and linux binaries.

You’ll also need to download the STM32F1 hardware abstraction layer:2

http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software/stm32cubef1.html

Can’t use OpenJDK

Note that STMCubeMX didn’t work for me with OpenJDK. I needed to install Oracle’s Java


sudo add-apt-repository ppa:webupd8team/java -y
sudo apt-get update
sudo apt-get -y install oracle-java8-installer

For instructions on how to get the boilerplate, please go to the video linked above.

Add Code needed to blink

To turn on pin 13:

GPIOC->ODR |= GPIO_PIN_13;

To turn it off:

GPIOC->ODR &= ~(GPIO_PIN_13);

To learn more about this code, I recommend ST’s RM0008 Reference manual, section 9.2.4 “Port output data register (GPIOx_ODR)”

To generate a delay for blinking this pin, you could just write a delay loop like this one:

void delayLoop() {
  volatile uint32_t delayCount = 100000; 
  while (delayCount > 0) {
    delayCount--;
  }
}

but there’s a better way. SysTick. The STM32 hardware abstraction layer includes a timer interrupt that ticks every millisecond. The learn more about it, I recommend ST’s UM1850 User manual: Description of STM32F1xx HAL drivers. This is the document I’ve found most helpful.

For the code below, I’ve omitted code not relevant to this post. The interrupt handler is in Src/stm32f1xx_it.c:

void SysTick_Handler(void) {
    HAL_SYSTICK_IRQHandler();
}

Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c:

void HAL_SYSTICK_IRQHandler(void)
{
    HAL_SYSTICK_Callback();
}

__weak void HAL_SYSTICK_Callback(void)
{
/* NOTE : This function Should not be modified, when the 
   callback is needed, the HAL_SYSTICK_Callback could be 
   implemented in the user file
*/
}

so we do as instructed and implement our own HAL_SYSTICK_Callback. Since the HAL one is marked weak, we can redefine it. Something like this:

void HAL_SYSTICK_Callback(void) {
  static uint8_t ledon = 1;
  if ((HAL_GetTick() % 1000) == 0) {
    if (ledon) {
      GPIOC->ODR |= GPIO_PIN_13;
    } else {
      GPIOC->ODR &= ~(GPIO_PIN_13);
    }
    ledon = !ledon;
  }  
}

While this works, note that it’s bad practice. You don’t want to do real work in an interrupt handler. Part of my point is to show you how easy it can be to deal with interrupts.

Compiling the code

Now that we have some code, we need to compile it. Many/most of the other tutorials that I’ve seen out there focus on using some sort of IDE. Call me old, but I like the old fashioned way, calling gcc, make,…

To compile, you’ll need a version of the gcc/gdb/g++… toolchain that’s built for ARM: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads. Download the latest version, untar it, and note where you put it.

Now you need to modify the Makefile that STMCubeMX generated for you. You’ll want to update the BINPATH var:

BINPATH = /bubba/electronicsDS/stm32/gcc/gcc-arm-none-eabi-6-2017-q1-update/bin

I also recommend making two additional debugger/gdb related changes to the Makefile:

  • adding -Werror next to the existing -Wall flags. 3
  • change -g to -g3. This enables you to see #define values in gdb.

Now you can just run make. I get something like this at the end of the output:

/bubba/electronicsDS/stm32/gcc/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-size build/blinky.elf
 text data bss dec hex filename
 4084 16 1568 5668 1624 build/blinky.elf

A good explanation of these lines can be found here. In a nutshell:

  • text (~4k) is how much flash we’re using (out of 64k or 128k, in the case of stm32f103
  • data is initialized RAM values. globals with initialization.
  • bss is uninitialized RAM. globals without initialization.

Transfer the binary to the board

The STM32 products come with a bootloader. Many of the stm arduino tutorials use that to get the arduino bootloader on there. I prefer st-link because once you have that setup, you also have debug access. All of this isn’t hard, though I didn’t find a good step-by-step with the little details. Here’s my version (remember this is for ubuntu. 16.04 in my case). I use openocd. I found this page helpful in getting started on openocd

wget https://sourceforge.net/projects/openocd/files/openocd/0.10.0/openocd-0.10.0.tar.gz
tar -xf openocd-0.10.0.tar.gz
cd openocd-0.10.0/
mkdir install
sudo apt-get install -y libtool automake libusb-1.0.0-dev texinfo libusb-dev texlive-base libftdi-dev
# the stlink and usb blaster flags are not required, openocd will automatically include these if you
# have the needed includes in your system. Adding the flags forces it to include and will trigger
# an error if the includes aren't there.
./configure --prefix=`realpath install` --enable-stlink --enable-usb-blaster
make install

this will put openocd into openocd-0.10.0/install

before we can check it, we need to connect the stm board to the st-link. See the picture at the beginning of this post. Both devices are labeled.

  • st-link 3.3  – stm 3.3
  • st-link gnd – stm gnd
  • st-link swclk – stm swclk
  • st-link swdio – stm swo

linux permissions to st-link v2

Once you plug in the programmer (which will also power the stm32; no need to plug in both) 4, linux probably won’t let you access the programmer yet.

First let’s see that the programmer is recognized:

--> lsusb
Bus 001 Device 013: ID 0483:3748 STMicroelectronics ST-LINK/V2

--> ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 Jul 5 10:43 /dev/ttyUSB0
crw-rw-rw- 1 root dialout 188, 1 Jul 5 10:38 /dev/ttyUSB1

Note that the USB tty devices belong to the dialout group. Add yourself to this group and you’ll be able to proceed (after logging out and then back in)

sudo usermod -a -G dialout $USER

If all goes well, you can do this:

export OPENOCD=/bubba/electronicsDS/stm32/openocd-0.10.0/install
$OPENOCD/bin/openocd -f $OPENOCD/share/openocd/scripts/interface/stlink-v2.cfg -f $OPENOCD/share/openocd/scripts/target/stm32f1x.cfg

This is what I get:

Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.227913
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints

If you get this instead, you have a permissions error:

Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
Error: open failed

An alternative to adding yourself to dialout group is to add these lines to /etc/udev/rules.d/49-stlinkv2.rules

# stm32 discovery boards, with onboard st/linkv2
# ie, STM32L, STM32F4.
# STM32VL has st/linkv1, which is quite different

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", \
MODE:="0666", SYMLINK+="stlinkv2_%n"

Finally, we can transfer the code. I like to have gdb upload the code every time I invoke it so I know it’s always uptodate. I do this with a local .gdbinit file. This file is mostly reusable from project to project. Just update the two mentions of blinky.elf. Also note the two env variables mentioned in comments.

#export GDBEXEC=/bubba/electronicsDS/stm32/gcc/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-gdb-py
#export OPENOCD=/bubba/electronicsDS/stm32/openocd-0.10.0/install

file build/blinky.elf
target remote | $OPENOCD/bin/openocd -f $OPENOCD/share/openocd/scripts/interface/stlink-v2.cfg -f $OPENOCD/share/openocd/scripts/target/stm32f1x.cfg -c "gdb_port pipe; log_output openocd.log"

define restart
monitor reset halt
end

define reload
monitor reset halt
monitor stm32f1x mass_erase 0
monitor program build/blinky.elf verify
monitor reset halt
end

reload
# add your breakpoints.
break main

continue

Now I run gdb

export GDBEXEC=/bubba/electronicsDS/stm32/gcc/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-gdb-py
export OPENOCD=/bubba/electronicsDS/stm32/openocd-0.10.0/install
$GDBEXEC

target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000178 msp: 0x20005000
stm32x mass erase complete
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0xfffffffc
wrote 5120 bytes from file build/blinky.elf in 0.365343s (13.686 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0xfffffffc
verified 4100 bytes in 0.102377s (39.109 KiB/s)
** Verified OK **
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000f18 msp: 0x20005000
Breakpoint 1 at 0x8000286: file Src/main.c, line 86.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at Src/main.c:86
86 HAL_Init();
(gdb) c
Continuing.


You should now have a blinking light on your board.


  1. Some months ago, I had some clocking issues using the generated code. Thankfully, they fixed it. Also a new feature is Makefile generation. There is still at least one major bug I’ve had to work around. (I2C stability)

  2. In theory, STMCube will download this for you, but when I did it, the application crashed

  3. the main reason I do this it to get an error on non-void functions that don’t return a value. I forget to do this with small functions all the time.

  4. most tutorials advise not to plug in both, or if you do, to disconnect the power wire on all but one. This is good conservative advice. I have not had issues when all are connected to various usb ports on the same computer.

Automatically aligning multiple video/audio clips in kdenlive

I’ve recently begun trying to produce some youtube videos on programming topics that I find interesting. In that interest, I’ve come to use the kdenlive linux video editor 1. Kdenlive is pretty nice and will serve my needs just fine.

One thing I’ve aspired to do is some multi-camera videos. My wife practices a couple kinds of martial arts and I’d love to record some of her test katas from several angles.

Aligning a handful of clips really isn’t that hard to do manually, but since I’m a nerd, I decided to program a utility to do this. It’s a problem that I wanted to implement for years and I’ve finally gotten to it.

Similar to the product PluralEyes, my utility looks at the audio portions of your clips and aligns them based on that. In a nutshell, I compute the cross correlation of all pairs of clips using FFTs and then write a timeline based on the strongest matches.

The end of this post will have more implementation details.

Here is a quick demo

 

The steps to use it are pretty simple

Step 1 – create an unaligned kdenlive project

First, create a kdenlive project that contains all of the desired clips in the desired tracks as below (click for larger image). Note that the clock in the multiple views show different times. This demo project has three different cameras (an S5, HTCM8, and motorola something) in addition to a cheap Sony voice recorder and a Sony PCM-M10

Here’s the fancy rig I used. It’s for creating some 360 style VR videos. I have some scripting for merging stuff together using Hugin, but I haven’t been satisfied with the results yet.

Step 2 – run the utility

A binary of the utility can be found on my github. You can also find the source code for it.

To run it is easy. In the example below, my project is called easydump, because it’s just an easy dump of all the clips:

./sync_kdenlive video_and_voice_recorders/easydump.kdenlive

It will create the file easydump_aligned.kdenlive. It also creates easydump_aligned_aligned0.wav which is a wav file with as many channels as clips.

The demo is about 4.5 minutes and the utility runs in ~10seconds on my Skylake with 16GB. 2 Run time will scale linearly in the length of your longest clip and quadratic in the number of clips. So far, I’ve made little/no attempt to optimize it beyond using FFTs.

This utility is for my own benefit/enjoyment/curiosity. If you have any interest in it, please comment. If you tried to run it and it didn’t work, please comment. If you tried it and it did work, please comment. If I get no comments, I’ll assume no one cares and will make no effort to make it better.

Of course, the easydump part isn’t hardcoded. It’s just the file name that I chose for this experiment.

Step 3 – load the updated project file into kdenlive

Step 2 generated a easydump_aligned.kdenlive. Load it into kdenlive. In the picture below, note that the clocks show the same time.

Here’s the result. From listening to the audio of it, I’d say it worked pretty well:

 

So how’s it work?

The core idea is something that I learned many moons ago, when I took 6.003 – signals and systems. A playlist of the 2011 lectures can be found here.

In particular, this lecture about convolution:

Convolution or the variant of it cross-correlation that I use in the utility is basically that act of sliding one signal along another, multiply the two, and taking the area of the result. A large area means lots of similarity. Smaller area means less.

If you were to just compute the cross correlation directly, you’d have a lot of computation to do. Thankfully, there was a guy named Fourier who found a way to compute this in the frequency domain. This coupled with the Fast Fourier Transform enables me to to cross correlations on WAV files pretty quickly.

Here are the required steps:

  1. compute the discrete fourier transform of each of your wav files. The length of each result should be equal to the max of the lengths of the two wavs.
  2. piecewise,  multiply the first by the complex conjugate of the second
  3. compute the inverse transform of the result of those multiplies.

Here is what you get with you take two sine waves, shifted relative to each other. The two two waveforms are the two input sines. The bottom two are the real and imaginary components of the cross correlation. The source code for this experiment can be found here on my github.

Note that this technique works for any kind of data. Spatial/visual works too. I’ve had thoughts of implementing a jigsaw puzzle solver this way.

Try it with your own waves

I have a compiled (for ubuntu linux) binary of a utility that takes two waves and writes a wave showing the cross correlation. It can be found here. To invoke it:

./sync_wavs file2.wav file1.wav true

If you omit the “true” argument, you’ll get just the aligned channels. In this case, I added true to tell sync_wavs to include the cross-correlation as the third and fourth channels. Note the peak location corresponds to the beginning of the second channel.

Attribution of libraries I used

Very few real programming projects are implemented entirely from scratch and this one is no different. The external libraries I used are:

FFTW This library implements the fourier transform parts. In addition to its excellent tutorial, I have a couple simple programs that I used in the lead up to this project.

TinyXML2 This library implements the xml read/write functions. I have a lot of experience using LibXML2’s perl interface. LibXML2 is excellent but there are some areas where it makes me do more of the work than I care for. TinyXML2 is easier to use in most ways. The output xml is nicely formatted by default. Adding text and new elements is a bit quicker to implement. The main thing missing TinyXML2 is XPATH support. Using the visitor methods sort of makes up for this.

BOOST. It’s hard for me not to use boost these days. In particular, I use:

ffmpeg I don’t use this in the code directly. The code does call ffmpeg to extract wav files of the same samplerate from each of the clips.

Some additional implementation details

I have found that downsampling the audio of each clip to 5k samples/sec works fine. This is important because the longer the fourier transform, the longer the runtime.

When taking the ffts and iffts, you need to double the length of the input data but padding with zeros (ie, the first half is your wav, the second is silence). This is important in knowing the relative order and offset of any pair of clips. The way the cross-correlation works, if you have a negative offset, the peaks will show up in the second half of the transform data. At the same time, what happens if one clip begins near the end (past halfway) of the other? To sidestep this, I simply doubled the data lengths. 3

In the utility, I compute the cross correlation for all pairs of audios. Some of those pairs will correlate better than other and some don’t correlate at all (since they don’t overlap). Here’s the method I’ve found to work for me:

  • compute the mean/average and standard deviation of the cross-correlation result.
  • find the peak value
  • order the peaks of all the pairs by ordering by the number of standard deviations above the mean/average. For pairs that should correlate (they overlap), the peaks tend to be at least 15 standard deviations above the mean.

  1. I actually have a version of Movie Studio Platinum, which I paid for some years ago. The problem is that I use windows less and less

  2. I imagine that anyone doing video editing will need/want/have a machine that it also pretty beefy. I’m using the graphics stuff built into the Skylake.

  3. I imagine there’s a way to do this without doubling but I don’t know the math well enough. If you do know, please let me know

Using a phony C struct as a function selector

Generic programming, as used by the std and boost packages, depends heavily on template tricks to extract data from specific data structures in a generic way. When I first tried using some of the boost libraries, I felt pretty clueless in getting them to do what I wanted. Hence this post.

Say you have a C struct like this one:

struct Foo {
  int a;
  int b;
};

Generic programming accesses the a and b members using a global get function and a property map:

template <typename T, typename PMAP>
int get(T &t, PMAP pmap);

What’s in the property map? In this case nothing. The magic happens in the templated specialization of get:

struct get_a {};

int get(Foo &foo, get_a)
{
  return foo.a;
}

Which you call like this:

Foo f1;
f1.a = 10;
std::cout << "a is " << get(f1, get_a()) << std::endl;

How’s it work and what’s the compiled result?

The get_a struct is empty; it contains no data members. When you call get, the compiler selects the get_a version since it’s the most specific specialization of get. From there, things get interesting. Constructing get_a() is a noop. Pushing it as a function argument is a noop. After inlining, get simply becomes f1.a.

 

How to quickly compute the Euclidean MST of a large number of points (and why you might want to)

When I was in college, like most CS type majors, 1 I took the algorithms class. Sorting, binary trees, O(n) notation… all of that.

One of the things I didn’t understand is why such a big deal was made about some algorithms like the graph algorithms. Why would I want a minimum spanning tree of a million nodes?

A bunch of years ago, I did need to compute the MST of a couple hundred thousand nodes for my job. Later on, I needed to do it three dimensionally. Something made me think of it recently, and I have a hankering to write about it.

I’ve also recorded a series of videos to explain the programming aspects:

What problem was I trying to solve?

At the time, I was working on code to generate a clock buffer tree for large seas of logic gates. Say you have a million gates in your logic design and that 10% of those are clocked elements.2. So we have 100k logic gates that need a clock signal.

So, clock buffers can’t drive the capacitance of a 100k gates, at least not if you want the design to run at more than 1 cycle per second. The solution is a clock tree. The input clock drives 5 buffers, which each drive 5 more buffers,… until everyone has their clock.

How do you decide which buffer drives which cell? That’s where the MST comes in. Once I had computed the MST of all of the clocked elements, I picked a random end (of the MST) node 3 and collapsed it into it’s adjacent node. When a collapsed node passes a capacitance threshold (also need to include wiring capacitance), that’s where I add a buffer. Keep doing this until you have your first level of buffers, then recursively do the same up the tree.

But some cells are more timing critical than others.

In a design of 1M gates and 100k clocked elements, most of those gates will easily meet timing, no matter how badly you design things. Most. If memory serves me, we’re talking 90% (99%?) of the design meets timing, easy peasy.

So in those 100k gates, some are timing critical, many are not. An easy solution is to have two subtrees. One for the easy stuff and the other for the hard. The problem there is that you can have one little cell surrounded by critical stuff. Do I really need to segregate it? How can I allow the user to control the thresholds for such things?

The solution I wanted to implement, but never did (though I’m convinced this will work) is to turn the problem into a 3D MST problem. The X and Y axes are the normal X/Y of the design. The third axis represents timing. I simply need to devise a timing to distance coefficient.

MST basics

First off, the MST algorithm is pretty easy. To quote wikipedia.org:

Initially, T contains an arbitrary vertex. In each step, T is augmented with a least-weight edge (x,y) such that x is in T and y is not yet in T. By the Cut property, all edges added to T are in the MST. Its run-time is either O(m log n) or O(m + n log n), depending on the data-structures used.

Sounds pretty easy. The problem is you need a graph to operate on. I only had a set of points. The easy solution is to create a complete graph. All nodes are connected to all other nodes. O(n^2) in the number of nodes. 100k*100k can take up some space.

Triangulation to the rescue

Again, I refer to wikipedia.org:

every edge not in a Delaunay triangulation is also not in any EMST

I don’t really understand the math behind it but first compute a triangulation of your points and run MST on that.

The CGAL library will give you the Delaunay triangulation.

The BOOST Graph Library will give you the MST.

The problem is that these libraries were difficult for me to really understand. Now that I’ve spent some time with them, they’re actually pretty simple. I’ve created some videos that perhaps will help you also see them as simple.

Visualization with paraview

First, it’s important to be able to see that data. I’ve found that paraview works well and is easy to use (once you know how to use it)

CGAL how to

Boost Graph library how to


  1. My major was basically computer science except it was in the math department. Instead of the normal 150 students per year, there were 18 of us doing the Math with CS variant.

  2. The design size was actually smaller. 100k-500k. The percentage of clocked elements was higher. I’m going by memory, but I think the final number of nodes is in the same ballpark.

  3. I think I actually picked the bottom right one, but it doesn’t really make a difference. The main benefit to the bottom right is that you get the same or similar results from one run to the next.

Most Android Apps can easily be decompiled to remove the ads

Trying to reach even non-computer people

This is a long post. Most of it is instructions for modifying Android apps for your own purposes. In the first portion, in which I talk about motivations, I will attempt to make it interesting even for non-computer people:

  • I was surprised how easily and well java sources can be recovered from any Android app
  • It’s easy to customize apps. You can easily change the pictures and the sound clips.
  • Banner ads in kids apps are surprisingly easy to remove
  • Some commentary on kids apps in general

The second part is a how to:

Android apps for little kids

As a parent, I’ve looked around for some good games for my two kids, aged 3 and 6. 1 There are some good ones out there. For example, all of the apps produced by Lego are excellent2. We look for educational ones. Endless Alphabet is a good one.3 Wonster Words.4 Beck and Bo is excellent…. There are some companies out there making great games for kids.

A step down from these, but still pretty good are games like FireFightersFireRescue. It’s a fun app and it appeals to little boys who are enamored with fire fighter related stuff. 5 The downside is that it’s got a big banner along to bottom for ads, and for adult users, that’s not a problem. This game involves moving a firetruck ladder to rescue people stuck in the building. It’s easy for little fingers to get dangerously close to the ads area. Even my 6 year old daughter doesn’t have perfect tablet swiping fingers6. So my son often clicks ads; ads that he has no chance of being interested in. Looking at the screenshot below, I don’t think he’s looking for a free ebook from resources.office.com.

Banner ads don’t really make sense for kids games

App developers need to make a living. As device users, we’ve voted that we don’t want to pay for anything. So instead of the apps being the product, we users have become the product; developers sell their users to advertisers. Ads is the main game in town. 7

Still, it doesn’t seem that ads make sense for little kids. Surely Google has thought about this and I imagine they’re in a bind. They want ad revenue, but they also don’t want the perception that they’re not friendly to kids. They have to know that some of their ads are served to an entirely inappropriate audience.

Anyway, my son enjoys playing the game. As parents, my wife and I don’t enjoy helping him get back to it after he clicks the ad. So I went to the playstore to find a paid version of the firefighter game without ads.

They don’t offer an ad free one. Bummer.

Looking for adblocking led to the rabbithole

Kids games like the firefighter game are pretty common, otherwise, I’d have just moved onto the next game. As a computer guy, I figured I’d look for a way to make these games more playable. As happens so often, I was led down a rabbithole.

I started by trying an adblocker. That didn’t work. The ads were just replaced with offers about their other apps, however, in the process, I stumbled on the youtube video below. They make it look so easy. More important, it made me curious about how apps are put together.8

In the end, I was successfully able to remove ads from the firefighter app. How I did this, is next in this post.

Finally the instructions

I am writing these instructions based on running in a fresh virtualbox install of ubuntu 16.04. The only prior thing I’ve installed is emacs24. I mention it because maybe other stuff gets installed with it. I’ve split this section into four parts:

  • installation of the needed tools
  • setting up your android device
  • using the tools to unpackage and decompile
  • selective recompile and repackage

Installing the tools

The instructions later in this post will want an env var APK_TOOLS that points to an area of installed tools.

In these install instructions, I’m attempting to enable you to simply cut/paste the commands. Things will be installed in groups. The main exception to this is Oracle’s java and Google sdk manager. The reason for this, is that the installers insist on you typing y to agree to their terms and conditions.

Java 1.8

Oracle doesn’t make it convenient to install java on ubuntu. So we get it from an alternate place. I’m usually wary of such alternates, but I found a couple sites that directed me here. In particular, this askubuntu answer:
http://askubuntu.com/questions/464755/how-to-install-openjdk-8-on-14-04-lts

The installer will ask you to accept some license conditions.

sudo add-apt-repository ppa:webupd8team/java -y
sudo apt-get update
sudo apt-get -y install oracle-java8-installer

android buildtools

At the end of the process to put an app back on your device, you will need to sign it. If you have android studion ide installed, the signer comes with the buildtools package which will probably end up in your home dir $HOME/Android/Sdk/build-tools/25.0.2/apksigner. This is the way to go if you think you might want to do android development.

Here I’m going to describe a less heavy handed way. First we need the sdkmanager https://developer.android.com/studio/index.html#downloads. We’ll then use the sdkmanager to install buildtools.

cd $APK_TOOLS
mkdir android_tools
cd android_tools
wget https://dl.google.com/android/repository/tools_r25.2.3-linux.zip
unzip tools_r25.2.3-linux.zip

# tools/bin/sdkmanager --list
# --> build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2

mkdir sdks
tools/bin/sdkmanager --sdk_root=sdks 'build-tools;25.0.2'

32 bit support, apktools, dex2jar, luyten, jdgui, adb, zipalign

adb, in this context, is used to copy apk files from/to your device. apk files are what you’re downloading from the playstore when installing apps.

Apktool is used to package/unpackage apk files. It can be installed using the normal Ubuntu package system, but that version gives me errors. Instead, these instructions download apktool directly from the website.

Compiled Java code is normally stored in jar files. In android apk files, the are in dex files. dex2java is used to convert between the two.

Luyten and JDGui are two java decompilers. They seem pretty good. My main gripe with them is that they both insist on you using the GUI.

zipalign is part of the apk signing process. signing is important for security reasons. We don’t want people accidentally installing fake Chase or Bank of America apps. The android OS requires signing before it will allow you to install an app.

From a small comment in the apktool instal instructions: https://ibotpeaches.github.io/Apktool/install

Make sure you have the 32bit libraries (ia32-libs) downloaded and installed by your linux package manager, if you are on a 64bit unix system.

(This helps provide support for the 32bit native binary aapt, which is required by apktool)

To fulfill this requirement, we’ll follow these instructions: https://blog.teststation.org/ubuntu/2016/05/12/installing-32-bit-software-on-ubuntu-16.04/

Because sudo asks for your password, I find it useful to do “sudo ls” right before cut/pasting these.

# 32 bit stuff
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get -y install libc6:i386 libstdc++6:i386

sudo apt-get -y install zlib1g:i386

# adb git zipalign. (I think I don't really need git anymore)
sudo apt -y install adb git zipalign

# Apktool
# APK_TOOLS is a directory where you want these to be installed.
cd $APK_TOOLS
mkdir Apktool
cd Apktool
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.2.2.jar
ln -s apktool_2.2.2.jar apktool.jar
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
chmod ugo+x apktool

# This package works in windows and linux. Since I use linux, I want all of the sh files. Let's make them executable.
cd $APK_TOOLS
mkdir dex2jar
cd dex2jar
wget https://downloads.sourceforge.net/project/dex2jar/dex2jar-2.0.zip
unzip dex2jar-2.0.zip
chmod ugo+x dex2jar-2.0/*.sh

# luyten
cd $APK_TOOLS
mkdir luyten
cd luyten 
wget https://github.com/deathmarine/Luyten/releases/download/v0.5.0/luyten-0.5.0.jar

# jdgui
cd $APK_TOOLS
mkdir jdgui
cd jdgui
wget https://github.com/java-decompiler/jd-gui/releases/download/v1.4.0/jd-gui-1.4.0.jar

generating a keystore for apk signing

Before you can install a new apk file on an android device, it has to be signed. To sign, you need a signature. Because keystore generation is a one time thing, I’m including it here in the instructions. Let’s generate that now with the keytool command. My system has keytool without doing anything extra. I imagine adb added it for me.

It will ask for a password followed 6 questions. I just use the default of unknown. I’m not trying to put these apps on the playstore. I just want different versions on my device. Finally, it’ll ask for confirmation that everything’s correct:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes

mkdir ${APK_TOOLS}/keystore
keytool -genkey -v -keystore ${APK_TOOLS}/keystore/my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias

building apktool yourself (optional)

In case you want to build apktool yourself from latest code. https://ibotpeaches.github.io/Apktool/install/

cd $APK_TOOLS
git clone https://github.com/iBotPeaches/Apktool.git 
./gradlew build fatJar

# get wrapper script
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
chmod ugo+x apktool
ln -s ./brut.apktool/apktool-cli/build/libs/apktool-cli.jar apktool.jar

 

Developer mode and unknown apk sources

On your phone you’ll need to activate developer mode.

  • Settings->about device
  • Tap on ‘build number’ 7 times and a new menu will appear on the top
    menu.
  • Tell your phone it’s ok for a computer to try to talk to it via adb:
    Settings->developer options->Android debugging
  • Tell your phone it’s ok to install apks from unknown sources. You’ll need this later, after you’ve modified the game. You’ll be the unknown source
    Security -> unknown sources to on

At this point, connect your device to your computer with its usb cable. Let’s check that you can connect to it. When you run the next command, your phone will ask if it’s ok for your specific computer to connect. You’ll want to say yes and that it should remember.

adb shell

Retreive, unpack and decompile

Again, I’m attempting to give bigger blocks of cut/pasteable commands. Here’s an overview of what we need to do:

  • use adb to find and retrieve the original app package (this needs to be it’s own step)
  • use apktool to unpackage it.
  • use dex2jar to… convert the dex containing the compiled into a jar file (still compiled)
  • use luyten or jdgui to get java sources.9

Some interesting things to look at

After you unpackage an apk with apktool, you’ll have a directory with something like an android project in it. Take a look around. In particular, you’ll find an assets directory. The assets directory contains all of the pictures and sound files of the game. Feel free to customize the app. Change character pictures. Put in some gangsta rap. Make sure the file names stay the same. When we rebuild from that area, any assets changes will come along for the ride.

In the instructions below, I use a environment variable to hold a base name for the stuff we’re processing. In this example it’s


export APK_NAME=firefightersFireRescue

Getting the package location

This step is not really automatable unless you’ll trying to get everything.10

adb shell pm list packages

Will give you a bunch of lines, including one like this:

package:com.bestopgames.firefightersFireRescue

Now you want to find out where the apk for that app is on your device

adb shell pm path com.bestopgames.firefightersFireRescue

gives me:

package:/data/app/com.bestopgames.firefightersFireRescue-1/base.apk

Now that we know where it is, copy from the device to your local unix disk

cd <some path where you'll be doing this experiment>
export APK_NAME=firefightersFireRescue
mkdir apk
cd apk
adb pull /data/app/com.bestopgames.firefightersFireRescue-1/base.apk ${APK_NAME}.apk
cd ..

The other steps for unpackage to decompile

mkdir unpack
${APK_TOOLS}/Apktool/apktool d -s apk/${APK_NAME}.apk -o unpack/${APK_NAME}

${APK_TOOLS}/dex2jar/dex2jar-2.0/d2j-dex2jar.sh unpack/$APK_NAME/classes.dex -o dex2jar/${APK_NAME}.jar

java -jar ${APK_TOOLS}/luyten/luyten-0.5.0.jar dex2jar/firefightersFireRescue.jar 
 

Additional notes:

  • One note about the -s flag to apktool. This flag is also called the –no-src flag if you don’t give this flag, you won’t get the classes.dex file which you’ll need in the next step.
  • luyten doesn’t have a command line interface beyond telling it what jar to read. To save the javas you’ll need to use the gui.

Modify java, repackage, sign and upload.

In this section, I explain the steps I follow to get new java into an android app. Similar to the install section, I’ll have a cut/pasteable snippet at the end of this one.

Using both the luyten and jdgui decompilation tools I did not get a set of javas that just compiled. Trying to do this did not work:


javac `find . -name "*.java"

In both cases, I get syntax errors, though not the same errors. Perhaps files from the two could be combined to get a clean full compile. For the purposes of what I’m showing here, you don’t need a clean compile. More on that later.

Turning off ads in the code

Here’s where things get really interesting (I think). Most games are pretty genericly written. They use a limited number of game engines. They use a limited number of in app advertising platforms. Poking around the firefighter game, I find two libraries in particular.

The first of these is cocos2dx: http://www.cocos2d-x.org/ Inside of it, I found the AISActivity class, which has the method “hideAd()”. That told me there’s a way to turn off ads with a switch. hmm. When I look some more, I find that the class ais.constants:Config.class has this:

package com.ais.constants;
  public class Config {
    public static void init() {
      org.cocos2dx.lib.AISCommon.enableAdmob = true; 
      org.cocos2dx.lib.AISCommon.enableInterstitial = true; 
      org.cocos2dx.lib.AISCommon.enableInApp = false; 
      org.cocos2dx.lib.AISCommon.enableLocalNotification = false; 
    } 
  }

Can it really be this easy? Now the trick is changing this file and recompiling. But how?

Again, if I do this:

javac `find . -name "*.java"`

I get a ton of errors; recompiling everything would be a pain. Can I recompile just this one class?

javac com/ais/constants/Config.java

Doing that, yields a bunch of android related errors. missing symbols. I tried a couple things. I downloaded the cocos2dx library, but there the problem is which version? I need to compile against something. Then I realized, I have a jar file!

So, here’s what you do. Change the two falses to trues and save it, along with any other files you want to change. You only need to compile modified files. For the commands below, place them under a “newjava” directory. It’s important to retain the intermediate paths to the files. In this example, that’s the com/ais/constants part.11

mkdir -p newjava/com/ais/con<code>tants/
cp <modified Config.java> newjava/com/ais/constants/
cd newjava
javac -cp ../dex2jar/${APK_NAME}.jar `find . -name "*java"`
jar uvf ../dex2jar/${APK_NAME}.jar `find . -name "*class"`

You can use the following line to verify that you didn’t duplicate the file

jar tf ../dex2jar/firefighter.jar | grep '/Config'

Here’s an important note. Unlike other compilers that I’ve worked with, java really pays attention to your directory structure. When running the javac and jar commands, it’s important to run the command from the directory that contains the com directory.

repackaging complete

Ok, now you have a new java file and I’ve showed how it can be easy to recompile it. There are several steps to get to something you can install.

apksigner has a nice feature that you can put your signing password into an environment varible instead of embedding into a script. In the commands below, I’m using SIGNPASS as the env var.

  • compile java to class files
  • add class files to jar
  • convert jar to dex
  • rebuild apk file
  • zipalign the apk file
  • sign the apk file
  • copy it to your device

export APK_NAME=firefightersFireRescue
export APK_TOOLS=../../tools/

# this assumes you've already dont the commented keytool step below.
# export SIGNPASS=YOUR_SIGNING_PASSWORD

cd newjava
javac -cp ../dex2jar/${APK_NAME}.jar `find . -name "*java"`
jar uvf ../dex2jar/${APK_NAME}.jar `find . -name "*java"`
cd ..

${APK_TOOLS}/dex2jar/dex2jar-2.0/d2j-jar2dex.sh -f dex2jar/${APK_NAME}.jar -o unpack/${APK_NAME}/classes.dex

mkdir rebuilt
${APK_TOOLS}/Apktool/apktool build unpack/${APK_NAME} -o rebuilt/${APK_NAME}_rebuilt.apk

zipalign -v -p 4 rebuilt/${APK_NAME}_rebuilt.apk rebuilt/${APK_NAME}_rebuilt_aligned.apk

${APK_TOOLS}/android_tools/sdks/build-tools/25.0.2/apksigner sign --ks-pass env:SIGNPASS --key-pass env:SIGNPASS --ks ${APK_TOOLS}/keystore/my-release-key.jks --out rebuilt/${APK_NAME}_rebuilt_signed.apk rebuilt/${APK_NAME}_rebuilt_aligned.apk


# now push to your device
adb push rebuilt/${APK_NAME}_rebuilt_signed.apk /storage/self/primary/Download
 

Extra stuff that may be helpful

If you get an error like this one,

Exception in thread "main" brut.androlib.AndrolibException: brut.androlib.AndrolibException: brut.common.BrutException: could not exec: [/tmp/brut_util_Jar_5394410189585563704.tmp, p, --forced-package-id, 127, --min-sdk-ver

it’s because of a small comment in the apktool install instructions:
https://ibotpeaches.github.io/Apktool/install/

Make sure you have the 32bit libraries (ia32-libs) downloaded and installed by your linux package manager, if you are on a 64bit unix system.
(This helps provide support for the 32bit native binary aapt, which is required by apktool)

To fulfill this requirement, make sure you’ve done the 32 bit stuff in the install section above.

To solve errors like this one:

 W: /tmp/brut_util_Jar_3065852416515877270.tmp: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
 Exception in thread "main" brut.androlib.AndrolibException: brut.androlib.AndrolibException:

You need this

sudo apt-get install zlib1g:i386

Install it on your device

Now you just need to install it. Using the adb push command from your xterm, it’ll be in your downloads fold. On your phone, navigate to it in the file manager and click it. If you get a popup about unknown apks, you want to change the setting in settings->developer options->allow unknow sources. Make sure you copy over the signed apk otherwise you’ll get “an unknown error occurred”


adb push firefighter_noads_signed.apk /storage/self/primary/Download

Please comment

This post took a lot of time to put together. It took more time than I really should have spent on it. The only way for me to justify it, is to know that others have benefited. If people respond positively, I’ll do other posts when I go down future rabbit holes.


  1. Let’s put aside the question of whether 3 year olds should be spending time on a tablet.

  2. and free! I would be happy to pay for them

  3. we paid to upgrade from free

  4. we paid to upgrade to “pro” version

  5. The same people also make a distasteful game (I think) Plastic Surgery Simulator Kids

  6. swiper no swiping.

  7. I’ll note that here in Germany, magazines and newspapers are not free to read online. You have to pay to get any of the content. NYTimes, Newsweek, The New Yorker give their full writings away. With the German equivalents, you get little more than short blurbs.

  8. I didn’t need to when developing my vocabulary app

  9. note that this is not truly the original, original java code. The variable names will be wrong. No comments. Still, the structure will be usable. This is not like getting C code from assembly. You’ll have if statements, for loops and all that.

  10. well, you could try to script it a little, but it’s not really worth the effort.

  11. Again, I have a bigger snippet later to do this and the other rebuild steps further down.