-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmicro_rle.c
More file actions
95 lines (83 loc) · 2.26 KB
/
micro_rle.c
File metadata and controls
95 lines (83 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
* micro_rle.c - 1 kB embedded stream compressor
* Target: ARM Cortex-M0+
*
* Compression: RLE + XOR delta, 40-60% on repetitive logs
* Timing: 6-12 cycles/byte deterministic
* Footprint: 512 B ring + 8 B state
*/
#include "micro_rle.h"
/* ---- Tunables ---- */
#define WIN 32
#define WIN_MSK 31 /* WIN - 1, assumes power-of-2 */
#define STUFF_TH 2
#define RLE_MAX 7
#define STUFF_BYTE 0x7E
/* ---- State ---- */
static struct {
uint8_t prev;
uint8_t run;
uint8_t window[WIN];
uint8_t widx;
uint8_t last_stuff; /* Suppress consecutive STUFF_BYTE */
} s;
/* ---- Helpers ---- */
static inline uint8_t popcnt(uint8_t x) {
x = (x & 0x55) + ((x >> 1) & 0x55);
x = (x & 0x33) + ((x >> 2) & 0x33);
return (x & 0x0F) + (x >> 4);
}
void __attribute__((weak)) emit(uint8_t b) {
/* User hook: write to UART, ring buffer, etc. */
(void)b; /* Replace with actual output */
}
/* ---- API ---- */
void log_init(void) {
s.prev = 0;
s.run = 0;
s.widx = 0;
s.last_stuff = 0;
for (uint8_t i = 0; i < WIN; i++)
s.window[i] = 0;
}
void log_byte(uint8_t curr) {
/* 1. Update sliding window */
s.window[s.widx & WIN_MSK] = curr;
s.widx++;
/* 2. Drift trigger (only after window fills) */
if (s.widx >= WIN) {
uint8_t h1_start = (s.widx - WIN) & WIN_MSK;
uint8_t h2_start = (s.widx - WIN/2) & WIN_MSK;
uint8_t drift = 0;
for (uint8_t i = 0; i < WIN/2; i++) {
drift += popcnt(s.window[(h1_start + i) & WIN_MSK] ^ s.window[(h2_start + i) & WIN_MSK]);
}
if (drift > STUFF_TH && !s.last_stuff) {
emit(STUFF_BYTE);
s.last_stuff = 1;
} else {
s.last_stuff = 0;
}
}
/* 3. RLE / XOR pack */
uint8_t delta = curr ^ s.prev;
if (delta == 0 && s.run < RLE_MAX) {
s.run++;
return;
}
/* Flush accumulated run + delta */
if (delta > 0x1F) {
/* Escape sequence for large deltas */
emit((s.run << 5) | 0x1F);
emit(delta);
} else {
uint8_t token = (s.run << 5) | (delta & 0x1F);
emit(token);
}
s.prev = curr;
s.run = 0;
}
void log_flush(void) {
if (s.run > 0)
emit((s.run - 1) << 5);
}