|
|
|
|
@ -153,47 +153,83 @@ void oled_draw_header(void)
|
|
|
|
|
}
|
|
|
|
|
// Slot 5 (cols 80-95): percentage text, page 0
|
|
|
|
|
// Slot 6 (cols 96-111): vertical battery icon, nub at top, fill from bottom
|
|
|
|
|
// or lightning bolt when charging
|
|
|
|
|
if (g_battery_pct >= 0) {
|
|
|
|
|
int show = (g_battery_pct >= BATT_LOW_PCT || (g_tick / 50) % 2 == 0);
|
|
|
|
|
|
|
|
|
|
if (show) {
|
|
|
|
|
// ── Percentage text, vertically centered (rows 4-11) ─────────────
|
|
|
|
|
char pct_str[5];
|
|
|
|
|
int plen = snprintf(pct_str, sizeof(pct_str), "%d", g_battery_pct);
|
|
|
|
|
int tx = 5 * SEG_W + (SEG_W - plen * 5) / 2;
|
|
|
|
|
for (int ci = 0; ci < plen; ci++) {
|
|
|
|
|
uint8_t c = (uint8_t)pct_str[ci];
|
|
|
|
|
if (c < FONT_BASE || c > FONT_MAX) continue;
|
|
|
|
|
const uint8_t *glyph = font5x8[c - FONT_BASE];
|
|
|
|
|
for (int sc = 0; sc < 5; sc++, tx++) {
|
|
|
|
|
if (tx < 0 || tx >= OLED_WIDTH) continue;
|
|
|
|
|
pages[0][tx] &= ~(uint8_t)(glyph[sc] << 4); // font bits 0-3 → rows 4-7
|
|
|
|
|
pages[1][tx] &= ~(uint8_t)(glyph[sc] >> 4); // font bits 4-7 → rows 8-11
|
|
|
|
|
if (!g_charging && !g_batt_full) {
|
|
|
|
|
// ── Percentage text, vertically centered (rows 4-11) ─────────
|
|
|
|
|
char pct_str[5];
|
|
|
|
|
int plen = snprintf(pct_str, sizeof(pct_str), "%d", g_battery_pct);
|
|
|
|
|
int tx = 5 * SEG_W + (SEG_W - plen * 5) / 2;
|
|
|
|
|
for (int ci = 0; ci < plen; ci++) {
|
|
|
|
|
uint8_t c = (uint8_t)pct_str[ci];
|
|
|
|
|
if (c < FONT_BASE || c > FONT_MAX) continue;
|
|
|
|
|
const uint8_t *glyph = font5x8[c - FONT_BASE];
|
|
|
|
|
for (int sc = 0; sc < 5; sc++, tx++) {
|
|
|
|
|
if (tx < 0 || tx >= OLED_WIDTH) continue;
|
|
|
|
|
pages[0][tx] &= ~(uint8_t)(glyph[sc] << 4);
|
|
|
|
|
pages[1][tx] &= ~(uint8_t)(glyph[sc] >> 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Vertical battery icon ─────────────────────────────────────────
|
|
|
|
|
// 1px inset from slot edges: body cols 2-13, rows 3-14.
|
|
|
|
|
// Nub: cols 5-10, rows 1-2.
|
|
|
|
|
// Inner: cols 3-12, rows 4-13 (10 rows). Fill rises from bottom.
|
|
|
|
|
int fill_rows = g_battery_pct * 10 / 100;
|
|
|
|
|
int fill_start = 14 - fill_rows; // first filled inner row
|
|
|
|
|
uint8_t p0_fill = 0, p1_fill = 0;
|
|
|
|
|
for (int r = 4; r <= 7; r++) if (r >= fill_start) p0_fill |= (1 << r);
|
|
|
|
|
for (int r = 8; r <= 13; r++) if (r >= fill_start) p1_fill |= (1 << (r-8));
|
|
|
|
|
|
|
|
|
|
// Body: cols 2-13, rows 3-14. Nub: cols 5-10, rows 1-2.
|
|
|
|
|
// Inner: cols 3-12, rows 4-13 (10 rows).
|
|
|
|
|
int bbase = 6 * SEG_W;
|
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
|
uint8_t p0 = 0, p1 = 0;
|
|
|
|
|
if (x == 2 || x == 13) {
|
|
|
|
|
p0 = 0xF8; p1 = 0x7F; // side borders rows 3-14
|
|
|
|
|
} else if (x >= 3 && x <= 12) {
|
|
|
|
|
p0 = 0x08 | p0_fill; // top border (row 3) + fill
|
|
|
|
|
p1 = 0x40 | p1_fill; // bottom border (row 14) + fill
|
|
|
|
|
|
|
|
|
|
if (g_batt_full) {
|
|
|
|
|
// Fully filled battery body; no percentage text.
|
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
|
uint8_t p0 = 0, p1 = 0;
|
|
|
|
|
if (x == 2 || x == 13) {
|
|
|
|
|
p0 = 0xF8; p1 = 0x7F;
|
|
|
|
|
} else if (x >= 3 && x <= 12) {
|
|
|
|
|
p0 = 0xF8; p1 = 0x7F;
|
|
|
|
|
}
|
|
|
|
|
if (x >= 5 && x <= 10) p0 |= 0x06;
|
|
|
|
|
pages[0][bbase + x] &= ~p0;
|
|
|
|
|
pages[1][bbase + x] &= ~p1;
|
|
|
|
|
}
|
|
|
|
|
} else if (g_charging) {
|
|
|
|
|
// Lightning bolt inside body; no fill level or percentage.
|
|
|
|
|
// Per-column page masks for rows 4-13 within the 16-wide slot:
|
|
|
|
|
// p0 bits 4-7 → rows 4-7; p1 bits 0-5 → rows 8-13
|
|
|
|
|
static const uint8_t bp0[16] = {0,0,0,0,0,0x80,0x80,0xC0,0xF0,0x90,0x10,0,0,0,0,0};
|
|
|
|
|
static const uint8_t bp1[16] = {0,0,0,0,0,0x19,0x0D,0x03,0x01,0x01,0x00,0,0,0,0,0};
|
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
|
uint8_t p0 = bp0[x], p1 = bp1[x];
|
|
|
|
|
if (x == 2 || x == 13) {
|
|
|
|
|
p0 |= 0xF8; p1 |= 0x7F;
|
|
|
|
|
} else if (x >= 3 && x <= 12) {
|
|
|
|
|
p0 |= 0x08; // top border row 3
|
|
|
|
|
p1 |= 0x40; // bottom border row 14
|
|
|
|
|
}
|
|
|
|
|
if (x >= 5 && x <= 10) p0 |= 0x06; // nub rows 1-2
|
|
|
|
|
pages[0][bbase + x] &= ~p0;
|
|
|
|
|
pages[1][bbase + x] &= ~p1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Fill level rising from bottom.
|
|
|
|
|
int fill_rows = g_battery_pct * 10 / 100;
|
|
|
|
|
int fill_start = 14 - fill_rows;
|
|
|
|
|
uint8_t p0_fill = 0, p1_fill = 0;
|
|
|
|
|
for (int r = 4; r <= 7; r++) if (r >= fill_start) p0_fill |= (1 << r);
|
|
|
|
|
for (int r = 8; r <= 13; r++) if (r >= fill_start) p1_fill |= (1 << (r-8));
|
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
|
uint8_t p0 = 0, p1 = 0;
|
|
|
|
|
if (x == 2 || x == 13) {
|
|
|
|
|
p0 = 0xF8; p1 = 0x7F;
|
|
|
|
|
} else if (x >= 3 && x <= 12) {
|
|
|
|
|
p0 = 0x08 | p0_fill;
|
|
|
|
|
p1 = 0x40 | p1_fill;
|
|
|
|
|
}
|
|
|
|
|
if (x >= 5 && x <= 10) p0 |= 0x06;
|
|
|
|
|
pages[0][bbase + x] &= ~p0;
|
|
|
|
|
pages[1][bbase + x] &= ~p1;
|
|
|
|
|
}
|
|
|
|
|
if (x >= 5 && x <= 10) p0 |= 0x06; // nub rows 1-2
|
|
|
|
|
pages[0][bbase + x] &= ~p0;
|
|
|
|
|
pages[1][bbase + x] &= ~p1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|