|
@@ -0,0 +1,512 @@
|
|
|
+///////////////////////////////////////////////////////
|
|
|
+//
|
|
|
+// DCC packet analyze: Ruud Boer, October 2015
|
|
|
+// DCC packet capture: Robin McKay, March 2014
|
|
|
+//
|
|
|
+// The DCC signal is detected on Arduino digital pin 2
|
|
|
+//
|
|
|
+// Set theSerial Monitor Baud Rate to 38400 !!
|
|
|
+//
|
|
|
+// Keyboard commands that can be sent viaSerial Monitor:
|
|
|
+// 1 = 1s refresh time
|
|
|
+// 2 = 2s
|
|
|
+// 3 = 4s (default)
|
|
|
+// 4 = 8s
|
|
|
+// 5 = 16s
|
|
|
+// 6 = 4 DCC packet buffer
|
|
|
+// 7 = 8
|
|
|
+// 8 = 16
|
|
|
+// 9 = 32 (default)
|
|
|
+// 0 = 64
|
|
|
+// a = show accessory packets toggle
|
|
|
+// l = show locomotive packets toggle
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+byte refreshTime = 4; // Time between DCC packets buffer refreshes in s
|
|
|
+byte packetBufferSize = 2; // DCC packets buffer size
|
|
|
+
|
|
|
+#define TIMER_PRESCALER 64
|
|
|
+#define DccBitTimerCount (F_CPU * 80L / TIMER_PRESCALER / 1000000L)
|
|
|
+// 16000000 * 80 / 64 / 1000000 = 20; 20 x 4usecs = 80us
|
|
|
+
|
|
|
+boolean packetEnd;
|
|
|
+boolean preambleFound;
|
|
|
+
|
|
|
+const byte bitBufSize = 50; // number of slots for bits
|
|
|
+volatile byte bitBuffer[bitBufSize];
|
|
|
+volatile byte bitBuffHead = 1;
|
|
|
+volatile byte bitBuffTail = 0;
|
|
|
+
|
|
|
+byte pktByteCount = 0;
|
|
|
+byte packetBytesCount;
|
|
|
+byte preambleOneCount;
|
|
|
+byte dccPacket[6]; // buffer to hold a packet
|
|
|
+byte instrByte1;
|
|
|
+byte decoderType; //0=Loc, 1=Acc
|
|
|
+byte bufferCounter = 0;
|
|
|
+byte isDifferentPacket = 0;
|
|
|
+byte showLoc = 1;
|
|
|
+byte showAcc = 1;
|
|
|
+
|
|
|
+
|
|
|
+unsigned int decoderAddress;
|
|
|
+unsigned int packetBuffer[64];
|
|
|
+unsigned int packetNew = 0;
|
|
|
+
|
|
|
+unsigned long timeToRefresh = millis() + refreshTime * 1000;
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+//custom vars
|
|
|
+#include<SPI.h>
|
|
|
+
|
|
|
+const int boards = 3 ;
|
|
|
+const int registers = boards*3;
|
|
|
+const int outputCount = registers*8;
|
|
|
+
|
|
|
+const int signalValsLength = outputCount; //2signalvals = 1 sein
|
|
|
+int signalVals[signalValsLength];
|
|
|
+
|
|
|
+byte data[registers]; //data array die naar de registers wordt gestuurd, index register , value = byte (00000000)
|
|
|
+int bitCounter = 0; //bits in byte 0 tot 7
|
|
|
+int byteCounter = 0; //byte gelijk aan register
|
|
|
+int val = 0; //tijdelijk var om de value voor de bit te bepalen
|
|
|
+
|
|
|
+bool testMode = true;
|
|
|
+int testOffset = 0;
|
|
|
+int testInterval = 1000;
|
|
|
+unsigned long updateTestAt = millis()+testInterval;
|
|
|
+//end custom vars
|
|
|
+
|
|
|
+//custom functions
|
|
|
+
|
|
|
+void setTestValues(bool val){
|
|
|
+ if(val == testMode)
|
|
|
+ return;
|
|
|
+ testMode = val;
|
|
|
+ Serial.print("setting testVal ");
|
|
|
+ Serial.println(val);
|
|
|
+ if(!val){
|
|
|
+ processData();
|
|
|
+ updateRegisters();
|
|
|
+ }else{
|
|
|
+ updateTestData();
|
|
|
+ updateRegisters();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void updateTestData(){
|
|
|
+ bitCounter = 0;
|
|
|
+ byteCounter = 0;
|
|
|
+ if(testOffset == 3)
|
|
|
+ testOffset = 0;
|
|
|
+ for (int i = 0; i < signalValsLength; i++){
|
|
|
+ if(bitCounter > 7){
|
|
|
+ byteCounter++;
|
|
|
+ bitCounter = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ //stap door
|
|
|
+ if((i+testOffset) % 3 != 0)
|
|
|
+ bitSet(data[byteCounter],7-bitCounter);
|
|
|
+ else
|
|
|
+ bitClear(data[byteCounter],7-bitCounter);
|
|
|
+ bitCounter++;
|
|
|
+
|
|
|
+ //random*/
|
|
|
+ /*
|
|
|
+ if(random(0,2) == 1)
|
|
|
+ bitSet(data[byteCounter],7-bitCounter);
|
|
|
+ else
|
|
|
+ bitClear(data[byteCounter],7-bitCounter);
|
|
|
+ bitCounter++;
|
|
|
+ //*/
|
|
|
+ }
|
|
|
+
|
|
|
+ testOffset++;
|
|
|
+}
|
|
|
+
|
|
|
+void processData(){
|
|
|
+ Serial.println("1");
|
|
|
+ bitCounter = 0;
|
|
|
+ byteCounter = 0;
|
|
|
+ for (int i = 0; i < signalValsLength; i++){
|
|
|
+ if(bitCounter > 7){
|
|
|
+ byteCounter++;
|
|
|
+ bitCounter = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(signalVals[i] == 1)
|
|
|
+ bitSet(data[byteCounter],7-bitCounter);
|
|
|
+ else
|
|
|
+ bitClear(data[byteCounter],7-bitCounter);
|
|
|
+ bitCounter++;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void printStatus(int value){
|
|
|
+ switch(value){
|
|
|
+ case 0:
|
|
|
+ Serial.print("groen");
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ Serial.print("rood");
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ Serial.print("oranje");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ Serial.print("invalid signal");
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+ Serial.print(" ");
|
|
|
+ Serial.println(value);
|
|
|
+}
|
|
|
+
|
|
|
+void setupSpi(){
|
|
|
+ SPI.begin();
|
|
|
+ pinMode(SS, OUTPUT);
|
|
|
+ digitalWrite(SS, HIGH);
|
|
|
+ SPI.setDataMode(3);
|
|
|
+ SPI.setClockDivider(4);
|
|
|
+ SPI.setBitOrder(LSBFIRST);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void updateRegisters(){
|
|
|
+ //Serial.println("2");
|
|
|
+ digitalWrite(SS, LOW);
|
|
|
+ //digitalWrite(13, LOW);
|
|
|
+ for(int r = registers-1; r >= 0 ; r--){
|
|
|
+ SPI.transfer(data[r]); // high byte
|
|
|
+ }
|
|
|
+ digitalWrite(SS, HIGH);
|
|
|
+ digitalWrite(13, HIGH);
|
|
|
+}
|
|
|
+
|
|
|
+void resetData(){
|
|
|
+ return;
|
|
|
+ bitCounter = 0;
|
|
|
+ byteCounter = 0;
|
|
|
+ for(int r = registers-1; r >= 0 ; r--){
|
|
|
+ data[r] = 0; // reset Byte
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void handleData(int addr , bool val){
|
|
|
+ if(addr == 799){
|
|
|
+ setTestValues(val);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(addr <= 899)
|
|
|
+ return;
|
|
|
+ addr = addr-900;
|
|
|
+ if(val)
|
|
|
+ signalVals[addr] = 0;
|
|
|
+ else
|
|
|
+ signalVals[addr] = 1;
|
|
|
+
|
|
|
+ processData();
|
|
|
+ updateRegisters();
|
|
|
+}
|
|
|
+
|
|
|
+//end custom functions
|
|
|
+
|
|
|
+void getPacket() {
|
|
|
+ preambleFound = false;
|
|
|
+ packetEnd = false;
|
|
|
+ packetBytesCount = 0;
|
|
|
+ preambleOneCount = 0;
|
|
|
+ while (! packetEnd) {
|
|
|
+ if (preambleFound) getNextByte();
|
|
|
+ else checkForPreamble();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void checkForPreamble() {
|
|
|
+ byte nextBit = getBit();
|
|
|
+ if (nextBit == 1) preambleOneCount++;
|
|
|
+ if (preambleOneCount < 10 && nextBit == 0) preambleOneCount = 0;
|
|
|
+ if (preambleOneCount >= 10 && nextBit == 0) preambleFound = true;
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void getNextByte() {
|
|
|
+ byte newByte = 0;
|
|
|
+ for (byte n = 0; n < 8; n++) newByte = (newByte << 1) + getBit();
|
|
|
+ packetBytesCount ++;
|
|
|
+ dccPacket[packetBytesCount] = newByte;
|
|
|
+ dccPacket[0] = packetBytesCount;
|
|
|
+ if (getBit() == 1) packetEnd = true;
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+byte getBit() {
|
|
|
+ // gets the next bit from the bitBuffer
|
|
|
+ // if the buffer is empty it will wait indefinitely for bits to arrive
|
|
|
+ byte nbs = bitBuffHead;
|
|
|
+ while (nbs == bitBuffHead) byte nbs = nextBitSlot(bitBuffTail); //Buffer empty
|
|
|
+ bitBuffTail = nbs;
|
|
|
+ return (bitBuffer[bitBuffTail]);
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void beginBitDetection() {
|
|
|
+ TCCR0A &= B11111100;
|
|
|
+ attachInterrupt(0, startTimer, RISING);
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void startTimer() {
|
|
|
+ OCR0B = TCNT0 + DccBitTimerCount;
|
|
|
+ TIMSK0 |= B00000100;
|
|
|
+ TIFR0 |= B00000100;
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+ISR(TIMER0_COMPB_vect) {
|
|
|
+ byte bitFound = ! ((PIND & B00000100) >> 2);
|
|
|
+ TIMSK0 &= B11111011;
|
|
|
+ byte nbs = nextBitSlot(bitBuffHead);
|
|
|
+ if (nbs == bitBuffTail) return;
|
|
|
+ else {
|
|
|
+ bitBuffHead = nbs;
|
|
|
+ bitBuffer[bitBuffHead] = bitFound;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+byte nextBitSlot(byte slot) {
|
|
|
+ slot ++;
|
|
|
+ if (slot >= bitBufSize) slot = 0;
|
|
|
+ return (slot);
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void printPacket() {
|
|
|
+ Serial.print(" ");
|
|
|
+ for (byte n = 1; n < pktByteCount; n++) {
|
|
|
+ Serial.print(" ");
|
|
|
+ Serial.print(dccPacket[n], BIN);
|
|
|
+ }
|
|
|
+ Serial.println(" ");
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void refreshBuffer() {
|
|
|
+ timeToRefresh = millis() + refreshTime * 500;
|
|
|
+ for (byte n = 0; n < packetBufferSize; n++) packetBuffer[n] = 0;
|
|
|
+ bufferCounter = 0;
|
|
|
+ Serial.println("-");
|
|
|
+ /*
|
|
|
+ Serial.print("Loc ");
|
|
|
+ Serial.print(showLoc);
|
|
|
+ Serial.print(" / Acc ");
|
|
|
+ Serial.print(showAcc);
|
|
|
+ Serial.print(" / Time ");
|
|
|
+ Serial.print(refreshTime);
|
|
|
+ Serial.print(" / Buff ");
|
|
|
+ Serial.println(packetBufferSize);
|
|
|
+ Serial.println(" ");
|
|
|
+ */
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//========================
|
|
|
+
|
|
|
+void setup() {
|
|
|
+ Serial.begin(38400); // 38400 when on DCC, 9600 when testing on 123Circuits !!!!!!!!!!!!!!!!!!!!!!!
|
|
|
+ Serial.println("---");
|
|
|
+ Serial.println("DCC Packet Analyze started");
|
|
|
+ Serial.print("Updates every ");
|
|
|
+ Serial.print(refreshTime);
|
|
|
+ Serial.println(" seconds");
|
|
|
+ Serial.println("---");
|
|
|
+
|
|
|
+ setupSpi();
|
|
|
+
|
|
|
+ processData();
|
|
|
+ updateRegisters();
|
|
|
+
|
|
|
+ beginBitDetection(); //Uncomment this line when on DCC !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
+}
|
|
|
+
|
|
|
+//====================
|
|
|
+
|
|
|
+void loop() {
|
|
|
+ updateRegisters();
|
|
|
+ getPacket(); //Uncomment this line when on DCC !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
+ byte speed;
|
|
|
+ byte checksum = 0;
|
|
|
+
|
|
|
+ if (millis() > timeToRefresh){
|
|
|
+ refreshBuffer();
|
|
|
+ //processData();
|
|
|
+ //updateRegisters();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(millis() > updateTestAt && testMode )
|
|
|
+ {
|
|
|
+ Serial.println("running test");
|
|
|
+ updateTestAt = millis()+testInterval;
|
|
|
+ updateTestData();
|
|
|
+ updateRegisters();
|
|
|
+ }
|
|
|
+
|
|
|
+ pktByteCount = dccPacket[0];
|
|
|
+ if (!pktByteCount){
|
|
|
+ Serial.println("nodata");
|
|
|
+ return; // No new packet available
|
|
|
+ }
|
|
|
+
|
|
|
+ for (byte n = 1; n <= pktByteCount; n++) checksum ^= dccPacket[n];
|
|
|
+ //checksum=0; //Comment this line when on DCC !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
+ if (checksum) {
|
|
|
+ Serial.println("invalid checkSum");
|
|
|
+ return; // Invalid Checksum
|
|
|
+ }
|
|
|
+
|
|
|
+ else { // There is a new packet with a correct checksum
|
|
|
+ isDifferentPacket = 1;
|
|
|
+ for (byte n = 0; n < packetBufferSize ; n++) { // Check if packet is not already in the buffer.
|
|
|
+ // The checksum byte is used for the test, not ideal, some new packets may not show (only 256 different checksums)
|
|
|
+ if (dccPacket[pktByteCount] == packetBuffer[n]) isDifferentPacket = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isDifferentPacket) { // packet does not yet exist in the packet buffer
|
|
|
+ packetBuffer[bufferCounter] = dccPacket[pktByteCount]; // add new packet to the buffer
|
|
|
+ bufferCounter = (++bufferCounter) & (packetBufferSize - 1);
|
|
|
+
|
|
|
+ if (dccPacket[1] == B11111111) { //Idle packet
|
|
|
+ Serial.println("Idle ");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!bitRead(dccPacket[1], 7)) { //bit7=0 -> Loc Decoder Short Address
|
|
|
+ decoderAddress = dccPacket[1];
|
|
|
+ instrByte1 = dccPacket[2];
|
|
|
+ decoderType = 0;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (bitRead(dccPacket[1], 6)) { //bit7=1 AND bit6=1 -> Loc Decoder Long Address
|
|
|
+ decoderAddress = 256 * (dccPacket[1] & B00000111) + dccPacket[2];
|
|
|
+ instrByte1 = dccPacket[3];
|
|
|
+ decoderType = 0;
|
|
|
+ }
|
|
|
+ else { //bit7=1 AND bit6=0 -> Accessory Decoder
|
|
|
+ decoderAddress = dccPacket[1] & B00111111;
|
|
|
+ instrByte1 = dccPacket[2];
|
|
|
+ decoderType = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (decoderType) { // Accessory Basic
|
|
|
+ if (showAcc) {
|
|
|
+ if (instrByte1 & B10000000) { // Basic Accessory
|
|
|
+ decoderAddress = (((~instrByte1)&B01110000) << 2) + decoderAddress;
|
|
|
+ byte port = (instrByte1 & B00000110) >> 1;
|
|
|
+ int decAddr = (decoderAddress) * 4 + port + 1;
|
|
|
+ Serial.print("Acc ");
|
|
|
+ Serial.print(decAddr);
|
|
|
+ Serial.print(" ");
|
|
|
+ Serial.print(decoderAddress);
|
|
|
+ Serial.print(":");
|
|
|
+ Serial.print(port);
|
|
|
+ Serial.print(" ");
|
|
|
+ Serial.print(bitRead(instrByte1, 3));
|
|
|
+ if (bitRead(instrByte1, 0)){
|
|
|
+ Serial.print(" On");
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ Serial.print(" Off");
|
|
|
+ }
|
|
|
+ //custom code
|
|
|
+ handleData(decAddr ,bitRead(instrByte1, 0));
|
|
|
+ //end custom code
|
|
|
+ }
|
|
|
+ else { // Accessory Extended NMRA spec is not clear about address and instruction format !!!
|
|
|
+ Serial.print("Acc Ext ");
|
|
|
+ decoderAddress = (decoderAddress << 5) + ((instrByte1 & B01110000) >> 2) + ((instrByte1 & B00000110) >> 1);
|
|
|
+ Serial.print(decoderAddress);
|
|
|
+ Serial.print(" Asp ");
|
|
|
+ Serial.print(dccPacket[3], BIN);
|
|
|
+ }
|
|
|
+ printPacket();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else { // Loc / Multi Function Decoder
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (Serial.available()) {
|
|
|
+ Serial.println(" ");
|
|
|
+ switch (Serial.read()) {
|
|
|
+ case 49:
|
|
|
+ Serial.println("Refresh Time = 1s");
|
|
|
+ refreshTime = 1;
|
|
|
+ break;
|
|
|
+ case 50:
|
|
|
+ Serial.println("Refresh Time = 2s");
|
|
|
+ refreshTime = 2;
|
|
|
+ break;
|
|
|
+ case 51:
|
|
|
+ Serial.println("Refresh Time = 4s");
|
|
|
+ refreshTime = 4;
|
|
|
+ break;
|
|
|
+ case 52:
|
|
|
+ Serial.println("Refresh Time = 8s");
|
|
|
+ refreshTime = 8;
|
|
|
+ break;
|
|
|
+ case 53:
|
|
|
+ Serial.println("Refresh Time = 16s");
|
|
|
+ refreshTime = 16;
|
|
|
+ break;
|
|
|
+ case 54:
|
|
|
+ Serial.println("Buffer Size = 4");
|
|
|
+ packetBufferSize = 2;
|
|
|
+ break;
|
|
|
+ case 55:
|
|
|
+ Serial.println("Buffer Size = 8");
|
|
|
+ packetBufferSize = 8;
|
|
|
+ break;
|
|
|
+ case 56:
|
|
|
+ Serial.println("Buffer Size = 16");
|
|
|
+ packetBufferSize = 16;
|
|
|
+ break;
|
|
|
+ case 57:
|
|
|
+ Serial.println("Buffer Size = 32");
|
|
|
+ packetBufferSize = 32;
|
|
|
+ break;
|
|
|
+ case 48:
|
|
|
+ Serial.println("Buffer Size = 64");
|
|
|
+ packetBufferSize = 64;
|
|
|
+ break;
|
|
|
+ case 97:
|
|
|
+ if (showAcc) showAcc = 0; else showAcc = 1;
|
|
|
+ Serial.print("show acc packets = ");
|
|
|
+ Serial.println(showAcc);
|
|
|
+ break;
|
|
|
+ case 108:
|
|
|
+ if (showLoc) showLoc = 0; else showLoc = 1;
|
|
|
+ Serial.print("show loc packets = ");
|
|
|
+ Serial.println(showLoc);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ Serial.println(" ");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//=====================
|