/**************************************************************** DCF39/DCF49 PACKET PARSER / ANALYZER v1.3 2020.04.01 /****************************************************************/ #include <LiquidCrystal.h> #include <TimerOne.h> LiquidCrystal lcd(4,5,6,7,8,9,10); boolean byteEnd; byte ti; int x; byte y; char c[33]; byte incomingByte; byte buff[256]; byte addr; boolean dataBurstEnd; byte realLength; boolean parityBit; byte headParityChk; byte bodyParityChk; byte frameSq; byte LField1; boolean lostData; volatile int idleTime; void setup() { lcd.begin(16, 2); lcd.cursor(); lcd.setCursor(0, 0); Timer1.initialize(); Timer1.attachInterrupt(timer_interrupt, 500); Serial.begin(19200); frameSq = 0; } void timer_interrupt(void) { static byte rSq; ti++; if(rSq == 0 && digitalRead(19) == 0) { rSq = 1; ti = 0; } if(rSq == 1 && ti == 5) { if(digitalRead(19) == 0) { rSq = 2; ti = 0; } else { rSq = 0; } } else if(rSq == 2 && ti == 10) { bitWrite(incomingByte, 0, digitalRead(19)); } else if(rSq == 2 && ti == 20) { bitWrite(incomingByte, 1, digitalRead(19)); } else if(rSq == 2 && ti == 30) { bitWrite(incomingByte, 2, digitalRead(19)); } else if(rSq == 2 && ti == 40) { bitWrite(incomingByte, 3, digitalRead(19)); } else if(rSq == 2 && ti == 50) { bitWrite(incomingByte, 4, digitalRead(19)); } else if(rSq == 2 && ti == 60) { bitWrite(incomingByte, 5, digitalRead(19)); } else if(rSq == 2 && ti == 70) { bitWrite(incomingByte, 6, digitalRead(19)); } else if(rSq == 2 && ti == 80) { bitWrite(incomingByte, 7, digitalRead(19)); } else if(rSq == 2 && ti == 90) { parityBit = digitalRead(19); byteEnd = true; } if(rSq == 2 && ti == 100) { rSq = 0; } if(digitalRead(19) == 0) { idleTime = 0; } else { idleTime++; } } //DISPLAYS CHARACTER void lcdOut() { int i; char ch = incomingByte; //ASCII CODE FILTER if(ch < 32 || ch > 126) { ch = ' '; } lcd.print(ch); c[16 * y + x] = ch; x++; if(x == 16 && y == 0) { x = 0; y = 1; } else if(x == 16 && y == 1) { for(i = 0; i < 16; i++) { c[i] = c[16 + i]; } for(i = 0; i < 16; i++) { c[16 + i] = '\0'; } lcd.clear(); lcd.noCursor(); for(i = 0; i < 16; i++) { lcd.print(c[i]); } lcd.cursor(); x = 0; y = 1; } lcd.setCursor(x, y); } //CLEAR BUFFER void bufClear() { int i; for(i = 0; i < 256; i++) { buff[i] = '\0'; } } void checkAndStore() { byte paritySum; byte LField2; boolean bit7 = incomingByte & B10000000; boolean bit6 = incomingByte & B01000000; boolean bit5 = incomingByte & B00100000; boolean bit4 = incomingByte & B00010000; boolean bit3 = incomingByte & B00001000; boolean bit2 = incomingByte & B00000100; boolean bit1 = incomingByte & B00000010; boolean bit0 = incomingByte & B00000001; Serial.print(bit7); Serial.print(bit6); Serial.print(bit5); Serial.print(bit4); Serial.print(bit3); Serial.print(bit2); Serial.print(bit1); Serial.print(bit0); Serial.print(' '); Serial.print(' '); Serial.print(parityBit); //Even Parity Check paritySum = 0; if(bit7){ paritySum++; } if(bit6){ paritySum++; } if(bit5){ paritySum++; } if(bit4){ paritySum++; } if(bit3){ paritySum++; } if(bit2){ paritySum++; } if(bit1){ paritySum++; } if(bit0){ paritySum++; } if(parityBit){ paritySum++; } if(paritySum % 2 == 0) { if(frameSq == 0 && headParityChk < 4) { headParityChk++; } else if(frameSq == 1) { bodyParityChk++; } } else { if(frameSq == 0) { headParityChk = 0; } } Serial.print(' '); Serial.print(' '); if(paritySum % 2 == 0) { Serial.print("OK"); } else { Serial.print("ER"); } Serial.print(' '); Serial.print(' '); if(incomingByte < 16) { Serial.print(0, HEX); } Serial.print(incomingByte, HEX); char ch = incomingByte; //ASCII CODE FILTER if(ch < 32 || ch > 126) { ch = ' '; } Serial.print(' '); Serial.print(' '); Serial.println(ch); if(frameSq == 0) { buff[addr] = incomingByte; //SEEK HEADER if(buff[addr - 3] == 0x68 && buff[addr] == 0x68) { LField1 = buff[addr - 2]; LField2 = buff[addr - 1]; if(LField1 == LField2) { if(headParityChk == 4) { bufClear(); addr = 0; idleTime = 0; bodyParityChk = 0; lostData = false; frameSq = 1; } else { addr++; } } else { addr++; } } else { addr++; } } else if(frameSq == 1) //BODY { buff[addr] = incomingByte; if(addr == LField1 + 1) { frameSq = 2; } else { addr++; } } } void parsePk() { int i; byte CField; byte AField; byte CIField; byte checkSum; byte endMarker; int year; byte month; byte day; byte dOWeek; byte hour; boolean summer; byte minute; byte second; CField = buff[0x00]; AField = buff[0x01]; CIField = buff[0x02]; if(lostData) { checkSum = buff[addr - 2]; endMarker = buff[addr - 1]; realLength = addr - 2; } else { checkSum = buff[LField1]; endMarker = buff[LField1 + 1]; realLength = LField1; } Serial.println(); //-- -------------------------------------------- --// if(AField == 0x00 && CIField == 0x00) { Serial.println("TIME"); //PARSE TIME year = buff[9] & B01111111; year = year + 2000; month = buff[8] & B00001111; day = buff[7] & B00011111; dOWeek = buff[7] & B11100000; dOWeek = dOWeek >> 5; hour = buff[6] & B00011111; summer = buff[6] & B10000000; minute = buff[5] & B00111111; second = buff[4] & B11111100; second = second >> 2; Serial.print(year); Serial.print(','); if(month < 10) { Serial.print('0'); } Serial.print(month); Serial.print(','); if(day < 10) { Serial.print('0'); } Serial.print(day); switch(dOWeek) { case 1: Serial.print(" Mon "); break; case 2: Serial.print(" Tue "); break; case 3: Serial.print(" Wed "); break; case 4: Serial.print(" Thu "); break; case 5: Serial.print(" Fri "); break; case 6: Serial.print(" Sat "); break; case 7: Serial.print(" Sun "); break; } if(hour < 10) { Serial.print('0'); } Serial.print(hour); Serial.print(':'); if(minute < 10) { Serial.print('0'); } Serial.print(minute); Serial.print(':'); if(second < 10) { Serial.print('0'); } Serial.print(second); if(summer) { Serial.println(" Summer Time"); } else { Serial.println(" Standard Time"); } } else if(AField == 0xFF && CIField == 0xFF) { Serial.println("BROADCAST"); } else { Serial.println("COMMAND"); } //-- -------------------------------------------- --// Serial.print("L Field: "); Serial.print(LField1); Serial.print('d'); Serial.print(" / Real L: "); Serial.print(realLength); Serial.print('d'); if(lostData) { Serial.print('*'); } Serial.println(); //-- -------------------------------------------- --// Serial.print("C Field: "); if(CField < 16) { Serial.print(0, HEX); } Serial.print(CField, HEX); byte telegramNumber = CField & B11110000; telegramNumber = telegramNumber >> 4; Serial.print(" / Telegram # "); Serial.println(telegramNumber); //-- -------------------------------------------- --// Serial.print("A Field: "); if(AField < 16) { Serial.print(0, HEX); } Serial.println(AField, HEX); //-- -------------------------------------------- --// Serial.print("CI Field: "); if(CIField < 16) { Serial.print(0, HEX); } Serial.println(CIField, HEX); //-- -------------------------------------------- --// Serial.print("Payload: "); for(i = 3; i < realLength; i++) { if(buff[i] < 16) { Serial.print(0, HEX); } Serial.print(buff[i], HEX); Serial.print(' '); } Serial.print("("); for(i = 3; i < realLength; i++) { //ASCII CODE FILTER if(char(buff[i]) < 32 || char(buff[i]) > 126) { Serial.print(' '); } else { Serial.print(char(buff[i])); } } Serial.println(')'); //-- -------------------------------------------- --// Serial.print("Check Sum: "); if(checkSum < 16) { Serial.print(0, HEX); } Serial.print(checkSum, HEX); Serial.print(' '); //CHECK SUM CALC uint8_t checkSumCalc; checkSumCalc += CField; checkSumCalc += AField; checkSumCalc += CIField; for(i = 3; i < realLength; i++) { checkSumCalc += buff[i]; } if(checkSumCalc < 16) { Serial.print(0, HEX); } Serial.print(checkSumCalc, HEX); Serial.print(' '); if(checkSumCalc == checkSum) { Serial.println("OK"); } else { Serial.println("ER"); } //-- -------------------------------------------- --// Serial.print("End Marker: "); if(endMarker < 16) { Serial.print(0, HEX); } Serial.print(endMarker, HEX); Serial.print(' '); if(endMarker == 0x16) { Serial.println("OK"); } else { Serial.println("ER"); } //-- -------------------------------------------- --// Serial.print("Parity: "); Serial.print(4 + bodyParityChk); Serial.print("/"); Serial.print(4 + realLength + 2); Serial.print(' '); if(bodyParityChk == realLength + 2) { Serial.println("OK"); } else { Serial.println("ER"); } //-- -------------------------------------------- --// Serial.println(); bufClear(); addr = 0; headParityChk = 0; dataBurstEnd = true; frameSq = 0; } void loop() { int i; if(byteEnd) { lcdOut(); checkAndStore(); dataBurstEnd = false; byteEnd = false; } if(frameSq == 0 && idleTime > 100) { if(dataBurstEnd == false) { Serial.println(); dataBurstEnd = true; } } else if(frameSq == 1 && idleTime > 100) { lostData = true; parsePk(); } else if(frameSq == 2) { parsePk(); } }