#pragma once // Flat, ungrouped event log the spy Arduino.h/SPI.h shims append to as a // real vendor GxEPD2 driver runs. Deliberately NOT grouped into // EpdCommand-shaped entries here - this exploratory pass prints the raw // observed event stream and compares it against the hand-written // panel_213_z98c.h by eye, to learn what the trace actually looks like // before building a grouping/JSON-emitting post-processor. #include #include #include #include enum class EventKind { PIN_MODE, DIGITAL_WRITE, DIGITAL_READ, DELAY, SPI_BEGIN_TXN, SPI_TRANSFER, SPI_SETTINGS }; struct Trace { // Structured, ordered event log (opt-in via start_event_record) for the // descriptor emitter (emit_descriptor.h). Unlike `record` below - which // keeps SPI bytes only - this also keeps delays and busy-checks interleaved // in call order, so the emitter can attach a delay / wait-busy to the // command it follows. While event-recording, every Trace method suppresses // its printf and appends an Event instead (DC tracking via // note_digital_write_for_dc still runs, so each SPI byte's is_command flag // stays correct). struct Event { EventKind kind; bool is_command = false; // SPI_TRANSFER: DC low at transfer time uint8_t byte = 0; // SPI_TRANSFER int pin = 0; // DIGITAL_WRITE / DIGITAL_READ int value = 0; // DIGITAL_WRITE unsigned long ms = 0; // DELAY }; static inline bool event_recording = false; static inline std::vector events; static void start_event_record() { events.clear(); event_recording = true; } static void stop_event_record() { event_recording = false; } static void pin_mode(int pin, int mode) { if (event_recording) return; printf("pinMode(%d, %d)\n", pin, mode); } static void digital_write(int pin, int value) { if (event_recording) { events.push_back({EventKind::DIGITAL_WRITE, false, 0, pin, value, 0}); return; } printf("digitalWrite(%d, %d)\n", pin, value); } // Every digitalRead() in these drivers is a busy-pin poll - there's // nothing else wired as an input. Log it as such and always report // "released" so _waitWhileBusy()'s loop exits after one check; we // don't need real timing, just to observe *that* a wait happened here. static int digital_read(int pin) { if (event_recording) { events.push_back({EventKind::DIGITAL_READ, false, 0, pin, 0, 0}); return last_busy_release_value; } printf("digitalRead(%d) -> busy-check, reporting released\n", pin); return last_busy_release_value; } static void delay_ms(unsigned long ms) { if (event_recording) { events.push_back({EventKind::DELAY, false, 0, 0, 0, ms}); return; } printf("delay(%lu)\n", ms); } static void spi_settings(uint32_t clock_hz, uint8_t bit_order, uint8_t data_mode) { if (event_recording) return; printf("SPISettings(clock_hz=%u, bit_order=%u, data_mode=%u)\n", (unsigned) clock_hz, bit_order, data_mode); } // dc_state: current logical level of the DC pin at the moment of this // transfer, as last set via digital_write() on the pin number the // harness tells us is DC (see set_dc_pin()). true = command byte, // false = data byte - matches GxEPD2_EPD::_writeCommand()/_writeData() // exactly (DC low while the command byte goes out, high for data). static uint8_t spi_transfer(uint8_t byte) { if (event_recording) events.push_back({EventKind::SPI_TRANSFER, dc_is_low, byte, 0, 0, 0}); // is_command = DC low else if (recording) record.push_back({dc_is_low, byte}); // (is_command, byte) else printf("SPI.transfer(0x%02X) dc=%s\n", byte, dc_is_low ? "LOW(cmd)" : "HIGH(data)"); return 0; } // Byte recording for the diagnostic-fill analyzer (run_diag_harness.h): // when on, SPI bytes are collected (with their command/data flag) instead // of printed, so the analyzer can invert the fill pattern off the exact // byte stream rather than parsing text. Off by default - every other // harness still prints as before. static void start_record() { record.clear(); recording = true; } static void stop_record() { recording = false; } static inline bool recording = false; static inline std::vector> record; // (is_command, byte) static void set_dc_pin(int pin) { dc_pin = pin; } static void note_digital_write_for_dc(int pin, int value) { if (pin == dc_pin) dc_is_low = (value == 0); } static inline int dc_pin = -1; static inline bool dc_is_low = false; static inline int last_busy_release_value = 0; // overwritten by harness once busy_level is known };