/****************************************************************
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();
}
}