trace.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #pragma once
  2. // Flat, ungrouped event log the spy Arduino.h/SPI.h shims append to as a
  3. // real vendor GxEPD2 driver runs. Deliberately NOT grouped into
  4. // EpdCommand-shaped entries here - this exploratory pass prints the raw
  5. // observed event stream and compares it against the hand-written
  6. // panel_213_z98c.h by eye, to learn what the trace actually looks like
  7. // before building a grouping/JSON-emitting post-processor.
  8. #include <cstdint>
  9. #include <cstdio>
  10. #include <utility>
  11. #include <vector>
  12. enum class EventKind { PIN_MODE, DIGITAL_WRITE, DIGITAL_READ, DELAY, SPI_BEGIN_TXN, SPI_TRANSFER, SPI_SETTINGS };
  13. struct Trace {
  14. // Structured, ordered event log (opt-in via start_event_record) for the
  15. // descriptor emitter (emit_descriptor.h). Unlike `record` below - which
  16. // keeps SPI bytes only - this also keeps delays and busy-checks interleaved
  17. // in call order, so the emitter can attach a delay / wait-busy to the
  18. // command it follows. While event-recording, every Trace method suppresses
  19. // its printf and appends an Event instead (DC tracking via
  20. // note_digital_write_for_dc still runs, so each SPI byte's is_command flag
  21. // stays correct).
  22. struct Event {
  23. EventKind kind;
  24. bool is_command = false; // SPI_TRANSFER: DC low at transfer time
  25. uint8_t byte = 0; // SPI_TRANSFER
  26. int pin = 0; // DIGITAL_WRITE / DIGITAL_READ
  27. int value = 0; // DIGITAL_WRITE
  28. unsigned long ms = 0; // DELAY
  29. };
  30. static inline bool event_recording = false;
  31. static inline std::vector<Event> events;
  32. static void start_event_record() {
  33. events.clear();
  34. event_recording = true;
  35. }
  36. static void stop_event_record() { event_recording = false; }
  37. static void pin_mode(int pin, int mode) {
  38. if (event_recording)
  39. return;
  40. printf("pinMode(%d, %d)\n", pin, mode);
  41. }
  42. static void digital_write(int pin, int value) {
  43. if (event_recording) {
  44. events.push_back({EventKind::DIGITAL_WRITE, false, 0, pin, value, 0});
  45. return;
  46. }
  47. printf("digitalWrite(%d, %d)\n", pin, value);
  48. }
  49. // Every digitalRead() in these drivers is a busy-pin poll - there's
  50. // nothing else wired as an input. Log it as such and always report
  51. // "released" so _waitWhileBusy()'s loop exits after one check; we
  52. // don't need real timing, just to observe *that* a wait happened here.
  53. static int digital_read(int pin) {
  54. if (event_recording) {
  55. events.push_back({EventKind::DIGITAL_READ, false, 0, pin, 0, 0});
  56. return last_busy_release_value;
  57. }
  58. printf("digitalRead(%d) -> busy-check, reporting released\n", pin);
  59. return last_busy_release_value;
  60. }
  61. static void delay_ms(unsigned long ms) {
  62. if (event_recording) {
  63. events.push_back({EventKind::DELAY, false, 0, 0, 0, ms});
  64. return;
  65. }
  66. printf("delay(%lu)\n", ms);
  67. }
  68. static void spi_settings(uint32_t clock_hz, uint8_t bit_order, uint8_t data_mode) {
  69. if (event_recording)
  70. return;
  71. printf("SPISettings(clock_hz=%u, bit_order=%u, data_mode=%u)\n", (unsigned) clock_hz, bit_order, data_mode);
  72. }
  73. // dc_state: current logical level of the DC pin at the moment of this
  74. // transfer, as last set via digital_write() on the pin number the
  75. // harness tells us is DC (see set_dc_pin()). true = command byte,
  76. // false = data byte - matches GxEPD2_EPD::_writeCommand()/_writeData()
  77. // exactly (DC low while the command byte goes out, high for data).
  78. static uint8_t spi_transfer(uint8_t byte) {
  79. if (event_recording)
  80. events.push_back({EventKind::SPI_TRANSFER, dc_is_low, byte, 0, 0, 0}); // is_command = DC low
  81. else if (recording)
  82. record.push_back({dc_is_low, byte}); // (is_command, byte)
  83. else
  84. printf("SPI.transfer(0x%02X) dc=%s\n", byte, dc_is_low ? "LOW(cmd)" : "HIGH(data)");
  85. return 0;
  86. }
  87. // Byte recording for the diagnostic-fill analyzer (run_diag_harness.h):
  88. // when on, SPI bytes are collected (with their command/data flag) instead
  89. // of printed, so the analyzer can invert the fill pattern off the exact
  90. // byte stream rather than parsing text. Off by default - every other
  91. // harness still prints as before.
  92. static void start_record() {
  93. record.clear();
  94. recording = true;
  95. }
  96. static void stop_record() { recording = false; }
  97. static inline bool recording = false;
  98. static inline std::vector<std::pair<bool, uint8_t>> record; // (is_command, byte)
  99. static void set_dc_pin(int pin) { dc_pin = pin; }
  100. static void note_digital_write_for_dc(int pin, int value) {
  101. if (pin == dc_pin)
  102. dc_is_low = (value == 0);
  103. }
  104. static inline int dc_pin = -1;
  105. static inline bool dc_is_low = false;
  106. static inline int last_busy_release_value = 0; // overwritten by harness once busy_level is known
  107. };