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