// EFR Broadcast Packet Sender
// ARDUINO MEGA 2560
// 0.5 AD9850 DDS対応
// 0.6 telegramNumber入れた

#define  CLK   6
#define  FQ    7
#define  DATA  8
#define  RST   9
const long oFreq = 21390000;

#include <LiquidCrystal.h>
LiquidCrystal lcd(34,35,36,37,38,39,40);

#include <TimerOne.h>
#define MARK  392   //500000/1275(Hz)
#define SPACE 346   //500000/1445(Hz)

#include <FlexiTimer2.h>

//packet
byte  startMk   = 0x68;            //start marker
byte  LField;                      //length
byte  CField;                      //control, function
byte  AField    = 0xFF;            //a1, address
byte  CIField   = 0xFF;            //a2, control information
char  message[] = "JI3BNB TEST";   //max 16 bytes
byte  msgLen;
byte  checkSum;
byte  stopMk    = 0x16;            //stop marker

//controls
int     sSq;
boolean snd;
int     ti;
byte    telegramNumber; //0-15

//data
char ascii;

//dds
void shortPulse (char PIN)
{
        digitalWrite(PIN, 1);
        digitalWrite(PIN, 0);
}

void setFreq(double freq)
{
        //--calculate
        int32_t d_Phase = freq * pow(2, 32) / 125000000;
        //--send first 32bit
        for (int i=0; i<32; i++, d_Phase>>=1)
        {
                if(d_Phase & 1 == 1)
                {
                        digitalWrite(DATA, HIGH); //--data
                }
                else
                {
                        digitalWrite(DATA, LOW); //--data
                }
                shortPulse(CLK);
        }
        //--send rest 8bit
        digitalWrite(DATA, LOW); //--data
        for (int i=0; i<8; i++)
        {
                shortPulse(CLK);
        }
        //--finish
        shortPulse(FQ);
}

void setup()
{
  //DDS
  pinMode(CLK, OUTPUT);
  pinMode(FQ, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RST, OUTPUT);
  //--dds reset
  shortPulse(RST);
  shortPulse(CLK);
  //--change mode
  shortPulse(FQ);
  
  //pins
  pinMode(12, OUTPUT);  //AFSK AUDIO
  pinMode(13, OUTPUT);  //TTL
  
  //LCD
  lcd.begin(16, 2);

  //timers
  Timer1.initialize();
  FlexiTimer2::set(1, timer2_interrupt); //1:200Bd 4:50Bd
  FlexiTimer2::start();

  //calculate message length
  int n;
  while(message[n] != '\0')
  {
    n++;
  }
  msgLen = n;
  LField = msgLen + 3;
}

//AFSK TONE GENERATOR
void timer1_interrupt(void)
{
  static boolean toggle;
  
  toggle = toggle ^ 1;
  digitalWrite(12, toggle);
}

void setOutput(bool state)
{
  if(state == true)
  {
    Timer1.setPeriod(MARK);
    digitalWrite(13, 1);
    setFreq(oFreq);
  }
  else
  {
    Timer1.setPeriod(SPACE);
    digitalWrite(13, 0);
    setFreq(oFreq + 340);
  }
}

//8E1 ascii GENERATOR
void timer2_interrupt(void)
{
  byte paritySum;
  static bool bit1;
  static bool bit2;
  static bool bit3;
  static bool bit4;
  static bool bit5;
  static bool bit6;
  static bool bit7;
  static bool bit8;
  static bool parity;
  
  if(snd == 1)
  {
    switch(ti)
    {
      case 0:
        setOutput(false);
        bit1 = ascii & B00000001; paritySum += bit1;
        bit2 = ascii & B00000010; paritySum += bit2;
        bit3 = ascii & B00000100; paritySum += bit3;
        bit4 = ascii & B00001000; paritySum += bit4;
        bit5 = ascii & B00010000; paritySum += bit5;
        bit6 = ascii & B00100000; paritySum += bit6;
        bit7 = ascii & B01000000; paritySum += bit7;
        bit8 = ascii & B10000000; paritySum += bit8;
        if(paritySum % 2 == 0)
        {
          parity = false;
        }
        else
        {
          parity = true;
        }
        break;
      case 5:
        setOutput(bit1);
        break;
      case 10:
        setOutput(bit2);
        break;
      case 15:
        setOutput(bit3);
        break;
      case 20:
        setOutput(bit4);
        break;
      case 25:
        setOutput(bit5);
        break;
      case 30:
        setOutput(bit6);
        break;
      case 35:
        setOutput(bit7);
        break;
      case 40:
        setOutput(bit8);
        break;
      case 45:
        setOutput(parity);
        break;
      case 50:
        setOutput(true);
        break;
      case 55:
        snd = 0;
        break;
    }
    ti++;
  }
}

void loop()
{
  static int addr;
  
  if(sSq == 0) //--- pretone ---
  {
    checkSum = 0;
    lcd.clear();
    Timer1.attachInterrupt(timer1_interrupt, MARK); setFreq(oFreq);
    delay(400);
    addr = 0; sSq = 1;
  }
  if(sSq == 1) //--- packet ---
  {
    if(snd == 0)
    {
      if(addr == 0)
      {
        ascii = startMk;
      }
      else if(addr == 1)
      {
        ascii = LField;
      }
      else if(addr == 2)
      {
        ascii = LField;
      }
      else if(addr == 3)
      {
        ascii = startMk;
      }
      else if(addr == 4)
      {
        CField = telegramNumber;
        CField = CField << 4;
        bitWrite(CField, 3, 0);
        bitWrite(CField, 2, 1);
        bitWrite(CField, 1, 1);
        bitWrite(CField, 0, 1);
        ascii = CField;
        checkSum += CField;
      }
      else if(addr == 5)
      {
        ascii = AField;
        checkSum += AField;
      }
      else if(addr == 6)
      {
        ascii = CIField;
        checkSum += CIField;
      }
      else if(addr >= 6 + 1 && addr <= 6 + msgLen)
      {
        ascii = message[addr - 7];
        checkSum += ascii;
        lcd.print(ascii);
      }
      else if(addr == 6 + msgLen + 1)
      {
        ascii = checkSum;
      }
      else if(addr == 6 + msgLen + 2)
      {
        ascii = stopMk;
      }
      else if(addr > 6 + msgLen + 2)
      {
        telegramNumber++;
        if(telegramNumber ==16)
        {
          telegramNumber = 0;
        }
        sSq = 2;
        goto intv;
      }
      ti = 0; snd = 1;
      addr++;
    }
  }
  intv: //-- interval --
  if(sSq == 2)
  {
    Timer1.detachInterrupt(); setFreq(5);
    delay(3000);
    sSq = 0;
  }
  delay(5);
}