/* Library: DCC_Decoder Original file: DCC_Monitor File: DCC_Decoder-Monitor Descr: Monitors DCC-traffic and prints packets to the serial monitor By: Ed den Ouden 2022 DCC-Edd (public domain) Remark: In order to function properly this library needs an active DCC locomotive to be on the track */ #include // library to use for this sketch #define kDCC_INTERRUPT 0 typedef struct // internal datafields for the DCC-decoder { int count; byte validBytes; byte data[6]; } DCCPacket; // the DCC-decoder object and global data int gPacketCount = 0; int gIdlePacketCount = 0; int gLongestPreamble = 0; DCCPacket gPackets[25]; static unsigned long lastMillis = millis(); boolean RawPacket_Handler(byte byteCount, byte* packetBytes) { // bump global packet count ++gPacketCount; int thisPreamble = DCC.LastPreambleBitCount(); if ( thisPreamble > gLongestPreamble ) { gLongestPreamble = thisPreamble; } // search table and look for a matching packet for ( int i = 0; i < (int)(sizeof(gPackets) / sizeof(gPackets[0])); ++i ) { if ( gPackets[i].validBytes ) { // not an empty slot. Does this slot match this packet? If so, bump count if ( gPackets[i].validBytes == byteCount ) { char isPacket = true; for ( int j = 0; j < byteCount; j++) { if ( gPackets[i].data[j] != packetBytes[j] ) { isPacket = false; break; } } if ( isPacket ) { gPackets[i].count++; return false; } } } else { // empty slot, just copy over data gPackets[i].count++; gPackets[i].validBytes = byteCount; for ( int j = 0; j < byteCount; j++) { gPackets[i].data[j] = packetBytes[j]; } return false; } } return false; } // idle packets are sent here (unless handled in rawpacket handler). void IdlePacket_Handler(byte byteCount, byte* packetBytes) { ++gIdlePacketCount; } // setup void setup() { Serial.begin(115200); Serial.println("DCC packet monitor, Ed den Ouden 2022 (lib: DCC_Decoder)"); Serial.println(""); Serial.println("Ready/idle, waiting for DCC-packets..."); Serial.println(""); DCC.SetRawPacketHandler(RawPacket_Handler); DCC.SetIdlePacketHandler(IdlePacket_Handler); DCC.SetupMonitor( kDCC_INTERRUPT ); } void DumpAndResetTable() { char buffer60Bytes[60]; Serial.print("Total Packet Count: "); Serial.println(gPacketCount, DEC); Serial.print("Idle Packet Count: "); Serial.println(gIdlePacketCount, DEC); Serial.print("Longest Preamble: "); Serial.println(gLongestPreamble, DEC); Serial.println(""); Serial.println("Count Packet_Data"); for ( int i = 0; i < (int)(sizeof(gPackets) / sizeof(gPackets[0])); ++i ) { if ( gPackets[i].validBytes > 0 ) { Serial.print(gPackets[i].count, DEC); if ( gPackets[i].count < 10 ) { Serial.print(" "); } else { if ( gPackets[i].count < 100 ) { Serial.print(" "); } else { Serial.print(" "); } } Serial.println( DCC.MakePacketString(buffer60Bytes, gPackets[i].validBytes, &gPackets[i].data[0]) ); } gPackets[i].validBytes = 0; gPackets[i].count = 0; } Serial.println(""); Serial.println(""); gPacketCount = 0; gIdlePacketCount = 0; gLongestPreamble = 0; } void loop() { DCC.loop(); if ( millis() - lastMillis > 2000 ) { DumpAndResetTable(); lastMillis = millis(); } }