| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- #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 <cstdint>
- #include <cstdio>
- #include <utility>
- #include <vector>
- 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<Event> 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<std::pair<bool, uint8_t>> 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
- };
|