/****************************************************************
JI3BNB AX.25 HF PACKET (300baud) DECODE ENGINE <CORE>
TESTED ON ARDUINO MEGA 2560
2026.03.01
v1.5 4-MODE-OUTPUT
v1.51 5-MODE-OUTPUT
/****************************************************************/
/*
* Digital input 19
* (external demodulator required)
*/
const int mode = 3;
/*
* Serial output 115200 baud
* mode 0: BIN
* mode 1: HEX
* mode 2: ASCII
* mode 3: Combined
* mode 4: Sync Monitor
*/
#include <TimerOne.h>
volatile int pArray[11];
volatile int syncPoint;
volatile bool state_1;
volatile bool state_2;
volatile bool state_3;
volatile bool state_4;
void setup()
{
Timer1.initialize();
Timer1.attachInterrupt(timer_interrupt, 333); //300Baud
Serial.begin(115200);
}
void timer_interrupt(void)
{
static int syncClock;
static bool smplReady;
static int skips;
static long ones;
static bool fiveOnes;
static byte count8;
static byte buf8;
static int addr;
static int chars;
//save sync points
state_2 = digitalRead(19);
if(state_1 == 0 && state_2 == 1) //rising edge
{
for(int s = 0; s < 11; s++)
{
pArray[s] = pArray[s + 1];
}
pArray[10] = syncClock;
}
//sample and get byte
if(syncClock - syncPoint >= -1 && syncClock - syncPoint <= 1)
{
smplReady = true;
}
else if(syncClock - syncPoint == -9 || syncClock - syncPoint == 9)
{
smplReady = true;
}
else if(smplReady == true)
{
skips++;
if(skips == 5) //go sample now!
{
state_4 = digitalRead(19);
if(state_3 != state_4) //(NRZI) inverted = 0
{
if(fiveOnes == true)
{
//zero insertion
//do nothing
}
else
{
buf8 = buf8 >> 1;
bitWrite(buf8, 7, 0);
if(mode == 0 || mode == 3)
{
Serial.print('0');
}
count8++;
}
fiveOnes = false;
ones = 0;
}
else //(NRZI) no change = 1
{
buf8 = buf8 >> 1;
bitWrite(buf8, 7, 1);
if(mode == 0 || mode == 3)
{
Serial.print('1');
}
ones++;
if(ones == 5)
{
fiveOnes = true;
}
else
{
fiveOnes = false;
}
count8++;
if(ones == 6) //flag
{
count8 = 7; //reset position
}
}
if(count8 == 8) //get BYTE now!
{
/* ----- */
if(mode == 1 || mode == 3) //hex
{
if(mode == 3)
{
Serial.print(" ");
}
if(buf8 < 16)
{
Serial.print('0');
}
Serial.print(buf8, HEX);
}
/* ----- */
if(buf8 != 0x7E && addr < 15) //address field
{
buf8 = buf8 >> 1;
}
/* ----- */
if(mode == 2 || mode == 3) //ascii
{
if(mode == 3)
{
Serial.print(" ");
}
if(buf8 < 32 || buf8 > 126) //ascii char filter
{
Serial.print(' ');
}
else
{
Serial.print((char)buf8);
}
}
/* ----- */
if(mode == 2) //LF every 80 chars
{
chars++;
if(chars == 80)
{
Serial.println();
chars = 0;
}
}
else if(mode != 4)
{
Serial.println();
}
/* ----- */
count8 = 0;
addr++;
if(buf8 == 0x7E) //after flag
{
addr = 1;
}
}
smplReady = false;
skips = 0;
}
}
syncClock++;
if(syncClock > 9)
{
syncClock = 0;
}
state_1 = state_2;
state_3 = state_4;
}
void loop()
{
volatile int tMax;
int sumArray[] = {0,0,0,0,0,0,0,0,0,0};
//find MOST SEEN point
for(int p = 0; p < 11; p++)
{
if(mode == 4)
{
Serial.print(pArray[p]);
Serial.print(' ');
}
for(int s = 0; s < 10; s++)
{
if(pArray[p] == s)
{
sumArray[s] += 1;
}
}
}
if(mode == 4)
{
Serial.print(" ");
for(int s = 0; s < 10; s++)
{
Serial.print(sumArray[s]);
Serial.print(' ');
}
}
tMax = -1;
syncPoint = -1;
for(int s = 0; s < 10; s++)
{
if(sumArray[s] > tMax)
{
tMax = sumArray[s];
syncPoint = s;
}
}
if(mode == 4)
{
Serial.print(" ");
Serial.print("tMax:");
Serial.print(tMax);
Serial.print(' ');
Serial.print("syncPoint:");
Serial.print(syncPoint);
Serial.print(' ');
Serial.println();
}
delay(1);
}