23 #include <util/atomic.h> 113 template <u
int16_t Size = 60, u
int16_t LastErrorSize = 30>
117 byte lastError[LastErrorSize];
118 uint16_t bytesInLastError = 0;
120 uint16_t failureCodes = 0;
121 uint32_t millisAtLastRecording = 0;
123 enum class Ps2Code : uint8_t {
124 packetDidNotStartWithZero = 0,
126 packetDidNotEndWithOne = 2,
127 packetIncomplete = 3,
130 incorrectResponse = 6,
132 noTranslationForKey = 8,
134 _firstUnusedError = 10,
139 clockLineGlitch = 19,
144 _firstUnusedInfo = 22,
147 void recordFailure(uint8_t code) {
149 ATOMIC_BLOCK(ATOMIC_FORCEON) {
150 this->failureCodes |= 1 << code;
153 uint16_t numBytesCopied = 0;
154 uint16_t i = index < 0 ? -1 - index : index;
155 i = (i == 0 ? Size : i) - 1;
156 while (index >= 0 || i != Size - 1)
158 byte bytesInWord = 1 + (this->data[i] & 0x3);
159 if (numBytesCopied + bytesInWord > LastErrorSize) {
163 while (bytesInWord > 0) {
164 this->lastError[numBytesCopied] = this->data[i];
165 i = (i == 0 ? Size : i) - 1;
170 bytesInLastError = numBytesCopied;
174 void pushByte(byte b)
176 ATOMIC_BLOCK(ATOMIC_FORCEON) {
178 data[-1 - index] = b;
179 index = (index == -Size) ? 0 : index - 1;
183 index = (index == Size - 1) ? 0 : index + 1;
188 void pushRaw(byte code) {
190 this->recordFailure(code);
192 void pushRaw(byte code, byte extraData1) {
193 pushByte(extraData1);
194 pushByte((code << 2) | 1);
195 this->recordFailure(code);
197 void pushRaw(byte code, byte extraData1, byte extraData2) {
198 pushByte(extraData2);
199 pushByte(extraData1);
200 pushByte((code << 2) | 2);
201 this->recordFailure(code);
206 unsigned long millisNow = millis();
207 unsigned long timeDelta = millisNow - millisAtLastRecording;
208 if (timeDelta >= 4 && timeDelta < 2044) {
209 pushRaw((byte)Ps2Code::pause, (byte)((timeDelta + 4) >> 3));
210 millisAtLastRecording = millisNow;
212 else if (timeDelta >= 2044) {
213 unsigned long lowResDelay = (timeDelta + 32) >> 6;
214 if (lowResDelay > 0xffff) {
215 lowResDelay = 0xffff;
217 pushRaw((byte)Ps2Code::pause, (byte)(lowResDelay >>8), (byte)(lowResDelay & 0xff));
218 millisAtLastRecording = millisNow;
224 static const uint8_t firstUnusedFailureCode = (uint8_t)Ps2Code::_firstUnusedError;
225 static const uint8_t firstUnusedInfoCode = (uint8_t)Ps2Code::_firstUnusedInfo;
227 template <
typename E>
232 template <
typename E1,
typename E2>
233 void push(E1 code, E2 extraData1) {
235 pushRaw((byte)code, (uint8_t)extraData1);
237 template <
typename E1,
typename E2,
typename E3>
238 void push(E1 code, E2 extraData1, E3 extraData2) {
240 pushRaw((byte)code, (byte)extraData1, (byte)extraData2);
247 template <
typename Target>
257 printTo.print(this->failureCodes, 16);
261 for (
int i = bytesInLastError-1; i >= 0; --i) {
262 printTo.print(this->lastError[i] >> 4, 16);
263 printTo.print(this->lastError[i] & 0xf, 16);
269 for (
int i = 0; i < -1 - this->index; ++i) {
271 printTo.print(this->data[i] >> 4, 16);
272 printTo.print(this->data[i] & 0xf, 16);
276 for (
int i = this->index; i < Size + this->index; ++i) {
277 printTo.print(this->data[i % Size] >> 4, 16);
278 printTo.print(this->data[i % Size] & 0xf, 16);
285 bool anyErrors()
const {
return this->failureCodes != 0; }
289 this->failureCodes = 0;
291 this->bytesInLastError = 0;
299 template <u
int8_t DiagnosticLedPin = LED_BUILTIN, DiagnosticsLedBlink LedBehavior = DiagnosticsLedBlink::blinkOnError>
302 switch (LedBehavior) {
304 value = (millis() & (failureCodes != 0 ? 128 : 1024));
307 value = (failureCodes == 0 || (millis() & 128));
310 value = (failureCodes != 0);
313 value = (failureCodes == 0);
316 digitalWrite(DiagnosticLedPin, value ? HIGH : LOW);
326 this->push(Ps2Code::incorrectResponse, scanCode, expectedScanCode);
329 this->push(Ps2Code::noResponse, expectedScanCode);
332 this->push(Ps2Code::noTranslationForKey, isExtended, code);
336 this->push(Ps2Code::clockLineGlitch, numBitsSent);
339 void sentByte(byte b) { this->push(Ps2Code::sentByte, b); }
void push(E1 code, E2 extraData1, E3 extraData2)
Definition: ps2_SimpleDiagnostics.h:238
DiagnosticsLedBlink
Used with SimpleDiagnostics to control the behavior of a pin that will signal the device's user that ...
Definition: ps2_SimpleDiagnostics.h:29
void sendFrameError()
Definition: ps2_SimpleDiagnostics.h:323
Definition: ps2_AnsiTranslator.h:24
void noTranslationForKey(bool isExtended, KeyboardOutput code)
Definition: ps2_SimpleDiagnostics.h:331
void incorrectResponse(KeyboardOutput scanCode, KeyboardOutput expectedScanCode)
Definition: ps2_SimpleDiagnostics.h:325
void push(E1 code, E2 extraData1)
Definition: ps2_SimpleDiagnostics.h:233
void push(E code)
Definition: ps2_SimpleDiagnostics.h:228
void clockLineGlitch(uint8_t numBitsSent)
Definition: ps2_SimpleDiagnostics.h:335
void sentByte(byte b)
Definition: ps2_SimpleDiagnostics.h:339
KeyboardOutput
Byte-codes sent back from the Ps2 keyboard to the host.
Definition: ps2_KeyboardOutput.h:31
void bufferOverflow()
Definition: ps2_SimpleDiagnostics.h:324
void sendReport(Target &printTo)
Dumps all event data to a print-based class.
Definition: ps2_SimpleDiagnostics.h:248
void receivedByte(byte b)
Definition: ps2_SimpleDiagnostics.h:340
void noResponse(KeyboardOutput expectedScanCode)
Definition: ps2_SimpleDiagnostics.h:328
void parityError()
Definition: ps2_SimpleDiagnostics.h:320
A basic recorder for events coming from the PS2 keyboard class library.
Definition: ps2_SimpleDiagnostics.h:114
void startupFailure()
Definition: ps2_SimpleDiagnostics.h:334
void packetDidNotEndWithOne()
Definition: ps2_SimpleDiagnostics.h:321
void packetIncomplete()
Definition: ps2_SimpleDiagnostics.h:322
void reset()
Clears all recorded data.
Definition: ps2_SimpleDiagnostics.h:288
void packetDidNotStartWithZero()
Definition: ps2_SimpleDiagnostics.h:319
bool anyErrors() const
Returns true if any errors have been recorded since the last call to reset.
Definition: ps2_SimpleDiagnostics.h:285
void setLedIndicator()
Enables you to have a blinking indicator when an error happens.
Definition: ps2_SimpleDiagnostics.h:300