#include <SoftwareSerial.h>

/* APC220 reprogramming
  ng  April 2017

  AUTO VERSION WHICH USE hw serial and pin 8 for set and if seelcted pin7 for enable radio

  (C)CJens Dalsgaard Nielsen (AAU)
  no warranty whatsoever
  you are on your own
  find m on github.com/jdn-aau/div
* * SEE readme.ino for more info (look up in tabs)

*** IMPORTANT ***

   NB NB NB NB NB
   orange radioes V4  i 435000 freq range (431-455)
   green radioer i 475000 freq range  (455-485 ca)
   Its up to you to comply to ITU and local radio frequency regulations !


  IMPORTANT
    I many cases 5V pulled from pin 13 cant deliver enough power for the radio
    It is advised to connect 5V pin on radio to 5V on arduino.
*/



void (*resetF)(void) = 0x00;

const int vrs = 123;

#define BUFL 50
#define RADIOARGLGT (2  +1+6 +1+1 +1+1 +1+1 +1+1 +1+1)
//                   WR  MHZ   3    9    3    0    !  ( one space between each - and not two !!

#define RDLGT 4
#define WRLGT 19
#define SERTIMEOUT 20000

char rcvBuf[BUFL+5]; // for receving from radio

// enable pin turn radio on(HIGH). off(LOW)

// setpin radio on(high) off(low)
#define SETPIN 8
#define ENPIN 12
// D13 supply radio with power
#define FIVEV 13

// by software serial
#define RXPIN 10
#define TXPIN 11

#define PARM_LGT 10
#define CMD_BUF_LGT 50

// vars

char var1[PARM_LGT], var2[PARM_LGT], var3[PARM_LGT], var4[PARM_LGT], var5[PARM_LGT], var6[PARM_LGT];

SoftwareSerial apc220(RXPIN, TXPIN); // Crt softserial port and bind tx/rx to appropriate PINS

void emptySerial()
{
  int c;
  while (0 < Serial.available())
    c = Serial.read();
}

void emptyRadio()
{
  int c;
  while (0 < apc220.available() ) {
    c = apc220.read();
  }
}

int readSerialLine(char buff[], int maxL)
{
  int n;
  /*
     read a line until CR or LF
     If buffer is to short chars are just dumped
  */
  Serial.setTimeout(SERTIMEOUT);
  n = Serial.readBytesUntil('.', buff, RADIOARGLGT);

  delay(500);
  emptySerial();

  if (n != RADIOARGLGT) {
    return 0;  // bad
  }
  return 1;
}

/**----------------------------------------------------------------------------------*/
char st[200];

void enterSetMode() {
  emptyRadio();
  delay(500);
  digitalWrite(ENPIN, HIGH);
  digitalWrite(SETPIN, HIGH);
  delay(100);
  digitalWrite(SETPIN, LOW); // setmode in 1 msec
  delay(5);

}

void leaveSetMode() {
  digitalWrite(SETPIN, HIGH);
  delay(500);
}


int inRange(int val, int lw, int hg) {
  if ( (lw <= val) && (val <= hg) )
    return 1;
  else
    return 0;
}
/**----------------------------------------------------------------------------------*/
void set_para(char hz[], int rfRate, int pwr, int uartRate, int par)
{
  // sanity chk
  if (strlen(hz) != 6) {
    Serial.println("Freq parm not 6 digits... - legal is 418000 - 455000");
    return;
  }
  if (! inRange(rfRate, 1, 4 )) {
    Serial.println("RF parm bad: legal values is 1/2/3/4");
    return;
  }
  if (! inRange(pwr, 0, 9)) {
    Serial.println("Power parm bad: legal values is 0..9(9: max power)");
    return;
  }
  if (! inRange(uartRate, 0, 6) ) {
    Serial.println("Uart baudrate bad: legal values is 0..6");
    return;
  }
  if ( ! inRange(par, 0, 2) ) {
    Serial.println("Parity parm bad: legal values is 0/1/2");
    return;
  }

  Serial.println("programming now");


  enterSetMode();
  delay(10);

  apc220.print("WR");
  apc220.print(" ");

  apc220.print(hz);
  apc220.print(" ");

  apc220.print(rfRate);
  apc220.print(" ");

  apc220.print(pwr);
  apc220.print(" ");

  apc220.print(uartRate);
  apc220.print(" ");

  apc220.print(par);

  apc220.println("");



  // read feedback from radio

  delay(10);

  while (apc220.available()) {
    Serial.print((char)(apc220.read()));
  }

  leaveSetMode();
}


void get_para(char s[])
{
  int i;

  s[0] = 0x00;
  s[3] = 0x0a; // just a guard

  enterSetMode();

  apc220.println("RD");

  delay(205);

  i = 0;
  while (apc220.available()) {
    s[i] = apc220.read();
    i++;
    delay(1);
  }

  // check of endofdata (rudimentary)
  for (i = 0; i < BUFL; i++) {
    if ((s[i] != 0x0a) || (s[i] != 0x0d)) {
      s[i] = 0x00;
      goto ende;
    }
  }

  s[0] = 0x00; //termination of string bad bad ende not found

ende:
  leaveSetMode();
}

int rdRadio()
{
  get_para(rcvBuf);

  if ( ! rcvBuf[0] )  { // a zero on first place so nothing received
    return 0;
  }
  else {
    return 1;
  }
}

/**----------------------------------------------------------------------------------*/
void setup() {
  int jj;

  delay(1000);

  apc220.begin(9600);

  Serial.begin(9600);
  while (!Serial);

  dmpProgID(); // version of program

  return; // TEST

  Serial.println(F("Test starts for presence on apc220 radios in 1 second"));

  get_para(rcvBuf);

  if ( ! rcvBuf[0] )  { // a zero on first place so nothing received
    Serial.println( F("no radio ? ") );
  }
  else {
    Serial.println(F("Just read from radio ..."));
    Serial.println(rcvBuf);
    delay(1000);
  }

}

int isRdValid(char b[]) {
  if (b[0] != 'R' && b[1] != 'D') {
    b[2] = 0x00;  // rdy to tx
    return 1; // ok
  }

  if (b[0] != 'W' || b[1] != 'R')
    return 0;

  // from here it is a write command

  for (int i = 3 ; i < 9; i++) {
    if (! inRange(b[i], '0', '9')) {
      return 0;
    }
  }

  if (! inRange(b[10], '1', '4'))
    return 0;
  if (! inRange(b[12], '0', '9'))
    return 0;
  if (! inRange(b[14], '0', '6'))
    return 0;
  if (! inRange(b[16], '0', '2'))
    return 0;

  b[17] = 0x00;  // rdy to tx
  return 1; // ok
}

/**----------------------------------------------------------------------------------*/
void loop()
{
  int l, i = 0; char c;
  char buff[CMD_BUF_LGT];

  buff[0] = c = 0;

  menu();

  emptySerial();
  emptyRadio();


  // commands
  // 1) RD !
  // 2) WR xxxxxx x x x x !

  l = readSerialLine(buff, RADIOARGLGT);
  buff[l] = 0x00;
  if (l != RDLGT || l !=  WRLGT) {
    Serial.print("\nbad rd/wr tlg. we did read from you <");
    Serial.print(buff);
    Serial.println(">");
    delay(1000);
    return;
  }

  switch (l) {
    case RDLGT:
      // send rd
      break;
    case WRLGT:
      // send wr
      break;
    default: Serial.println("err in sw");
  }
}


