DEV Community

Cover image for JsonX: Mapping JSON to C Structs on Embedded Systems
Mihail
Mihail

Posted on

JsonX: Mapping JSON to C Structs on Embedded Systems

Introduction

JSON is everywhere - from web services to IoT. But here’s the catch: most popular JSON libraries were written with desktops and servers in mind, where nobody cares about a few extra megabytes. On microcontrollers, especially Cortex-M devices, every byte and every millisecond counts.

Sure, you can push raw C structs around and even write them directly to a config file. It works, but debugging turns into a painful quest.

At some point I got tired of wrestling with JSON on STM32: writing endless boilerplate to walk through cJSON trees, hunting memory leaks, and guessing where malloc would betray me next. That’s when JsonX was born - a lightweight, minimalistic wrapper around cJSON, designed specifically for MCUs and RTOS.

What JsonX Brings to the Table

  • Automatic mapping JSON <> C structures via a flat JX_ELEMENT[] description.

  • Memory control: no heap required (baremetal) or use your RTOS allocators (ThreadX/FreeRTOS).

  • Straightforward configuration via jx_config.h.

  • Less boilerplate when reading/writing configs and reports.

Why not just use cJSON?

Good question. JsonX doesn’t replace cJSON - it complements it. Inside, cJSON still does the parsing and builds its object tree. JsonX adds what’s usually missing in embedded projects:

Mapping instead of manual walking: describe your schema once, JsonX takes care of the rest.

Centralized memory management: all allocations go through a pool or a custom allocator, so you control fragmentation and leaks.

RTOS-friendly integration: ThreadX, FreeRTOS, baremetal with static buffers, or even POSIX with custom allocators.

In short: you keep the ecosystem of cJSON, but without the pain of raw malloc/free on MCUs and without hundreds of lines of repetitive glue code.

Example:
Config structure
typedef struct
{
char device_name[32];
uint32_t baudrate;
bool debug;
} config_t;
static config_t config;

Mapping description
JX_ELEMENT config_desc[] =
{
JX_ELEMENT_STR ("device_name", config.device_name),
JX_ELEMENT_NUM ("baudrate", config.baudrate),
JX_ELEMENT_BOOL("debug", config.debug),
JX_ELEMENT_END()
};

Parsing JSON
jx_json_to_struct(json_str, config_desc);

Generating JSON
char buffer[256];
jx_struct_to_json(config_desc, buffer, sizeof(buffer), JX_FORMAT_PRETTY);

Limitations:

  • Numbers are currently doubles (like in cJSON). A strict int mode is planned. -Max property name length is fixed via JX_PROPERTY_MAX_SIZE.
  • No auto-expansion of element arrays — you define the limit at compile time.

Where to Get It

GitHub: embedmind/JsonX

STM32 usage example: src/example.c

Roadmap

Right now JsonX relies on cJSON for parsing and generation. But I’m considering a move towards a custom parser that would:

  • Work directly with memory pools (ThreadX block pool, FreeRTOS safe allocator).
  • Operate fully without malloc/free.
  • Reduce overhead and improve predictability in constrained systems.

Whether this happens depends on how much demand JsonX gets from the embedded community.

Conclusion

JsonX is a way to use cJSON on microcontrollers without unpredictable allocations and endless glue code. It’s especially useful in projects where every byte and millisecond matters — but you still want JSON to be as easy to work with as on a PC.

Top comments (0)