Five compression algorithms for embedded sensor data. Zero allocations. Zero dependencies. #include and go.
microcodec is a small C99 compression library focused on the data patterns
that actually show up in embedded and IoT systems:
- repeated bytes and zero-padded frames
- small counters, IDs, and flags
- slowly changing sensor readings
- monotonic timestamps
- compact binary payloads
The library is designed around caller-owned buffers, no heap usage, no hidden state, and simple APIs that fit microcontroller codebases.
Additional project resources:
#include "microcodec.h" float temperatures[64]; uint8_t encoded[512]; float recovered[64]; mc_buf_t dst = MC_BUF(encoded, sizeof(encoded)); if (mc_delta_encode_f32(temperatures, 64, 1, &dst) == MC_OK) { mc_delta_decode_f32(MC_SLICE(encoded, dst.len), recovered, 64); }
For general binary blobs:
mc_lzss_ctx_t ctx; mc_lzss_ctx_init(&ctx); uint8_t out[mc_lzss_max_encoded_size(256)]; mc_buf_t dst = MC_BUF(out, sizeof(out)); mc_err_t err = mc_lzss_encode(&ctx, MC_SLICE(data, data_len), &dst); if (err == MC_ERR_INCOMPRESS) { /* store raw data instead */ }
| Algorithm | Best for | Typical ratio | Notes |
|---|---|---|---|
| RLE | Repeated bytes, padding, zeros | 10-50x for uniform data | Simplest, fastest |
| Varint | Small integers, IDs, counters | 2-4x | Exact for small values |
| Delta | Slowly-changing sensor values | 3-8x | Float quantization |
| LZSS | Binary blobs, config data | 2-4x | General purpose |
| Static Huffman | Structured binary data | 1.5-3x | Pre-built table |
All configuration is compile-time and lives in microcodec.h.
#define MICROCODEC_ENABLE_RLE 1 #define MICROCODEC_ENABLE_VARINT 1 #define MICROCODEC_ENABLE_DELTA 1 #define MICROCODEC_ENABLE_LZSS 1 #define MICROCODEC_ENABLE_HUFF 1 #define MICROCODEC_LZSS_WINDOW_SIZE 256 #define MICROCODEC_LZSS_MIN_MATCH 3 #define MICROCODEC_LZSS_MAX_MATCH 18 #define MICROCODEC_HUFF_SYMBOLS 256 #define MICROCODEC_HUFF_MAX_CODE_LEN 15 #define MICROCODEC_DELTA_F32_SCALE 100.0f
Main families:
mc_rle_encode/mc_rle_decodemc_varint_encode_*/mc_varint_decode_*mc_delta_encode_*/mc_delta_decode_*mc_lzss_ctx_init,mc_lzss_encode,mc_lzss_decodemc_huff_build_table,mc_huff_encode_static,mc_huff_decode_staticmc_huff_encode_adaptive,mc_huff_decode_adaptive
Dispatch API:
mc_encodemc_decodemc_max_encoded_sizemc_alg_name
Current dispatch contract in this repo:
MC_ALG_RLE,MC_ALG_LZSS,MC_ALG_HUFFoperate on raw bytesMC_ALG_VARINToperates onuint32_t[]passed viasrc.ptrMC_ALG_DELTAoperates onfloat[]passed viasrc.ptrwith default order1
microcodec is intentionally separate from microdb. A typical pattern is:
float readings[50]; uint8_t compressed[256]; mc_buf_t cbuf = MC_BUF(compressed, sizeof(compressed)); mc_delta_encode_f32(readings, 50, 1, &cbuf); microdb_kv_put(&db, "sensor_burst", compressed, cbuf.len);
On load, read the compressed bytes from microdb and decode them back into the
target array with the matching mc_*_decode call.
- No heap allocation anywhere in the codec implementations
- No global mutable state
- All APIs are caller-buffer driven
- Compile-time feature toggles for each algorithm
- Separate focused codecs instead of one opaque auto-tuned compressor
microcodec is intended to live alongside small focused embedded libraries such
as microdb and other components in the micro-toolkit ecosystem.
MIT