/*
 * relay.c
 *
 *  Created on: Jul 16, 2010
 *      Author: zumbruch
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "api.h"
#include "api_define.h"
#include "api_global.h"
#include "adc.h"
#include "one_wire_temperature.h"

#include "relay.h"

static const char relayThresholdCommandKeyword00[] PROGMEM = "current_state";
static const char relayThresholdCommandKeyword01[] PROGMEM = "current_value";
static const char relayThresholdCommandKeyword02[] PROGMEM = "thr_high";
static const char relayThresholdCommandKeyword03[] PROGMEM = "thr_low";
static const char relayThresholdCommandKeyword04[] PROGMEM = "enable";
static const char relayThresholdCommandKeyword05[] PROGMEM = "input_channel";
static const char relayThresholdCommandKeyword06[] PROGMEM = "output_pin";
static const char relayThresholdCommandKeyword07[] PROGMEM = "led_pin";
static const char relayThresholdCommandKeyword08[] PROGMEM = "report_state_enable";
static const char relayThresholdCommandKeyword09[] PROGMEM = "relay";
static const char relayThresholdCommandKeyword10[] PROGMEM = "thresholds";
static const char relayThresholdCommandKeyword11[] PROGMEM = "status";
static const char relayThresholdCommandKeyword12[] PROGMEM = "outOfBounds_transit_lock";
static const char relayThresholdCommandKeyword13[] PROGMEM = "in_bounds_polarity";
static const char relayThresholdCommandKeyword14[] PROGMEM = "out_of_bounds_polarity";
static const char relayThresholdCommandKeyword15[] PROGMEM = "invert_polarity_logic";
static const char relayThresholdCommandKeyword16[] PROGMEM = "extern_inBounds_polarity";
static const char relayThresholdCommandKeyword17[] PROGMEM = "extern_inBounds_pin_pos";
static const char relayThresholdCommandKeyword18[] PROGMEM = "extern_inBounds_port";
static const char relayThresholdCommandKeyword19[] PROGMEM = "polarity";
static const char relayThresholdCommandKeyword20[] PROGMEM = "polarity_reinit";

const char* relayThresholdCommandKeywords[] PROGMEM = {
         relayThresholdCommandKeyword00,
         relayThresholdCommandKeyword01,
         relayThresholdCommandKeyword02,
         relayThresholdCommandKeyword03,
         relayThresholdCommandKeyword04,
         relayThresholdCommandKeyword05,
         relayThresholdCommandKeyword06,
         relayThresholdCommandKeyword07,
         relayThresholdCommandKeyword08,
         relayThresholdCommandKeyword09,
         relayThresholdCommandKeyword10,
         relayThresholdCommandKeyword11,
         relayThresholdCommandKeyword12,
         relayThresholdCommandKeyword13,
         relayThresholdCommandKeyword14,
         relayThresholdCommandKeyword15,
         relayThresholdCommandKeyword16,
         relayThresholdCommandKeyword17,
         relayThresholdCommandKeyword18,
         relayThresholdCommandKeyword19,
         relayThresholdCommandKeyword20
};

static const char relayThresholdStateString00[] PROGMEM = "IDLE";
static const char relayThresholdStateString01[] PROGMEM = "BELOW_LOW_THRESHOLD";
static const char relayThresholdStateString02[] PROGMEM = "INBETWEEN";
static const char relayThresholdStateString03[] PROGMEM = "ABOVE_HIGH_THRESHOLD";
static const char relayThresholdStateString04[] PROGMEM = "UNDEFINED";

const char* relayThresholdStateStrings[] PROGMEM = {
         relayThresholdStateString00,
         relayThresholdStateString01,
         relayThresholdStateString02,
         relayThresholdStateString03,
         relayThresholdStateString04
};

void relayThreshold(struct uartStruct *ptr_uartStruct)
{
   uint8_t index = 0;

   switch(ptr_uartStruct->number_of_arguments/* arguments of argument */)
   {
      case 0:
         /* show all */
         for (index = 0; index < relayThresholdCommandKeyNumber_MAXIMUM_NUMBER; index ++)
         {
            ptr_uartStruct->number_of_arguments = 1;
            relayThresholdMiscSubCommands(ptr_uartStruct, index);
            ptr_uartStruct->number_of_arguments = 0;
         }
         break;
      default: /* else */
         relayThresholdMiscSubCommands(ptr_uartStruct, -1);
         break;
   }
}

void relayThresholdMiscSubCommands( struct uartStruct *ptr_uartStruct, int16_t index )
{
   uint32_t status = 0;
   uint32_t value = 0;


   if ( index < 0 )
   {
      index = 0;
      // find matching command keyword
      while ( index < relayThresholdCommandKeyNumber_MAXIMUM_NUMBER )
      {
         if ( 0 == strncmp_P(setParameter[1], (const char*) ( pgm_read_word( &(relayThresholdCommandKeywords[index])) ), MAX_LENGTH_PARAMETER) )
         {
            break;
         }
         index++;
      }
   }

   /* TODO: relayThresholdMiscSubCommandsChooseFunction(ptr_uartStruct, index)*/
   switch ( ptr_uartStruct->number_of_arguments - 1 /* arguments of argument */)
   {
      case 0:
         /* printout status*/

         /* generate message */
         createExtendedSubCommandReceiveResponseHeader(ptr_uartStruct, commandKeyNumber_RLTH, index, relayThresholdCommandKeywords);
         switch ( index )
         {
            case relayThresholdCommandKeyNumber_CURRENT_VALUE:
               value = relayThresholdsGetCurrentValue();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s0x%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_CURRENT_STATE:
               value = relayThresholdsGetCurrentState();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%i %s"), uart_message_string, value);
               strncat_P(uart_message_string, (const char*) ( pgm_read_word( &(relayThresholdStateStrings[value])) ), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_THR_HIGH:
               value = relayThresholdsGetHighThreshold();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s0x%x"), uart_message_string, value);
               strncat_P(uart_message_string, ( FALSE != relayThresholds_valid[relayThreshold_HIGH] ) ? PSTR(" VALID") : PSTR(" INVALID"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_THR_LOW:
               value = relayThresholdsGetLowThreshold();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s0x%x"), uart_message_string, value);
               strncat_P(uart_message_string, ( FALSE != relayThresholds_valid[relayThreshold_LOW] ) ? PSTR(" VALID") : PSTR(" INVALID"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_ENABLE:
               value = relayThresholdsGetEnableFlag();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_REPORT_STATE_ENABLE:
               value = relayThresholdsGetReportStateEnableFlag();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_INPUT_CHANNEL:
               value = relayThresholdsGetInputChannel();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_OUTPUT_PIN:
               value = relayThresholdsGetOutputPin();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_LED_PIN:
               value = relayThresholdsGetLedPin();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_RELAY_VALUE:
               value = relayThresholdsGetRelayValue();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_OUT_OF_BOUNDS_TRANSIT_LOCK:
               value = relayThresholdsGetOutOfBoundsTransitLockFlag();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_IN_BOUNDS_POLARITY:
               value = relayThresholdsGetInBoundsPolarity();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_OUT_OF_BOUNDS_POLARITY:
               value = relayThresholdsGetOutOfBoundsPolarity();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_INVERT_POLARITY_LOGIC:
               value = relayThresholdsGetInvertPolarityFlag();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_EXTERNAL_IN_BOUNDS_POLARITY:
               value = relayThresholdsGetExternalPolarity();
               strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               break;
            case relayThresholdCommandKeyNumber_EXTERNAL_IN_BOUNDS_PIN_POS:
               value = relayThresholdsGetExternalPolarityPinPos();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_EXTERNAL_IN_BOUNDS_PORT:
               value = relayThresholdsGetExternalPolarityPort();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%x"), uart_message_string, value);
               break;
            case relayThresholdCommandKeyNumber_STATUS:
               {
                  value = relayThresholdsGetCurrentState();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s%i %s"), uart_message_string, value);
                  strncat_P(uart_message_string, (const char*) ( pgm_read_word( &(relayThresholdStateStrings[value])) ), BUFFER_SIZE - 1);
                  value = relayThresholdsGetCurrentValue();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s val:0x%x"), uart_message_string, value);
                  value = relayThresholdsGetLowThreshold();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s low:0x%x"), uart_message_string, value);
                  value = relayThresholdsGetHighThreshold();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s high:0x%x"), uart_message_string, value);
                  value = relayThresholdsGetRelayValue();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s relay:%x"), uart_message_string, value);
                  value = relayThresholdsGetInputChannel();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s in:%x"), uart_message_string, value);
                  value = relayThresholdsGetOutputPin();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s out:%x"), uart_message_string, value);
                  value = relayThresholdsGetLedPin();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s led:%x"), uart_message_string, value);
                  value = relayThresholdsGetEnableFlag();
                  strncat_P(uart_message_string, PSTR(" enable:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
                  value = relayThresholdsGetOutOfBoundsTransitLockFlag();
                  strncat_P(uart_message_string, PSTR(" 0t_lock:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
               }
               break;
            case relayThresholdCommandKeyNumber_POLARITY:
            {
                  value = relayThresholdsGetInBoundsPolarity();
                  strncat_P(uart_message_string, PSTR("inBounds:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
                  value = relayThresholdsGetOutOfBoundsPolarity();
                  strncat_P(uart_message_string, PSTR(" OfBounds:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
                  value = relayThresholdsGetInvertPolarityFlag();
                  strncat_P(uart_message_string, PSTR(" invert:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
                  value = relayThresholdsGetExternalPolarity();
                  strncat_P(uart_message_string, PSTR(" ext:"), BUFFER_SIZE - 1);
                  strncat_P(uart_message_string, ( FALSE != value ) ? PSTR("TRUE") : PSTR("FALSE"), BUFFER_SIZE - 1);
                  value = relayThresholdsGetExternalPolarityPinPos();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s ext_pos:%x"), uart_message_string, value);
                  value = relayThresholdsGetExternalPolarityPort();
                  snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s ext_port:%x"), uart_message_string, value);
                  break;
               }
            break;
            case relayThresholdCommandKeyNumber_POLARITY_REINIT:
               relayThresholdInBoundPolarityInit();
               break;
            case relayThresholdCommandKeyNumber_THRESHOLDS:
            {
               value = relayThresholdsGetLowThreshold();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%slow:0x%x"), uart_message_string, value);
               value = relayThresholdsGetHighThreshold();
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s high:0x%x"), uart_message_string, value);
               value = relayThresholdsGetRelayValue();
               break;
            }
            default:
               clearString(uart_message_string, BUFFER_SIZE);
               CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
               return;
               break;
         }

         /*send the data*/
         UART0_Send_Message_String(uart_message_string, BUFFER_SIZE - 1);
         /*clear strings*/
         clearString(uart_message_string, BUFFER_SIZE);
         break;
      case 1:
         /* set status*/

         /* T,F,t,f : T(RUE)/F(ALSE) */
         if ( 0 == strcmp_P(setParameter[2], PSTR("TRUE")) || 0 == strcmp_P(setParameter[2], PSTR("true")) )
         {
            value = TRUE;
         }
         else if ( 0 == strcmp_P(setParameter[2], PSTR("FALSE")) || 0 == strcmp_P(setParameter[2], PSTR("false")) )
         {
            value = FALSE;
         }
         /* or expecting numeric hex value, beware of the order since _F_ALSE has numeric hex length 1! */
         else if ( 0 < getNumericLength(setParameter[2], MAX_LENGTH_PARAMETER) )
         {
            value = strtoul(setParameter[2], &ptr_setParameter[2], 16);
         }
         else
         {
            CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
            return;
         }

         switch ( index )
         {
            case relayThresholdCommandKeyNumber_THR_HIGH:
               status = relayThresholdsSetHighThreshold(value & 0xFFFF);
               break;
            case relayThresholdCommandKeyNumber_THR_LOW:
               status = relayThresholdsSetLowThreshold(value & 0xFFFF);
               break;
            case relayThresholdCommandKeyNumber_ENABLE:
               status = relayThresholdsSetEnableFlag(0 != value);
               break;
            case relayThresholdCommandKeyNumber_OUT_OF_BOUNDS_TRANSIT_LOCK:
               status = relayThresholdsSetOutOfBoundsTransitLockFlag(0 != value);
               break;
            case relayThresholdCommandKeyNumber_INPUT_CHANNEL:
               status = relayThresholdsSetInputChannel(value & 0xFF);
               break;
            case relayThresholdCommandKeyNumber_OUTPUT_PIN:
               status = relayThresholdsSetOutputPin(value & 0xFF);
               break;
            case relayThresholdCommandKeyNumber_LED_PIN:
               status = relayThresholdsSetLedPin(value & 0xFF);
               break;
            case relayThresholdCommandKeyNumber_REPORT_STATE_ENABLE:
               status = relayThresholdsSetReportCurrentStatusEnableFlag(value & 0xF);
               break;
            case relayThresholdCommandKeyNumber_RELAY_VALUE:
               status = relayThresholdsSetRelayValue(value);
               break;
            case relayThresholdCommandKeyNumber_INVERT_POLARITY_LOGIC:
               status = relayThresholdsSetInvertPolarityFlag(value);
               break;
            case relayThresholdCommandKeyNumber_EXTERNAL_IN_BOUNDS_PIN_POS:
               status = relayThresholdsSetExternalPolarityPinPos(value);
               break;
            case relayThresholdCommandKeyNumber_EXTERNAL_IN_BOUNDS_PORT:
               status = relayThresholdsSetExternalPolarityPinPos(value);
               break;
            default:
               CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
               return;
               break;
         }

         /*recursive call to show change*/
         if ( 0 == status )
         {
            ptr_uartStruct->number_of_arguments = 1;
            relayThresholdMiscSubCommands(ptr_uartStruct, index);
            ptr_uartStruct->number_of_arguments = 2;

            switch ( index )
            {
               case relayThresholdCommandKeyNumber_ENABLE:
                  if ( value )
                  {
                     status = relayThresholdInit();
                  }
                  break;
               default:
                  break;
            }
         }
         break;
      default:
         general_errorCode = CommunicationError(ERRG, -1001, TRUE, PSTR("invalid number of arguments"), 101);
         break;
   }

   return;
}

void relayThresholdsReportCurrentStatus(void)
{
   int nargs = ptr_uartStruct->number_of_arguments;
   ptr_uartStruct->number_of_arguments = 1;
   relayThresholdMiscSubCommands(ptr_uartStruct, relayThresholdCommandKeyNumber_STATUS);
   ptr_uartStruct->number_of_arguments = nargs;
}

uint8_t relayThresholdInBoundPolarityInit(void)
{
   /* PORT F, pin "relayThresholdsExternalPolarityPinPos" determines whether relay is TRUE/FALSE when in bounds*/
   /* which is per default set to HIGH/TRUE/1 */
   switch(relayThresholdsExternalPolarityPort)
   {
      case 0xA:
         relayThresholdsExternalPolarity = (PORTA >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      case 0xB:
         relayThresholdsExternalPolarity = (PORTB >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      case 0xC:
         relayThresholdsExternalPolarity = (PORTC >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      case 0xD:
         relayThresholdsExternalPolarity = (PORTD >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      case 0xE:
         relayThresholdsExternalPolarity = (PORTE >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      case 0xF:
         relayThresholdsExternalPolarity = (PORTF >> (relayThresholdsExternalPolarityPinPos -1) ) & 0x1;
         break;
      default:
         general_errorCode = CommunicationError(ERRG, -1001, TRUE, PSTR("'RLTH invalid input port for external polarity"), 101);
         break;
         return ;
   }
   relayThresholdsInBoundsPolarity = ( 0x1 == relayThresholdsExternalPolarity );
   relayThresholdsOutOfBoundsPolarity = ( 0x1 != relayThresholdsExternalPolarity );
   if (FALSE != relayThresholdInvertPolarity_flag)
   {
      relayThresholdsInBoundsPolarity    = 0x1 & (~relayThresholdsInBoundsPolarity);
      relayThresholdsOutOfBoundsPolarity = 0x1 & (~relayThresholdsOutOfBoundsPolarity);
   }
   return relayThresholdsExternalPolarity;
}

uint8_t relayThresholdInit(void)
{
   if ( eventDebug <= debug && ( debugMask >> debugRELAY ) & 1 )
   {
      snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) Init"), __LINE__, __FILE__);
      UART0_Send_Message_String(NULL,0);
   }

   /* check prerequisites */
   if ( FALSE == relayThresholds_valid[relayThreshold_LOW] ||
        FALSE == relayThresholds_valid[relayThreshold_HIGH] )
   {
      return FALSE;
   }

   /* get current ADC value */
   uint32_t currentValue = 0xFFFFFFFF;
   currentValue = relayThresholdsGetCurrentValue(); // returns value + error information on top (16 MSB)

   if ( 0 != (currentValue >> 16))
   {
      // error
      return FALSE;
   }
   else
   {
      // to be sure, remove back packer info;
      currentValue = (currentValue & 0xFFFF);
   }

   /* checks passed */


   if ( currentValue < relayThresholdLow )
   {
      relayThresholdCurrentState = relayThresholdState_BELOW_LOW_THRESHOLD;
      relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
   }
   else if ( currentValue > relayThresholdHigh )
   {
      relayThresholdCurrentState = relayThresholdState_ABOVE_HIGH_THRESHOLD;
      relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
   }
   else
   {
      relayThresholdCurrentState = relayThresholdState_INBETWEEN;
      relayThresholdRelaySetValue = relayThresholdsInBoundsPolarity;
   }

   if (FALSE != relayThresholdEnable_flag)
   {
      relayThresholdsSetRelayValue(relayThresholdRelaySetValue); /*turns on/off relay*/
   }

   if (FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      PORTA = PORTA | ( ( 0x1 << relayThresholdLedPin ) ); // turn on lamp
      /* report current state and value */
      relayThresholdsReportCurrentStatus();
   }

   return TRUE;
}

void relayThresholdDetermineStateAndTriggerRelay(void)
{
   uint32_t currentValue = 0xFFFFFFFF;
   uint8_t report = FALSE;
   uint8_t relayThresholdOutOfBoundsTransitLockSetValue_flag = FALSE;
   currentValue = relayThresholdsGetCurrentValue(); // returns value + error information on top (16 MSB)

   if ( 0 != (currentValue >> 16))
   {
      // error
      return;
   }
   else
   {
      // to be sure, remove back packer info;
      currentValue = (currentValue & 0xFFFF);
   }

   /* checks passed */

   if ( eventDebug <= debug && ( debugMask >> debugRELAY ) & 1 )
      {
          snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) Determine..."), __LINE__, __FILE__);
          UART0_Send_Message_String(NULL,0);
      }

   report  = FALSE;
   switch ( relayThresholdCurrentState )
   {
      case relayThresholdState_IDLE:
         {
            if ( currentValue > relayThresholdHigh )
            {
               /*turn off relays*/
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_ABOVE_HIGH_THRESHOLD;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
            if ( currentValue < relayThresholdLow )
            {
               /*turn off relays*/
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_BELOW_LOW_THRESHOLD;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
            else if ( currentValue > relayThresholdLow + 2  && currentValue < relayThresholdHigh -2 )
            {
               /*turn on relays*/
               relayThresholdRelaySetValue = relayThresholdsInBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_INBETWEEN;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
         }
         break;
      case relayThresholdState_INBETWEEN:
         {
            if ( currentValue > relayThresholdHigh )
            {
               /*turn off relays*/
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_ABOVE_HIGH_THRESHOLD;
               if (FALSE != relayThresholdOutOfBoundsTransitLock_flag) { relayThresholdOutOfBoundsTransitLockSetValue_flag = TRUE ;}
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
            if ( currentValue < relayThresholdLow )
            {
               /*turn off relays*/
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_BELOW_LOW_THRESHOLD;
               if (FALSE != relayThresholdOutOfBoundsTransitLock_flag) { relayThresholdOutOfBoundsTransitLockSetValue_flag = TRUE ;}
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
         }
         break;
      case relayThresholdState_BELOW_LOW_THRESHOLD:
         {
            _delay_ms(100);
            _delay_ms(100);
            PINA = ( 0x1 << relayThresholdLedPin ); // toggle LED

            if ( currentValue > relayThresholdHigh )
            {
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_ABOVE_HIGH_THRESHOLD;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
            else if ( currentValue > relayThresholdLow + 2 )
            {
               /*turn on relays*/
               relayThresholdRelaySetValue = relayThresholdsInBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_INBETWEEN;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
         }
         break;
      case relayThresholdState_ABOVE_HIGH_THRESHOLD:
         {
            _delay_ms(100);
            _delay_ms(100);
            PINA = ( 0x1 << relayThresholdLedPin ); // toggle LED

            if ( currentValue < relayThresholdLow )
            {
               relayThresholdRelaySetValue = relayThresholdsOutOfBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_BELOW_LOW_THRESHOLD;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
            else if ( currentValue < relayThresholdHigh - 2 )
            {
               /* turn on relays and lamp*/
               relayThresholdRelaySetValue = relayThresholdsInBoundsPolarity;
               relayThresholdCurrentState = relayThresholdState_INBETWEEN;
               if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
            }
         }
         break;
      default:
         {
            relayThresholdCurrentState = relayThresholdState_UNDEFINED;
            if (FALSE != relayThresholdReportCurrentStatusEnable_flag) {report = TRUE;}
         }
         break;
   }


   /* physically set relay value */
   if (FALSE != relayThresholdEnable_flag)
   {
      if ( relayThresholdRelaySetValue != relayThresholdRelayValue )
      {
         relayThresholdsSetRelayValue(relayThresholdRelaySetValue); /*turns on/off relay*/
      }
      if (FALSE != relayThresholdOutOfBoundsTransitLockSetValue_flag)
      {
         relayThresholdsSetEnableFlag(FALSE);
      }
   }


   if (FALSE != report)
   {
      /* report current state and value */
      relayThresholdsReportCurrentStatus();
   }
}

uint8_t relayThresholdsSetHighThreshold(uint16_t value)
{
   uint8_t status = 0;

   relayThresholdHigh = value;

   relayThresholds_valid[relayThreshold_HIGH] = TRUE;

   return status;
}

uint8_t relayThresholdsSetLowThreshold(uint16_t value)
{
   uint8_t status = 0;

   relayThresholdLow = value;

   relayThresholds_valid[relayThreshold_LOW] = TRUE;

   return status;
}

uint8_t relayThresholdsSetEnableFlag(uint8_t value)
{
   uint8_t status = 0;

   relayThresholdEnable_flag = ( 0 != value);

   if ( FALSE == relayThresholdEnable_flag)
   {
      relayThresholdCurrentState = relayThresholdState_IDLE;
      PORTA = PORTA & ( ~( 0x1 << relayThresholdLedPin ) ); // turn off lamp
   }
   else
   {
      PORTA = PORTA | ( ( 0x1 << relayThresholdLedPin ) ); // turn on lamp
   }

   return status;
}

uint8_t relayThresholdsSetReportCurrentStatusEnableFlag(uint8_t value)
{
   uint8_t status = 0;

   relayThresholdReportCurrentStatusEnable_flag = ( 0 != value);

   if ( FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      relayThresholdsReportCurrentStatus();
   }

   return status;
}

uint8_t relayThresholdsSetOutOfBoundsTransitLockFlag(uint8_t value)
{
   uint8_t status = 0;

   relayThresholdOutOfBoundsTransitLock_flag = ( 0 != value);

   if ( FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      relayThresholdsReportCurrentStatus();
   }

   return status;
}

uint8_t relayThresholdsSetInvertPolarityFlag(uint8_t value)
{
   uint8_t status = 0;

   relayThresholdInvertPolarity_flag = ( 0 != value);

   /* reinit*/
   relayThresholdInBoundPolarityInit();

   if ( FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      relayThresholdsReportCurrentStatus();
   }

   return status;
}

uint8_t relayThresholdsSetRelayValue(uint8_t value)
{
   uint8_t status = 0;
   uint8_t setValue = 0;
   setValue = ( 0 != value);
   if (relayThresholdRelayValue != setValue)
   {
      if (TRUE == setValue)
      {
         PORTA |= ( 0x1 << relayThresholdOutputPin ) ;
      }
      else
      {
         PORTA &= ( ~( 0x1 << relayThresholdOutputPin) );
      }
      relayThresholdRelayValue = setValue;
      if (FALSE != relayThresholdReportCurrentStatusEnable_flag)
      {
         relayThresholdsReportCurrentStatus();
      }
   }

   return status;
}

uint8_t relayThresholdsSetRelaySetValue(uint8_t value)
{
   uint8_t status = 0;
   uint8_t setValue = 0;
   setValue = ( 0 != value);
   if (relayThresholdRelaySetValue != setValue)
   {
      relayThresholdRelaySetValue = setValue;
      if (FALSE != relayThresholdReportCurrentStatusEnable_flag)
      {
         relayThresholdsReportCurrentStatus();
      }
   }

   return status;
}

uint8_t relayThresholdsSetInputChannel(uint8_t value)
{
   uint8_t status = 0;
   if ( value <= 7)
   {
      relayThresholdInputChannel = value;
   }
   else
   {
      CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
      status = 1;
   }
   return status;
}

uint8_t relayThresholdsSetOutputPin(uint8_t value)
{
   uint8_t status = 0;
   if ( value <= 7)
   {
      relayThresholdOutputPin = value;
   }
   else
   {
      CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
      status = 1;
   }
   return status;
}

uint8_t relayThresholdsSetLedPin(uint8_t value)
{
   uint8_t status = 0;
   if ( value <= 7)
   {
      relayThresholdLedPin = value;
   }
   else
   {
      CommunicationError(ERRA, -1, TRUE, PSTR("invalid command argument"), -1);
      status = 1;
   }
   return status;
}

uint8_t relayThresholdsSetExternalPolarityPinPos(uint8_t value)
{
   uint8_t status = 0;

   if ( 1 > value || 8 < value )
   {
      snprintf_P(message, BUFFER_SIZE - 1,
                 PSTR("value out of bounds [1,8]"), value);
      CommunicationError(ERRG, -100, TRUE, NULL,
                         COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD - 100 );

      return 1;
   }

   relayThresholdsExternalPolarityPinPos = value;

   /* reinit*/
   relayThresholdInBoundPolarityInit();

   if ( FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      relayThresholdsReportCurrentStatus();
   }

   return status;
}

uint8_t relayThresholdsSetExternalPolarityPort(uint8_t value)
{
   uint8_t status = 0;

   if ( 0xA > value || 0xF < value )
   {
      snprintf_P(message, BUFFER_SIZE - 1,
                 PSTR("value out of bounds [A,F]"), value);
      CommunicationError(ERRG, -100, TRUE, NULL,
                         COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD - 100 );

      return 1;
   }

   relayThresholdsExternalPolarityPort = value;

   /* reinit*/
   relayThresholdInBoundPolarityInit();

   if ( FALSE != relayThresholdReportCurrentStatusEnable_flag)
   {
      relayThresholdsReportCurrentStatus();
   }

   return status;
}

uint8_t relayThresholdsGetInvertPolarityFlag(void)
{
   return relayThresholdInvertPolarity_flag;
}

uint16_t relayThresholdsGetHighThreshold(void)
{
   return relayThresholdHigh;
}

uint16_t relayThresholdsGetLowThreshold(void)
{
   return relayThresholdLow;
}

uint8_t relayThresholdsGetEnableFlag(void)
{
   return relayThresholdEnable_flag;
}

uint8_t relayThresholdsGetOutOfBoundsTransitLockFlag(void)
{
   return relayThresholdOutOfBoundsTransitLock_flag;
}

uint8_t relayThresholdsGetReportStateEnableFlag(void)
{
   return relayThresholdReportCurrentStatusEnable_flag;
}

uint8_t relayThresholdsGetInBoundsPolarity(void)
{
   return (relayThresholdsInBoundsPolarity != FALSE);
}

uint8_t relayThresholdsGetOutOfBoundsPolarity(void)
{
   return (relayThresholdsOutOfBoundsPolarity != FALSE);
}

uint8_t relayThresholdsGetExternalPolarityPinPos(void)
{
   return relayThresholdsExternalPolarityPinPos;
}

uint8_t relayThresholdsGetExternalPolarityPort(void)
{
   return relayThresholdsExternalPolarityPort;
}

uint8_t relayThresholdsGetExternalPolarity(void)
{
   return (relayThresholdsExternalPolarity != FALSE);
}

uint8_t relayThresholdsGetInputChannel(void)
{
   return relayThresholdInputChannel;
}

uint8_t relayThresholdsGetOutputPin(void)
{
   return relayThresholdOutputPin;
}

uint8_t relayThresholdsGetLedPin(void)
{
   return relayThresholdLedPin;
}

uint8_t relayThresholdsGetCurrentState(void)
{
   return relayThresholdCurrentState;
}

uint32_t relayThresholdsGetCurrentValue(void)

{
   uint8_t status = eNoError;

   /*pressure is checked only for channel 0*/
   status = atmelReadSingleADCChannelVoltage(relayThresholdInputChannel);

   /* set global status*/
   switch (relayThresholdInputChannel)
   {
      case 0:
         res0 = status;
         break;
      case 1:
         res1 = status;
         break;
      case 2:
         res2 = status;
         break;
      case 3:
         res3 = status;
         break;
      case 4:
         res4 = status;
         break;
      case 5:
         res5 = status;
         break;
      case 6:
         res6 = status;
         break;
      case 7:
         res7 = status;
         break;
      default:
         snprintf_P(message, BUFFER_SIZE - 1,
                    PSTR("error accessing ADC wrong channel: %i"), ptr_uartStruct->Uart_Message_ID);
         CommunicationError(ERRG, -100, TRUE, NULL,
                            COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD - 100 );
         return 0x2L << 16;
         break;
   }

   /* check status return*/
   if ( status != eNoError )
   {
      snprintf_P(message, BUFFER_SIZE - 1,
                 PSTR("error accessing ADC channel %i"), ptr_uartStruct->Uart_Message_ID);
      CommunicationError(ERRG, -100, TRUE, PSTR("error accessing ADCs"),
                         COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD - 100 );

      return 0x1L << 16;
   }

   return Voltages[relayThresholdInputChannel];
}

uint8_t relayThresholdsGetRelayValue(void)
{
   return relayThresholdRelayValue;
}

uint8_t relayThresholdsGetRelaySetValue(void)
{
   return relayThresholdRelaySetValue;
}
