Compiling ludocode/mpack (MessagePack) for Arduino AVR

Our first slyftlet is about data transport using MessagePack. We’ve chosen the MPack Library from Ludocode, because it’s very lightweight and easy to use. We integrated this on the Arduino firmware platform, but we started with an ESP8266 and not a board from Arduino.

The compiler toolchain from Espressif/Xtensa (xtensa-lx106-elf-cc) is able to compile ludocode/mpack out of the box without modifications, so we took this as a basis for our tutorials.

Using Arduino AVR (i.e. avr-gcc) this is a different story, it comes back with a bunch of warnings and error messages:

$ pio run 
(…)
lib/mpack/src/mpack/mpack-expect.c: In function 'mpack_expect_cstr_alloc_unchecked':
lib/mpack/src/mpack/mpack-expect.c:542:19: warning: large integer implicitly truncated to unsigned type [-Woverflow]
maxsize = UINT32_MAX;
(…)
Compiling .pioenvs/uno/lib/mpack/mpack/mpack-reader.o
lib/mpack/src/mpack/mpack-node.c: In function 'mpack_node_print_element':
lib/mpack/src/mpack/mpack-node.c:1174:31: error: expected ')' before 'PRIi64'
fprintf(file, "%" PRIi64, data->value.i);
(…)

So this needs some tweaking to be successful. Look the the code of both ludocode/mpack and the AVR toolchain, we found a macro __avr_libc_does_not_implement_long_long_in_printf_or_scanf that solves the compilation errors, when set as a build flag.

So with PlatformIO, we added a line

build_flags = -D__avr_libc_does_not_implement_long_long_in_printf_or_scanf

to platformio.ini, which works but still leaves some warnings open.

So more tweaking.. Ludocode/MPack comes with a configuration header file, where one can set various options. Adding mpack as a library to our project, directly from github:

$ pio init -b uno
$ ( cd lib && git clone https://github.com/ludocode/mpack.git )

leaves us with a file lib/mpack/src/mpack-config.h.sample. Typically one would rename this file to get rid of the .sample suffix, and make changes there. mpack-config.h.sample sets a number of flags depending on what modules we’d like to use (i.e. the expect API etc), and how large buffers should be sized.

For our cases we made the following changes:

#define MPACK_NODE 0
#define MPACK_COMPATIBILITY 0
#define MPACK_STDLIB 0
#define MPACK_STDIO 0
#define MPACK_STACK_SIZE 128
#define MPACK_BUFFER_SIZE 128
#define MPACK_NODE_PAGE_SIZE 128

That is:

  • we do not need the dynamic node api
  • no compatibility to older versions
  • No stdio.h (can live without that on embedded…). This essentially removes the compile errors from above.
  • One can choose to not have stdlib.h either (no malloc, among other things). Without STDLIB, the warnings from above also vanish.
  • We’re lowering buffer sizes from 4K to 128 bytes. This may depend on the size of data that you’re processing, so the last three are options to play around with.
  • If Debugging and meaningful error messages are not needed, then MPACK_DEBUG and MPACK_STRINGS can be set to 0 as well.

In the end, we could also remove the build_flags from platformio.ini, the adaptions to the config file were sufficient.

Happy hacking!