/*
  Name:    PhotometerPRO.ino
  Author:  Roman Schönfeld & Daniel Hausherr
*/

/***********************************************************************************************
  This work is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) License.

  You are free to:

  Share — copy and redistribute the material in any medium or format
  Adapt — remix, transform, and build upon the material
  for any purpose, even commercially.

  The licensor cannot revoke these freedoms as long as you follow the license terms.

  Under the following terms:

  Attribution — You must give appropriate credit, provide a link to the license, and indicate if
  changes were made. You may do so in any reasonable manner, but not in any way that suggests
  the licensor endorses you or your use.

  No additional restrictions — You may not apply legal terms or technological measures that
  legally restrict others from doing anything the license permits.

  Credits:
  Laboratory for Physics and Illumination Technologies,
  University of Applied Sciences Southern Westfalia
  Germany

  Make Light! Support by the BMBF in the development of this device is gratefully acknowledged
***************************************************************************************************/
#include "PhotometerPRO.h"
#include "PdResponse.h"
#include "Display.h"
#include "SauronPlus.h"
#include "Interface.h"

#define FIRMWARE_MAJOR 02
#define FIRMWARE_MINOR 00
#define DEFAULTBAUDRATE 115200


#define MODE_DEFAULT 0            // Defines Arduino Modes (Currently Not Used)
#define COMMANDLENGTH 15          // Defines The Number Of Bytes In A Single LabVIEW Command (This must match the packet size specifid in LabVIEW)

// Declare Variables
unsigned char currentCommand[COMMANDLENGTH];    // The Current Command For The Arduino To Process
unsigned int retVal;
int currentMode;
unsigned int freq;
unsigned long duration;
int i2cReadTimeouts = 0;
bool isLabVIEW_Mode = false;

volatile uint8_t count_for_ready_pin = 0;
volatile bool ready_pin_state_high = false;

void readyPinRising () {
  ready_pin_state_high = true;
}


// Called when data is available
void serialEvent(void) {
  if (Serial.available() >= (int)COMMANDLENGTH) {

    // New Command Ready, Process It
    // Build Command From SerialUSB Buffer

    for (int i = 0; i < COMMANDLENGTH; i++) {
      currentCommand[i] = Serial.read();
    }

    processCommand(currentCommand);
  }
}

void setup() {
  Serial.begin(DEFAULTBAUDRATE);
  i2cReadTimeouts = 0;
  Serial.flush();

  pinMode(_Y_MOVE, INPUT);
  pinMode(_X_MOVE, INPUT);
  pinMode(_READY_PIN, INPUT);

  pinMode(_SW_EN, OUTPUT);
  pinMode(_SW_A0, OUTPUT);
  pinMode(_SW_A1, OUTPUT);
  pinMode(_BL, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(_READY_PIN), readyPinRising, RISING);

  // Initialisiere Display
  init_tft();

  // Initialisiere I2C Bus
  init_device();

  // Initialisiere Menustruktur
  init_menu();

  set_brightness_tft(_TFT_BRIGHTNESS_HIGH);
}

void loop() {
  // *** Bestimmt die Position des Joysticks Y - Achse und führt die entsprechende Funktion aus **
  if ((uint16_t)analogRead(_Y_MOVE) < (MIN_THRESHOLD + HYSTERESIS)) {
    if ((uint16_t)analogRead(_Y_MOVE) < MIN_THRESHOLD) {
      navigation_menue((uint8_t)DOWN);
      delay(DELAY_LOOP_MIN);
    }
    else {
      navigation_menue((uint8_t)DOWN);
      delay(DELAY_LOOP_MAX);
    }
  }
  else if ((uint16_t)analogRead(_Y_MOVE) > (MAX_THRESHOLD - HYSTERESIS)) {
    if ((uint16_t)analogRead(_Y_MOVE) > MAX_THRESHOLD) {
      navigation_menue((uint8_t)UP);
      delay(DELAY_LOOP_MIN);
    }
    else {
      navigation_menue((uint8_t)UP);
      delay(DELAY_LOOP_MAX);
    }
  }

  // *** Bestimmt die Position des Joysticks X - Achse und führt die entsprechende Funktion aus **
  else {
    if ((uint16_t)analogRead(_X_MOVE) < (MIN_THRESHOLD + HYSTERESIS)) {
      navigation_menue((uint8_t)RIGHT);
      delay(DELAY_LOOP_MAX);
    }
    else if ((uint16_t)analogRead(_X_MOVE) > (MAX_THRESHOLD - HYSTERESIS)) {
      navigation_menue((uint8_t)LEFT);
      if (isLabVIEW_Mode)
      {
        asm volatile ("  jmp 0");
      }
      delay(DELAY_LOOP_MAX);
    }
  }
}

// Processes a given command
void processCommand(unsigned char command[]) {
  static float oldval = 1.234f;
  if (command[0] == 0xFF && checksum_Compute(command) == command[COMMANDLENGTH - 1])
  {
    switch (command[1]) {

      /***************************************************************
      ** LIFA Maintenance Commands
      ***************************************************************/
      case 0x00:     // Sync Packet
        Serial.print("sync");
        Serial.flush();
        if (!isLabVIEW_Mode)
          Enter_LabVIEW_Mode();
        isLabVIEW_Mode = true;
        break;
      case 0x01:    // Flush SerialUSB Buffer
        Serial.flush();
        break;

      /***************************************************************
      **  Powermeter
      ***************************************************************/

      case 0xF0:

        current_wavelenght = command[4];
        
        double current_to_power;
        switch ((detectors)command[2])
        {
          case OSD_50:
            current_detector = (detectors)OSD_50;
            get_osd50_characteristic(&current_to_power);
            break;
          case BPX_61:
            current_detector = (detectors)BPX_61;
            get_bpx61_characteristic(&current_to_power);
            break;
          default:
            break;
        }
        
        //int num_of_averages = command[5]; // ??? Wo Roman...
        current_time = command[3];
   
        double value;
        
        if (get_value_in_current(&value))
        {
         value /= current_to_power;
        }
        else
        {
          value = current_to_power;
        }

        Serial.write(((byte*)&value), 4);
        Serial.flush();
        break;
      /***************************************************************
      ** Unknown Packet
      ***************************************************************/
      default:      // Default Case
        Serial.flush();
        break;
    }
  }
  else {
    // Checksum Failed, Flush SerialUSB Buffer
    Serial.flush();
  }
}

// Compute Packet Checksum
unsigned char checksum_Compute(unsigned char command[]) {
  unsigned char checksum = 0;
  for (int i = 0; i < (COMMANDLENGTH - 1); i++) {
    checksum += command[i];
  }
  return checksum;
}
