Files
xteink-web-emulator/chip/test/test.c
T
2026-07-19 19:23:51 -04:00

78 lines
3.1 KiB
C

// Host self-check for the plane reconstruction (mirror + invert + bit unpack).
// Drives the chip's command/data handlers with a full-sync stream built the way
// EInkDisplay::displayBuffer emits it, then asserts the framebuffer matches the
// source image. Run: make -C chip test
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define W 792
#define H 528
#define WB (W / 8)
static uint8_t g_fb[W * H * 4];
// Minimal Wokwi API mocks (chip only calls these at runtime).
typedef int32_t pin_t;
typedef uint32_t spi_dev_t;
typedef uint32_t timer_t;
typedef uint32_t buffer_t;
typedef struct { void *user_data; uint32_t edge; void (*pin_change)(void *, pin_t, uint32_t); } pin_watch_config_t;
typedef struct { void *user_data; pin_t sck, mosi, miso; uint32_t mode; void (*done)(void *, uint8_t *, uint32_t); uint32_t reserved[8]; } spi_config_t;
typedef struct { void *user_data; void (*callback)(void *); uint32_t reserved[8]; } timer_config_t;
enum { LOW = 0, HIGH = 1, INPUT = 0, OUTPUT = 1, INPUT_PULLUP = 2, OUTPUT_HIGH = 17, BOTH = 3 };
#define NO_PIN ((pin_t)-1)
static pin_t pin_init(const char *n, uint32_t m) { (void)n; (void)m; return 0; }
static uint32_t pin_read(pin_t p) { (void)p; return HIGH; }
static void pin_write(pin_t p, uint32_t v) { (void)p; (void)v; }
static int pin_watch(pin_t p, const pin_watch_config_t *c) { (void)p; (void)c; return 1; }
static spi_dev_t spi_init(const spi_config_t *c) { (void)c; return 0; }
static void spi_start(spi_dev_t s, uint8_t *b, uint32_t n) { (void)s; (void)b; (void)n; }
static void spi_stop(spi_dev_t s) { (void)s; }
static timer_t timer_init(const timer_config_t *c) { (void)c; return 0; }
static void timer_start(timer_t t, uint32_t us, int r) { (void)t; (void)us; (void)r; }
static buffer_t framebuffer_init(uint32_t *w, uint32_t *h) { *w = W; *h = H; return 1; }
static void buffer_write(buffer_t b, uint32_t off, uint8_t *d, uint32_t n) { (void)b; memcpy(g_fb + off, d, n); }
#define WOKWI_API_H
#include "../eink-x3.chip.c"
static void feed_command(uint8_t c) { chip.span_is_command = true; handle_command(c); }
static void feed_data(uint8_t d) { handle_data(d); }
int main(void) {
chip.fb = framebuffer_init(&(uint32_t){0}, &(uint32_t){0});
// Source image: white, with a few black pixels at known coordinates.
static uint8_t src[WB * H];
memset(src, 0xFF, sizeof(src));
const int bx[] = {16, 0, 791, 400};
const int by[] = {3, 0, 527, 260};
for (int k = 0; k < 4; k++)
src[by[k] * WB + bx[k] / 8] &= (uint8_t)~(0x80 >> (bx[k] % 8));
// Full-sync stream: 0x13 + inverted, bottom-to-top plane; polarity 0xA9; 0x12.
feed_command(0x13);
for (int i = 0; i < H; i++) {
const int srcY = H - 1 - i;
for (int x = 0; x < WB; x++) feed_data((uint8_t)~src[srcY * WB + x]);
}
feed_command(0x50);
feed_data(0xA9);
feed_data(0x07);
feed_command(0x12);
for (int y = 0; y < H; y++)
for (int x = 0; x < W; x++) {
const int black = !(src[y * WB + x / 8] & (0x80 >> (x % 8)));
const uint8_t got = g_fb[(y * W + x) * 4];
assert(got == (black ? 0x00 : 0xFF));
}
printf("ok: %dx%d reconstructed, mirror+invert correct\n", W, H);
return 0;
}