123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- ///////////////////////////////////////////////////////
- //
- // 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(" ");
- }
- }
- //=====================
|