M5Unit-NFC 0.1.2 git rev:63c4caa
Loading...
Searching...
No Matches
emulation_trace.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
19#ifndef M5_UNIT_NFC_NFC_LAYER_EMULATION_TRACE_HPP
20#define M5_UNIT_NFC_NFC_LAYER_EMULATION_TRACE_HPP
21
22#include <stdint.h>
23
24#if defined(M5_UNIT_NFC_EMULATION_TRACE)
25#include <stdio.h>
26#include <M5Utility.hpp>
27#endif
28
29// Folding repeats keeps one session down to a handful of entries, so this covers more than a dozen
30// approaches of a reader
31#if !defined(M5_UNIT_NFC_EMULATION_TRACE_MAX)
32#define M5_UNIT_NFC_EMULATION_TRACE_MAX (128)
33#endif
34
35namespace m5 {
36namespace nfc {
37namespace emulation {
38
39/*
40 Records what the adapter state machine saw, to be printed later
41 @details The names of the events are given by the adapter, so NFC-A and NFC-F can use their own
42 state names while sharing this recorder
43 */
44class Trace {
45public:
46 /*
47 @param names Event names, indexed by the value given to record()
48 @param num Number of names
49 */
50 Trace(const char* const* names, const uint8_t num) : _names{names}, _num{num}
51 {
52 }
53
54 /*
55 Append one entry, or count it against the previous one when it repeats
56 @param ev Event, an index into the names given to the constructor
57 @param irq Interrupt bits that were seen, if any
58 @param detail Anything the adapter wants to keep, such as a register value
59 */
60 void record(const uint8_t ev, const uint32_t irq = 0, const uint8_t detail = 0)
61 {
62#if defined(M5_UNIT_NFC_EMULATION_TRACE)
63 const uint32_t now = m5::utility::millis();
64
65 // A reader polling a halted PICC produces two events in turn, so matching only the entry
66 // just before would never fold them. The interrupt bits are left out of the comparison
67 // because the same situation reports slightly different bits from one poll to the next;
68 // what was seen is kept by collecting the bits into the entry
69 const uint16_t look = (_count < LOOKBACK) ? _count : LOOKBACK;
70 for (uint_fast16_t back = 1; back <= look; ++back) {
71 auto& e = _entry[(_head + _count - back) % MAX];
72 if (e.ev == ev && e.detail == detail) {
73 if (e.count < 0xFFFF) {
74 ++e.count;
75 }
76 e.irq |= irq;
77 const uint32_t span = now - e.ms;
78 e.span = (span > 0xFFFF) ? 0xFFFF : (uint16_t)span;
79 return;
80 }
81 }
82
83 if (_count < MAX) {
84 _entry[(_head + _count++) % MAX] = Entry{now, irq, 1, 0, ev, detail};
85 } else {
86 // The buffer holds the newest, so the oldest one makes room
87 _entry[_head] = Entry{now, irq, 1, 0, ev, detail};
88 _head = (_head + 1) % MAX;
89 ++_dropped;
90 }
91#else
92 (void)ev;
93 (void)irq;
94 (void)detail;
95#endif
96 }
97
98 /*
99 Print what was recorded and start over
100 @warning Printing takes milliseconds, so call it while the emulation is not answering
101 */
102 void dump()
103 {
104#if defined(M5_UNIT_NFC_EMULATION_TRACE)
105 if (!_count) {
106 return;
107 }
108 printf("---- emulation trace %u", _count);
109 if (_dropped) {
110 printf(" (%u older dropped)", _dropped);
111 }
112 printf(" ----\n");
113
114 for (uint_fast16_t i = 0; i < _count; ++i) {
115 const auto& e = _entry[(_head + i) % MAX];
116 printf("T[%03u] %7u %-9s irq:%08X detail:%02X", (unsigned)i, (unsigned)e.ms,
117 (e.ev < _num) ? _names[e.ev] : "?", (unsigned)e.irq, e.detail);
118 if (e.count > 1) {
119 printf(" x%u (%u ms)", e.count, e.span);
120 }
121 printf("\n");
122 }
123 clear();
124#endif
125 }
126
128 void clear()
129 {
130#if defined(M5_UNIT_NFC_EMULATION_TRACE)
131 _count = 0;
132 _head = 0;
133 _dropped = 0;
134#endif
135 }
136
137private:
138#if defined(M5_UNIT_NFC_EMULATION_TRACE)
139 struct Entry {
140 uint32_t ms; // When the first of the repeats was seen
141 uint32_t irq; //
142 uint16_t count; // How many times in a row
143 uint16_t span; // Milliseconds between the first and the last repeat
144 uint8_t ev; //
145 uint8_t detail; //
146 };
147 static constexpr uint16_t MAX{M5_UNIT_NFC_EMULATION_TRACE_MAX};
148 // How far back a repeat is looked for. Two is enough for the pairs a polling reader produces
149 static constexpr uint16_t LOOKBACK{2};
150 Entry _entry[MAX]{};
151 uint16_t _head{}, _count{}, _dropped{};
152#endif
153 const char* const* _names{};
154 uint8_t _num{};
155};
156
157} // namespace emulation
158} // namespace nfc
159} // namespace m5
160#endif
Definition emulation_trace.hpp:44
void clear()
Forget what was recorded without printing it.
Definition emulation_trace.hpp:128
Top level namespace of M5Stack.
NFC related definitions.