/*
 * Author: klaute -Kai Lauterbach - @kailauterbach - me@klaute.de
 * Date: 09/2016
 * License: GPLv3
 */

/*****************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <avr/wdt.h>

/*****************************************************************************/

void cc_init(void);
void cc_abort(void);
void cc_processData(uint8_t);
void cc_clearReadDataBuffer(void);

/*****************************************************************************/

void cc_setStartFreq(void);
void cc_setEndFreq(void);
void cc_setIntervall(void);
void cc_setDriveStrength(void);
void cc_startMeasurement(void);

/*****************************************************************************/

extern "C" {
  #include "globals.h"
}

/*****************************************************************************/

uint8_t cc_commands[] = { 
    CC_CMD_SET_START_FREQ,
    CC_CMD_SET_END_FREQ,
    CC_CMD_SET_INTERVALL,
    CC_CMD_SET_DRIVE_STRENGTH,
    CC_CMD_START_MEASUREMENT,
  };

void (*cc_cmd_functions[])() = {
    CC_CMD_SET_START_FREQ_FUNC,
    CC_CMD_SET_END_FREQ_FUNC,
    CC_CMD_SET_INTERVALL_FUNC,
    CC_CMD_SET_DRIVE_STRENGTH_FUNC,
    CC_CMD_START_MEASUREMENT_FUNC,
  };

uint8_t cc_cmd_data_to_read[] = {
    CC_CMD_SET_START_FREQ_DATA_TO_READ,
    CC_CMD_SET_END_FREQ_DATA_TO_READ,
    CC_CMD_SET_INTERVALL_DATA_TO_READ,
    CC_CMD_SET_DRIVE_STRENGTH_DATA_TO_READ,
    CC_CMD_START_MEASUREMENT_DATA_TO_READ,
  };

uint8_t cc_read_data[CC_READ_DATA_MAX];

/*****************************************************************************/

uint8_t cc_state = CC_STATE_READ_SOM1;

uint8_t cc_cmd_to_call = CC_CMD_NO_CMD;

uint8_t cc_cmd_received_correct = MSG_INCOMPLETE;

uint8_t cc_cmd_data_read_cnt = 0;

/*****************************************************************************/

void cc_setStartFreq()
{
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             MSG_TYPE_ANSWER_NOK,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
}

void cc_setEndFreq()
{
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             MSG_TYPE_ANSWER_NOK,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
}

void cc_setIntervall()
{
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             MSG_TYPE_ANSWER_NOK,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
}

void cc_setDriveStrength()
{
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             MSG_TYPE_ANSWER_NOK,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
}

void cc_startMeasurement()
{
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             123,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
}

/*****************************************************************************/

void cc_init()
{
  cc_state                = CC_STATE_READ_SOM1;
  cc_cmd_to_call          = CC_CMD_NO_CMD;
  cc_cmd_data_read_cnt    = 0;
  cc_cmd_received_correct = MSG_INCOMPLETE;
}

/*****************************************************************************/

void cc_abort()
{
  // send abort message, then init
  char* tmp = "     ";
  sprintf(tmp, "%c%c%c%c%c", MSG_SOM1, MSG_SOM2,
                             MSG_TYPE_ANSWER_NOK,
                             MSG_EOM1, MSG_EOM2);
  Serial.write(tmp);
  cc_init();
}

/*****************************************************************************/

void cc_processData(uint8_t c)
{
  uint8_t i = 0;

  switch (cc_state)
  {
    //*********************************//
    case CC_STATE_READ_SOM1:;
      if (c == MSG_SOM1)
        cc_state = CC_STATE_READ_SOM2;
      else
        cc_abort();
      break;

    //*********************************//
    case CC_STATE_READ_SOM2:;
      if (c == MSG_SOM2)
        cc_state = CC_STATE_READ_CMD;
      else
        cc_abort();
      break;

    //*********************************//
    case CC_STATE_READ_CMD:;
      for (i = 0; i < sizeof(cc_commands)/sizeof(uint8_t); i++)
      {
        if (cc_commands[i] == c)
        {
          if (cc_cmd_data_to_read[i] > 0)
            cc_state = CC_STATE_READ_DATA;
          else
            cc_state = CC_STATE_READ_EOM1;

          cc_cmd_to_call = i; // remember the index of command to call

          break; // break the loop
        }
      }
      break;

    //*********************************//
    case CC_STATE_READ_DATA:;
      // write the variable c to the input buffer
      cc_read_data[cc_cmd_data_read_cnt] = c;

      if (cc_cmd_data_read_cnt >= cc_cmd_data_to_read[cc_cmd_to_call]-1)
      {
        cc_state = CC_STATE_READ_EOM1;
      }

      cc_cmd_data_read_cnt++;

      break;

    //*********************************//
    case CC_STATE_READ_EOM1:;
      if (c == MSG_EOM1)
        cc_state = CC_STATE_READ_EOM2;
      else
        cc_abort();
      break;

    //*********************************//
    case CC_STATE_READ_EOM2:;
      if (c == MSG_EOM2)
      {
        cc_cmd_received_correct = MSG_COMPLETE;
      } else
        cc_abort();
      break;

    default:
      cc_abort();
  }

  //*********************************//
  if (cc_cmd_received_correct == MSG_COMPLETE)
  {
    // call the function using the received data
    (*cc_cmd_functions[cc_cmd_to_call])();
    // clear the read buffer
    cc_clearReadDataBuffer();
    cc_init();
  }
}

/*****************************************************************************/

void cc_clearReadDataBuffer()
{
  uint8_t i = 0;
  for (i = 0; i < CC_READ_DATA_MAX; i++)
  {
    cc_read_data[i] = 0x00;
  }
}

/*****************************************************************************/

