/*
 * VERSION 1.0 Januar 7th 2010 LATE  File: 'api.c'
 * Author: Linda Fouedjio
 * modified (heavily rather rebuild): Peter Zumbruch
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>
#include <avr/iocanxx.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>

#include "api.h"
#include "api_define.h"
#include "api_global.h"
#include "api_constants.h"
#include "api_show.h"
#include "api_help.h"
#include "delay.h"
#include "twi_master.h"


#ifndef API_CONSTANTS_H_

#warning TODO: combine responseKeyword and other responses error into one set of responses
static const char responseKeyword00[] PROGMEM = "RECV";

const char* responseKeywords[] PROGMEM = {
        responseKeyword00
};

/* those are the command keywords of the API*/
static const char commandKeyword00[] PROGMEM = "TWIS";
static const char commandKeyword01[] PROGMEM = "RSET";

/* this is the corresponding command key array, beware of the same order*/
const char* commandKeywords[] PROGMEM = {
		commandKeyword00,
		commandKeyword01
};

/* those are the command keywords of the API*/
static const char commandShortDescription00[] PROGMEM = "Adresse for TWI communication";
static const char commandShortDescription01[] PROGMEM = "TWI-Data [0...4]";


/* this is the corresponding command key array, beware of the same order*/
const char* commandShortDescriptions[] PROGMEM= {
		commandShortDescription00,
		commandShortDescription01	
};

/* those are the command keywords of the API*/
static const char commandImplementation00[] PROGMEM = "TWIS implement";
static const char commandImplementation01[] PROGMEM = "RSET implement";
static const char commandImplementation02[] PROGMEM = "--- not implemented";



/* this is the corresponding command key array, beware of the same order*/
const char* commandImplementations[] PROGMEM= {
		commandImplementation00,
		commandImplementation01,
		commandImplementation02	
};


//* pointer of array for defined serial error number*/
static const char se00[] PROGMEM = "no valid command name";
static const char se01[] PROGMEM = "command_type is too long";
static const char se02[] PROGMEM = "adresse is too long";
static const char se03[] PROGMEM = "length is too long";
static const char se04[] PROGMEM = "data 0 is too long";
static const char se05[] PROGMEM = "data 1 is too long";
static const char se06[] PROGMEM = "data 2 is too long";
static const char se07[] PROGMEM = "data 3 is too long";
static const char se08[] PROGMEM = "data 4 is too long";
static const char se09[] PROGMEM = "data 5 is too long";
static const char se10[] PROGMEM = "data 6 is too long";
static const char se11[] PROGMEM = "data 7 is too long";
static const char se12[] PROGMEM = "command is too long";
static const char se13[] PROGMEM = "argument has invalid type";
static const char se14[] PROGMEM = "command_type has invalid type";
static const char se15[] PROGMEM = "adresse has invalid type";
static const char se16[] PROGMEM = "length has invalid type";
static const char se17[] PROGMEM = "data 0 has invalid type";
static const char se18[] PROGMEM = "data 1 has invalid type";
static const char se19[] PROGMEM = "data 2 has invalid type";
static const char se20[] PROGMEM = "data 3 has invalid type";
static const char se21[] PROGMEM = "data 4 has invalid type";
static const char se22[] PROGMEM = "data 5 has invalid type";
static const char se23[] PROGMEM = "data 6 has invalid type";
static const char se24[] PROGMEM = "data 7 has invalid type";
static const char se25[] PROGMEM = "undefined error type";
static const char se26[] PROGMEM = "first value is too long";
static const char se27[] PROGMEM = "second value is too long";
static const char se28[] PROGMEM = "arguments have invalid type";
static const char se29[] PROGMEM = "argument(s) exceed(s) allowed boundary";
static const char se30[] PROGMEM = "too many arguments";


const char *serial_error[] PROGMEM = { se00, se01, se02, se03, se04, se05, se06, se07, se08, se09, se10, se11, se12, se13, se14, se15, se16, se17, se18, se19, se20,
		se21, se22, se23, se24, se25, se26, se27,se28,se29,se30 };


/* array for defined serial error number*/
const uint8_t serial_error_number[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 110,
		111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
		121, 122, 123, 124, 125, 126, 127,128,129,130
		};

/* pointer of array for defined can error number*/

static const char tw00[] PROGMEM = "Error in initiating TWI interface";
static const char tw01[] PROGMEM = "Could not start TWI Bus for WRITE";
static const char tw02[] PROGMEM = "Could not start TWI Bus for READ";


const char *twi_error[] PROGMEM = { tw00, tw01, tw02 };

/* array for defined can error number*/
const uint8_t twi_error_number[] = { 21, 22, 23};
/* pointer of array for defined general error number*/

/* pointer of array for defined general error number*/

static const char errorType00[] PROGMEM = "ERRA"; /*api*/
static const char errorType01[] PROGMEM = "ERRT"; /*twi protocol*/
static const char errorType02[] PROGMEM = "ERRU"; /*undefined*/

/* this is the corresponding error Type array, beware of the same order*/
const char *errorTypes[] PROGMEM = {
		errorType00,
		errorType01,
		errorType02		
};

static const char debugLevelName00[] PROGMEM = "          noDebug";
static const char debugLevelName01[] PROGMEM = "     verboseDebug";
static const char debugLevelName02[] PROGMEM = "       eventDebug";
static const char debugLevelName03[] PROGMEM = "eventDebugVerbose";
static const char debugLevelName04[] PROGMEM = "    periodicDebug";

const char *debugLevelNames[] PROGMEM = {
         debugLevelName00,
         debugLevelName01,
         debugLevelName02,
         debugLevelName03,
         debugLevelName04
};

static const char debugSystemName00[] PROGMEM = "             Main";
static const char debugSystemName01[] PROGMEM = "             UART";
static const char debugSystemName02[] PROGMEM = "              CAN";
static const char debugSystemName03[] PROGMEM = "           TIMER0";
static const char debugSystemName04[] PROGMEM = "           TIMER1";
static const char debugSystemName05[] PROGMEM = "          TIMER0A";
static const char debugSystemName06[] PROGMEM = " TIMER0AScheduler";
static const char debugSystemName07[] PROGMEM = "       GETVOLTAGE";
static const char debugSystemName08[] PROGMEM = "            RELAY";
static const char debugSystemName09[] PROGMEM = "       CommandKey";
static const char debugSystemName10[] PROGMEM = "              OWI";
static const char debugSystemName11[] PROGMEM = "  OWITemperatures";
static const char debugSystemName12[] PROGMEM = "          Decrypt";
static const char debugSystemName13[] PROGMEM = "            DEBUG";
static const char debugSystemName14[] PROGMEM = "           OWIADC";
static const char debugSystemName15[] PROGMEM = "OWIDoubleSwitches";
static const char debugSystemName16[] PROGMEM = "OWISingelSwitches";
static const char debugSystemName17[] PROGMEM = "             SHOW";
static const char debugSystemName18[] PROGMEM = "   OWIApiSettings";

const char *debugSystemNames[] PROGMEM =
{
   debugSystemName00,
   debugSystemName01,
   debugSystemName02,
   debugSystemName03,
   debugSystemName04,
   debugSystemName05,
   debugSystemName06,
   debugSystemName07,
   debugSystemName08,
   debugSystemName09,
   debugSystemName10,
   debugSystemName11,
   debugSystemName12,
   debugSystemName13,
   debugSystemName14,
   debugSystemName15,
   debugSystemName16,
   debugSystemName17,
   debugSystemName18
};
#endif
/*----------------------------------------------------------------------------------------------------*/

/*
 *this function initializes the UART0 register needed to allow the at90can128
 *USART transmissions
 */
int8_t UART0_Init( void )
{
	uint8_t intstate1 = SREG;/*save global interrupt flag*/
	cli();
	/*disable interrupt*/
	while ( 0 << TXC0 )
	{
	}
	/* set baud rate*/
	UBRR0H = (uint8_t) ( BAUD >> 8 );
	UBRR0L = (uint8_t) ( BAUD );
	/* set frame format: i wil set it now as 8 bits, no parity 1 stop bit, asynchron*/
	UCSR0C = ( 0 << UMSEL0 ) | ( 0 << UPM0 ) | ( 0 << USBS0 ) | ( 3 << UCSZ0 );
	/*set double speed*/
	UCSR0A = ( 1 << U2X0 );
	/*enable receiver and transmitter; enable RX and Data register empty interrupt*/
	UCSR0B = ( 1 << TXEN0 ) | ( 1 << RXEN0 ) | ( 1 << RXCIE0 );
	SREG = intstate1; /*restore global interrupt flag*/
	return 1;
}//END of  UART0_Init




/*
 *this function initializes the 8 bit counter
 * the function has not input parameter
 */

int8_t Timer0_Init( void )
{
	uint8_t intstate3 = SREG; /* save global interrupt flag */
	cli(); /* disable interrupt */
	TCCR0A = ( 1 << CS02 ) | ( 0 << CS01 ) | ( 1 << CS00 ); /* set Prescaler 1024 */
	TIMSK0 |= ( 1 << TOIE0 ); /* Timer0 Overflow enable */
	SREG = intstate3; /* restore global interrupt flag */
	return 1;
}// END of Timer0_Init


/*
 *this function initializes the 8 bit counter with output compareA
 * the function has not input parameter
 * the output parameter is an integer
 * 1 -> the timer initializierung for timer 0 was successfully
 */

int8_t Timer0A_Init( void )
{
	uint8_t intstate4 = SREG; /* save global interrupt flag */
	cli();  /* disable interrupt */
	TCCR0A = ( 1 << FOC0A ) | ( 1 << CS02 ) | ( 0 << CS01 ) | ( 1 << CS00 ); /* set Prescaler 1024 */
	OCR0A = 255;
	TCNT0 = 20;
	TIMSK0 |= ( 1 << OCIE0A ); /* enable compare output Interrupt */
	SREG = intstate4; /*restore global interrupt flag */
	return 1;
}//END of int8_t Timer0A_Init

/* this function processes an UART event
 * i.e.
 * - parsing it
 * - finding command keywords
 * - converting command arguments into an structure
 * - check the parameter boundaries and types (integer)
 * - check for errors
 * - choose the corresponding function
 * - resetting data structures
 *
 * no direct input: use of global variable decrypt_uartStruct
 * no return value
 */

void Process_Uart_Event(void)
{
	/* split uart string into its elements */

	int8_t number_of_elements = -1;
	number_of_elements = Decrypt_Uart_String();

	if ( 0 < number_of_elements  )
	{
		/* set number of arguments */
		ptr_uartStruct->number_of_arguments = number_of_elements -1;

		/* Find matching command keyword */
		ptr_uartStruct->commandKeywordIndex = Parse_Keyword(setParameter[0]);

		if ( eventDebug <= debug && ( debugMask >> debugCommandKey ) & 1 )
		{
			snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) keywordIndex of %s is %i"), __LINE__, __FILE__, setParameter[0], ptr_uartStruct->commandKeywordIndex);
			UART0_Send_Message_String(NULL,0);
		}

		/* no matching keyword ?*/
		if ( 0 > ptr_uartStruct->commandKeywordIndex )
		{
			Check_Error(ptr_uartStruct);
		}
		else
		{
			switch(ptr_uartStruct->commandKeywordIndex)
			{
			Choose_Function(ptr_uartStruct);
			break;

			default:
				/* call the function for the conversion frameformat in Canformat*/
				Convert_UartData_to_UartStruct(setParameter);
				/*call the function Check_Parameter*/
				/* TODO: improve this for different command keywords than CAN based,
				 * i.e. think to do checks maybe later when already having chosen the
				 * right function*/
				if ( TRUE == Check_Parameter(ptr_uartStruct) )
				{
					Choose_Function(ptr_uartStruct);
				}
				else
				{
					Check_Error(ptr_uartStruct);
				}
				break;
			}
		}
	}


	/*clear the variables*/
	Reset_SetParameter();
	Reset_UartStruct(ptr_uartStruct);
	clearString(decrypt_uartString, BUFFER_SIZE);

	return;
}

/*
 * this function splits the string to receive various parameters
 * no direct input : use of global variable decrypt_uartString
 * no direct output: use of global variable setParameter
 * return value:
 *          number of found elements,
 *          FALSE else
 */

int8_t Decrypt_Uart_String( void )
{
	uint8_t index_parameter;

	/* maximum length check of input */

	if ( MAX_LENGTH_COMMAND < strlen(decrypt_uartString) )
	{
		uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_command_is_too_long, 0, NULL, 0);

		/* reset */
		clearString(decrypt_uartString, BUFFER_SIZE);
		/* "reset": decrypt_uartString[0] = '\0'; */

		return FALSE;
	}

	/*
	 * disassemble the decrypt_uartString into stringlets
	 * separated by delimiters "delim"
	 * into elements of array setParameter
	 */

	const char *delims = " ";
	char *test = NULL;
	char *result = NULL; /* pointer init */

	/* initial iteration */
	result = strtok_r(decrypt_uartString, delims, &test); /*search spaces in string */
	index_parameter = 0; /* pointer of setParameter*/

	while ( result != NULL )
	{
		if (MAX_LENGTH_PARAMETER < strlen(result))
		{
			/* TODO: create correct error code*/
			uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_command_is_too_long, 0, NULL, 0);
		     clearString(decrypt_uartString, BUFFER_SIZE);
		        /* "reset": decrypt_uartString[0] = '\0'; */

			return FALSE;
		}

		strncpy(setParameter[index_parameter], result, MAX_LENGTH_PARAMETER);
		result = strtok_r(NULL, delims, &test);
		index_parameter++;

		if ( MAX_PARAMETER < index_parameter )
		{
			uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_too_many_arguments, 0, NULL, 0);
	        clearString(decrypt_uartString, BUFFER_SIZE);
	        /* "reset": decrypt_uartString[0] = '\0'; */
			return FALSE;
		}
	}

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

    clearString(decrypt_uartString, BUFFER_SIZE);
     /* "reset": decrypt_uartString[0] = '\0'; */

	return index_parameter;;

}//END of Decrypt_Uart_String function


/*
 *this function assigns the various parameters of the string to the structure and reviewed the range of *individual  parameters.
 *the  function has a two dimensional array from string via serial interface as input and returns no parameter
 */

void Convert_UartData_to_UartStruct( char string[MAX_PARAMETER][MAX_LENGTH_PARAMETER] )
{

    if (1)//( eventDebug <= debug && ( debugMask >> debugOWIADC ) & 0x1 )
    {

    }
	/* convert char in Hexadezimal*/

        ptr_uartStruct->Command_typ     = (uint32_t) strtoul(setParameter [1], &ptr_setParameter[1], 16);
	ptr_uartStruct->Adresse         = (uint32_t) strtoul(setParameter [2], &ptr_setParameter[2], 16);
	ptr_uartStruct->Uart_Length     = (uint8_t)  strtoul(setParameter [3], &ptr_setParameter[3], 16);
	ptr_uartStruct->Uart_Data[0]    = (uint16_t) strtoul(setParameter [4], &ptr_setParameter[4], 16);
	ptr_uartStruct->Uart_Data[1]    = (uint16_t) strtoul(setParameter [5], &ptr_setParameter[5], 16);
	ptr_uartStruct->Uart_Data[2]    = (uint16_t) strtoul(setParameter [6], &ptr_setParameter[6], 16);
	ptr_uartStruct->Uart_Data[3]    = (uint16_t) strtoul(setParameter [7], &ptr_setParameter[7], 16);
	ptr_uartStruct->Uart_Data[4]    = (uint16_t) strtoul(setParameter [8], &ptr_setParameter[8], 16);
	ptr_uartStruct->Uart_Data[5]    = (uint16_t) strtoul(setParameter [9], &ptr_setParameter[9], 16);
	ptr_uartStruct->Uart_Data[6]    = (uint16_t) strtoul(setParameter [10], &ptr_setParameter[10], 16);
	ptr_uartStruct->Uart_Data[7]    = (uint16_t) strtoul(setParameter [11], &ptr_setParameter[11], 16);

} // END of function Convert_UartFormat_to_CanFormat

/* this function parses for all valid command matching keyword
 * on the first MAX_LENGTH_PARAMETER characters of the string
 *
 * it has an char pointer as input
 * it returns
 *     the commandKeyNumber of the corresponding command key word
 *     -1 if not found
 *     -99 on error
 */

int Parse_Keyword(char string[])
{
	static int8_t keywordNumber;

	if (NULL == string   ) {return -99;}
	if (STRING_END  == string[0]) {return -99;}

	if ( eventDebug <= debug && ( debugMask >> debugCommandKey ) & 1 )
	{
		snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) Parse_Keyword %s"), __LINE__, __FILE__, string);
		UART0_Send_Message_String(NULL,0);
	}
	for ( keywordNumber = 0; keywordNumber < commandKeyNumber_MAXIMUM_NUMBER ; keywordNumber++ )
	{
       /*exclude list*/
     //  if ( commandKeyNumber_OWON == keywordNumber) { continue; }

		if ( 0 == strncmp_P(&string[0], (const char*) (pgm_read_word( &(commandKeywords[keywordNumber]))), MAX_LENGTH_PARAMETER) )
		{
           if ( eventDebug <= debug && (debugMask >> debugCommandKey) & 0x1)
            {
               snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) fcn:ParseKeyword keyword %s matches "),
                          __LINE__, __FILE__, string);
               strncat_P(uart_message_string,(const char*) (pgm_read_word( &(commandKeywords[keywordNumber]))),BUFFER_SIZE -1);
               UART0_Send_Message_String(NULL,0);
            }

			return keywordNumber;
		}
        else
          {
             if ( eventDebugVerbose <= debug && (debugMask >> debugCommandKey) & 0x1)
             {
                snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) fcn:ParseKeyworkd keyword %s doesn't match "),
                           __LINE__, __FILE__, string);
                strncat_P(uart_message_string,(const char*) (pgm_read_word( &(commandKeywords[keywordNumber]))),BUFFER_SIZE -1);
                UART0_Send_Message_String(NULL,0);
             }
          }

	}
	return -1;
}

/* this function checks whether all the received parameters are valid
 * the function has a pointer of the serial structure as input and
 * returns TRUE if all checks are passed
 * else FALSE
 */

int8_t Check_Parameter( struct uartStruct *ptr_uartStruct )
{
	/*check correct keyword*/
	/*check range of parameter*/
	return ( 0 <= ptr_uartStruct->commandKeywordIndex && TRUE == Check_Parameter_CanFormat(ptr_uartStruct) ) ? TRUE : FALSE;
}

/* this function checks whether all the received parameters are valid
 * the function has a pointer of the serial structure as input and returns no parameter
 * returns TRUE if all checks are passed
 * returns FALSE else
 */

int8_t Check_Parameter_CanFormat( struct uartStruct *ptr_uartStruct )
{
	/*check range of parameter*/

	for (uint8_t index = 1; index < MAX_PARAMETER; index ++)
	{
		if ( 0 != *ptr_setParameter[index] ) return FALSE;
	}
	if ((0          != (ptr_uartStruct->Command_typ)) && 
	    ( 1         != (ptr_uartStruct->Command_typ)) ) return FALSE;
	if ( 0x7F       < ptr_uartStruct->Adresse         ) return FALSE;
	if ( 8          < ptr_uartStruct->Uart_Length     ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[0]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[1]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[2]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[3]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[4]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[5]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[6]    ) return FALSE;
	if ( 0XFF       < ptr_uartStruct->Uart_Data[7]    ) return FALSE;
	return TRUE;

}

/* this function clears the container setParameter
 * the function has no input
 */

void Reset_SetParameter()
{
	for ( uint8_t count_setParameter = 0 ; count_setParameter < MAX_PARAMETER ; count_setParameter++ )
	{
		setParameter[count_setParameter][0] = '\0';
		*ptr_setParameter[count_setParameter] = 0;

	}
}

/* this function clears the container pointed to by ptr_uartStruct
 * the function has as input a pointer to an uartStruct structure
 */

void Reset_UartStruct( struct uartStruct *ptr_uartStruct )
{
	if ( NULL != ptr_uartStruct )
	{
		
		ptr_uartStruct->Command_typ = 0;
		ptr_uartStruct-> Adresse = 0;
		ptr_uartStruct->commandKeywordIndex = -1;
		ptr_uartStruct->number_of_arguments = -1;
		for ( uint8_t i = 0 ; i < 8 ; i++ )
		{
			ptr_uartStruct->Uart_Data[i] = 0;
		}
	}
}

/* this function checks error for the received parameter
 * the function has a pointer of the serial structur as input and returns no parameter
 */


int8_t Check_Error( struct uartStruct *ptr_uartStruct )
		{
		   static int8_t error = FALSE;

			error = FALSE;


			if ( 0 > ptr_uartStruct->commandKeywordIndex )
			{
			   uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_no_valid_command_name,0,NULL,0);
		       error = TRUE;
			}
			else
			{
				for (uint8_t index = 1; index < MAX_PARAMETER; index ++)
				{
					if (0 != *ptr_setParameter[index])
					{
				         if (1)//( eventDebug <= debug && ( debugMask >> debugOWIADC ) & 0x1 )
				         {

				         }
						uart_errorCode = CommunicationError(ERRA,SERIAL_ERROR_argument_has_invalid_type + index, 0, NULL, 0);
						error = TRUE;
					}
				}

				switch (ptr_uartStruct->commandKeywordIndex)
				{
				case commandKeyNumber_TWIS: /*I2C*/
			
				{
		//#error missing break statement for number of arguments
					/* type check */
					for ( uint8_t i = 0 ; i < MAX_PARAMETER ; i++ )
					{

						switch (i)
						{

						case 1:
						  if ( (0 != (ptr_uartStruct->Command_typ)) && 
						       (1 != (ptr_uartStruct->Command_typ))  )
							
							{
								uart_errorCode = CommunicationError(ERRA,  SERIAL_ERROR_command_type_is_too_long, 0, NULL, 0);
								error = TRUE;
								break;
							}
							break;
						case 2:
							if ( ( 0x7F ) < ptr_uartStruct->Adresse )
							{
								uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_adresse_is_too_long, 0, NULL, 0);
								error = TRUE;
								break;
							}
							break;
						
						case 3:

							if ( ( 8 ) < ptr_uartStruct->Uart_Length )
							{
								uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_length_is_too_long, 0, NULL, 0);
								error = TRUE;
								break;
							}
							break;
						case 4:
						case 5:
						case 6:
						case 7:
						case 8:
						case 9:
						case 10:
						case 11:
							for ( uint8_t i = 0 ; i < 8 ; i++ )
							{
								if ( ( 0XFF ) < ptr_uartStruct->Uart_Data[i] )
								{
									uart_errorCode = CommunicationError(ERRA, SERIAL_ERROR_data_0_is_too_long + i, 0, NULL, 0);
									ptr_uartStruct->Uart_Data[i] = 0;
									error = TRUE;
									break;
								}
							}
							break;
						}

					}
				}
				break;
				default: /*uncovered command keys*/
					break;
				}
			}//ENde else

			if ( TRUE == error )
			{
				Reset_UartStruct(ptr_uartStruct);
				Reset_SetParameter();
				return 1;
			}
			else
			{
				return 0;
			}
		}//END of Check_Error function


/*
 *this function calls another function in relation to the first parameter of the string
 *the function has a pointer of the serial structure as input and returns no parameter
 */

void Choose_Function( struct uartStruct *ptr_uartStruct )
{
	switch (ptr_uartStruct->commandKeywordIndex)
	{
	case commandKeyNumber_TWIS:
	{
		Convert_UartData_to_UartStruct(setParameter);
		if (TRUE == Check_Parameter_CanFormat(ptr_uartStruct))
		{
			switch ( ptr_uartStruct->commandKeywordIndex )
			{
			case commandKeyNumber_TWIS:
				/* command :TWIS:Read/write  Adresse  length  Data[0...7] */
				if ( 0 == ptr_uartStruct->Command_typ )
				{
					Write_to_slave(ptr_uartStruct);
				}
				else
				{
					Read_to_slave(ptr_uartStruct);
				}
				break;
			}
		}
		else { Check_Error(ptr_uartStruct);}
	}
	break;
	case commandKeyNumber_RSET:
		Initialization();
		snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("RECV %s"), READY);
	        UART0_Send_Message_String(NULL,0);
		break;
    default:
		ptr_uartStruct->commandKeywordIndex = -1;
		Check_Error(ptr_uartStruct);
		break;
	}
	return;
}//END of Choose function


/* interrupt for receive  data via serial communication with defined interrupt vector SIG_UART0_RECV */
ISR (SIG_UART0_RECV)
{

	unsigned char c = UDR0;

	if ( c == '\n' ) /* the string is complete? */
	{

		uartString[nextCharPos] = '\0';
		uartReady = 1; /* mark, that we got an CAN_interrupt, to be handled by main */
		nextCharPos = 0;
	}

	else
	{
		uartString[nextCharPos] = c;
		nextCharPos++;
		uartString[nextCharPos] = '\0';
	}
}//END of ISR (SIG_UART0_RECV)


/* interrupt for receive data via CAN communication with defined interrupt vector CANIT_vect */



/*
 *USART0 must be initialized before using this function
 *for use this function, be sure that data is no longer then 8 bit
 *(single character) this function will send  8 bits from the at90can128
 */

#warning add timeout ? Add check for USART0 init ?

void UART0_Transmit( uint8_t data )
{
	/* wait for empty transmit buffer */
	while ( !( UCSR0A & ( 1 << UDRE0 ) ) )
	{
		/* do nothing*/
	}
	/* put the data into the buffer */

	UDR0 = data;
}

/*
 *this function sends a string to serial communication
 * the input parameter is a defined global variable tmp_str
 * the output parameter is an integer
 * 0 -> the message is sent
 */

int16_t UART0_Send_Message_String( char *tmp_str, uint16_t maxSize )
{
   /* this function sends the string pointed to by tmp_str to UART
    * this happens char by char until STRING_END is found
    * afterwards the message string is cleared up to the size maxSize
    *
    * if tmp_str is NULL
    *    - tmp_str is set to the global variable uart_message_string
    *    - and maxSize is set to BUFFER_SIZE
    * else if maxSize is 0
    *    - maxSize is assumed to be BUFFER_SIZE
    *
    * returns
    *   - in case of errors: -1
    *   - else number of transfered characters (max INT16_MAX )
    *
    * */

   /* if tmp_str is NULL, take as default uart_message_string and its size BUFFER_SIZE */
   if (NULL == tmp_str)
   {
      if (NULL != uart_message_string)
      {
         tmp_str = uart_message_string;
         maxSize = BUFFER_SIZE;
      }
      else
      {
         return -1;
      }
   }

   /* if maxSize is set to 0, take default value BUFFER_SIZE */
   if ( 0 == maxSize)
   {
      maxSize = BUFFER_SIZE;
   }

   static uint16_t index;

   for ( index = 0; STRING_END != tmp_str[index] && index < maxSize ; index++ )
   {
      UART0_Transmit(tmp_str[index]);
   }
   UART0_Transmit('\n');
   clearString(tmp_str, maxSize); /*clear tmp_str variable*/

   return index;
}//END of UART0_Send_Message_String function


/*
 *this function sends a string to serial communication
 * the input parameter is a defined global variable tmp_str
 * the output parameter is an integer
 * 0 -> the message is sent
 * only use for the function owiFindFamilyDevicesAndAccessValues in one_wire.c
 */
int8_t UART0_Send_Message_String_woLF( char *tmp_str, uint32_t maxSize )
{
	for ( uint16_t j = 0 ; j < strlen((char *) tmp_str) && j < maxSize ; j++ )
	{
		UART0_Transmit(tmp_str[j]);
	}

	clearString(tmp_str, maxSize); /*clear tmp_str variable*/
	return 0;
}//END of UART0_Send_Message_String_woLF


uint8_t CommunicationError( uint8_t errorType, const int16_t errorIndex, const uint8_t flag_printCommand, const prog_char *alternativeErrorMessage, const int16_t alternativeErrorNumber)
{
/* This (new) Communication Error function
 * sends a ((partly) predefined) error message to UART
 *
 * output: ERRG/T/U/A/M <error number> <error message> [<alternative/extra Error> <alternative/extra number>]
 * output: ERRA/T/U/A/M "<command key> <command arguments>" --- <error number> <error message>
 *
 * arguments:
 *    - Error type: defines the error class the error belongs to (ERRG, ERRA, ERRM, ERRC, ERRU)
 *      - use enums as input
 *        
 *         - ERRA: API specific
 *            - considered to be specific to a certain command call,
 *              therefore it delivers in addition to the error message, the calling command string
 *         - ERRT: TWI specific errors
 *            - if considered to be specific to a certain command call,
 *              then it delivers in addition to the error message, the calling command string
 *         - ERRU: undefined errors
 *      - if  Error_typ > ERRU, Error_typ = ERRU
 *    - Error_Index: selection index of predefined error messages
 *      - if index > MAX_INDEX or 0 > index, the next arguments are used
 *    - flag_printCommand
 *      - if 0 do nothing
 *      - else add command sequence to error message
 *    - alternativeErrorMessage: message to be printed/attached if Error_Index exceeds limits / else
 *       - by default prog_char, i.e. FLASH data (otherwise see below)
 *    - alternativeErrorNumber :  number to be printed/attached if Error_Index exceeds limits / else
 *       - if this value is less than COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD:
 *            value < COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD,
 *            then instead of the text the global variable message is used
 *
 * returns:
 *    - 0 , if all o.k.
 *    - <> 0, else
 * */

    unsigned char flag_UseOnlyAlternatives = FALSE;
    unsigned char errmax[4];
    errmax[ERRA] = SERIAL_ERROR_MAXIMUM_INDEX;
    errmax[ERRT] = TWI_ERROR_MAXIMUM_INDEX;
  
    /* checking error type */
    if ( ERR_MAXIMUM_NUMBER <= errorType )
    {
       errorType = ERRU; /* set to undefined error */
    }

/* checking error index */
    switch(errorType)
    {
       case ERRA:
       case ERRT:
          if (0 > errorIndex || errmax[errorType] <= errorIndex)
          { flag_UseOnlyAlternatives = TRUE; }
          break;
       case ERRU:
          flag_UseOnlyAlternatives = TRUE;
          break;
       default:
          if ( eventDebug <= debug )
          {
             for ( int clearIndex = 0 ; clearIndex < BUFFER_SIZE ; clearIndex++ )
             {
                message[clearIndex] = STRING_END;
             }
              snprintf_P(message, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) CommunicationError wrong error index ... returning"), __LINE__, __FILE__);
              UART0_Send_Message_String(message,BUFFER_SIZE);
          }
          return 1; /*shouldn't happen*/
          break;
    }

    /* check alternative pointer, return if empty*/
    if ( TRUE == flag_UseOnlyAlternatives && NULL == alternativeErrorMessage && COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD <= alternativeErrorNumber)
    {
          if ( eventDebug <= debug )
          {
             for ( int clearIndex = 0 ; clearIndex < BUFFER_SIZE ; clearIndex++ )
             {
                message[clearIndex] = STRING_END;
             }
             snprintf_P(message, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) CommunicationError alternatives: NULL ... returning"), __LINE__, __FILE__);
             UART0_Send_Message_String(message,BUFFER_SIZE);
          }
          return 1;
    }

    /* compose message
     * output: ERRG/C/U/A/M <error number> <error message> [<alternative/extra Error> <alternative/extra number>]
     * output: ERRA/C/U/A/M "<command key> <command arguments>" --- <error number> <error message>
     * */
    /* clear string*/
    clearString(uart_message_string, BUFFER_SIZE);

    /* cat Error Type */
    strncat_P(uart_message_string, (const char*) (pgm_read_word( &(errorTypes[errorType]))) ,BUFFER_SIZE - 1 );

    /* "<command key> <command arguments>" */
    if ( TRUE == flag_printCommand)
    {
       /* no command string parsing yet*/
       if ( STRING_END != decrypt_uartString[0]) /*assume decrypt_uartString  not to be empty */
       {
          strncat_P(uart_message_string, PSTR(" \""), BUFFER_SIZE -1 );
          strncat  (uart_message_string, decrypt_uartString, BUFFER_SIZE -1 );
          strncat_P(uart_message_string, PSTR("\""), BUFFER_SIZE -1 );
       }
       else /* command string already parsed: setParameter available */
       {
          uint8_t index=0;
          strncat_P(uart_message_string, PSTR(" \""), BUFFER_SIZE -1 );

          while (index < MAX_PARAMETER && NULL != setParameter[index] && STRING_END != setParameter[index][0])
          {
             snprintf_P(uart_message_string, BUFFER_SIZE -1 , PSTR("%s%s%s"), uart_message_string, (0 == index)?"":" ", &setParameter[index][0]);
             index++;
          }
          snprintf_P(uart_message_string, BUFFER_SIZE -1 , PSTR("%s\" ---"), uart_message_string);
       }
    }

    if ( FALSE == flag_UseOnlyAlternatives )
    {
       switch (errorType)
       {
          
          case ERRA:
             snprintf_P(uart_message_string, BUFFER_SIZE -1 , PSTR("%s %i "), uart_message_string, serial_error_number[errorIndex]);
             strncat_P(uart_message_string, (const char*) (pgm_read_word( &(serial_error[errorIndex]))), BUFFER_SIZE -1);
             break;
          case ERRT:
             snprintf_P(uart_message_string, BUFFER_SIZE -1 , PSTR("%s %i "), uart_message_string, twi_error_number[errorIndex]);
             strncat_P(uart_message_string, (const char*) (pgm_read_word( &(twi_error[errorIndex]))), BUFFER_SIZE -1);
             break;
          default:
             if ( eventDebug <= debug )
             {
                for ( int clearIndex = 0 ; clearIndex < BUFFER_SIZE ; clearIndex++ )
                {
                   message[clearIndex] = STRING_END;
                }
                snprintf_P(message, BUFFER_SIZE - 1, PSTR("DEBUG (%4i, %s) CommunicationError wrong error type %i... returning"), __LINE__, __FILE__, errorType);
                UART0_Send_Message_String(message,BUFFER_SIZE);
             }
             return 1;
             break;
       }
    }

    if ( NULL != alternativeErrorMessage || COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD > alternativeErrorNumber)
    {
       if (TRUE == flag_UseOnlyAlternatives)
       {
          snprintf_P(uart_message_string,  BUFFER_SIZE - 1 , PSTR("%s %i "), uart_message_string, alternativeErrorNumber);
       }
       else
       {
          strncat_P(uart_message_string, PSTR(" *** "), BUFFER_SIZE -1);
       }

       /* if alternativeErrorIndex is smaller then COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD use global message variable instead*/
       if ( COMMUNICATION_ERROR_USE_GLOBAL_MESSAGE_STRING_INDEX_THRESHOLD > alternativeErrorNumber )
       {
          strncat(uart_message_string, message, BUFFER_SIZE -1);
       }
       else
       {
          strncat_P(uart_message_string, alternativeErrorMessage, BUFFER_SIZE -1);
       }
    }

    UART0_Send_Message_String(NULL,0);

    return 0;
}//END of CommunicationError function

/*
 this function initializes all init functions again and activates the interrupt
 */
void Initialization( void )
{
   /* disable interrupts*/
   cli();
 
   /* enable interrupts*/
   sei();

   UART0_Init();
#warning why twice TWI init?
   Twim_Init (250000);
   if(!Twim_Init (250000))
   {
	   twi_errorCode = CommunicationError(ERRT, TWI_ERROR_Error_in_initiating_TWI_interface, 0, NULL, 0);
   }
   clearString(currentResponseKeyword,MAX_LENGTH_KEYWORD);
   strncat_P(currentResponseKeyword, (const char*) ( pgm_read_word( &(responseKeywords[responseKeyNumber_RECV])) ), MAX_LENGTH_KEYWORD - 1);

}//END of Initialization


void clearUartStruct( struct uartStruct *ptr_uartStruct ) /* resets all values of uartStruct*/
{ /*resets the uartStruct structure to "0" */
   if ( NULL != ptr_uartStruct )
   {
      ptr_uartStruct->Command_typ = 0;
      ptr_uartStruct->Adresse = 0;
      ptr_uartStruct->Uart_Length = 0;
      ptr_uartStruct->commandKeywordIndex = 0;
      ptr_uartStruct->number_of_arguments = 0;
      for ( uint8_t clearIndex = 0 ; clearIndex < UART_MAX_DATA_ELEMENTS ; clearIndex++ )
      {
         ptr_uartStruct->Uart_Data[clearIndex] = 0;
      }
   }
}//END of clearuartStruct

/* creates the string "RECV <current command keyword> "
 * from the information of the uart struct
 * input:
 *    ptr_myUartStruct:
 *       pointer to the uart struct
 *       - if NULL, set to ptr_uartStruct global variable
 *    message_string:
 *       pointer to char array where the created message should be stored
 *       - if NULL, set to uart_message_string global variable
 *    size:
 *       maximum size of message_string
 *       - if 0, set to BUFFER_SIZE
 * return:
 *  always: 0
 */

uint8_t createReceiveHeader( struct uartStruct *ptr_myUartStruct, char message_string[], uint16_t size )
{
   if (NULL == ptr_myUartStruct) {ptr_myUartStruct = ptr_uartStruct;}
   if (NULL == message_string) { message_string = uart_message_string; }
   if (0 == size) { size = BUFFER_SIZE; }
   clearString(message_string, size);
   strncat_P(message_string, (const char*) ( pgm_read_word( &(responseKeywords[responseKeyNumber_RECV])) ), size - 1);
   strncat_P(message_string, PSTR(" "), size - 1);
   strncat_P(message_string, (const char*) ( pgm_read_word( &(commandKeywords[ptr_myUartStruct->commandKeywordIndex])) ), size - 1);
   strncat_P(message_string, PSTR(" "), size - 1);
   return 0;
}

/*clear strings*/
uint16_t clearString( char mystring[], uint16_t length )
{
   if (NULL == mystring) {return 0;}
   uint16_t clearIndex = 0;
   for (; clearIndex < length ; clearIndex++) {mystring[clearIndex] = STRING_END;}
   return clearIndex;
}

/*
 *this function toggles endlessly ! PINA3
 */

#warning TODO finish this function (pin_number and timeout/duration)
void toggle_pin( unsigned char pin_number )
{
   long int i, c, d;
   _delay_ms(10);

   for ( i = 0; i <= 50 ; i++ )
   {
      _delay_ms(10);
      d = d + i * c;
      c = d + i;
   }
   /*toggle FrontLED*/

   PINA = 0x3;
}//END of toggle_pin function


/*
 * adds to the normal receive header created internally the additional command key word of sub command
 * input: uart container
 *  - key index number of primary command, or -1 for current
 *  - command Keyword of sub command
 */

void createExtendedSubCommandReceiveResponseHeader(struct uartStruct * ptr_uartStruct,
                                                   int8_t keyNumber, int8_t index,  const prog_char* commandKeywords[])
{
   /* make sure keyNumber is shown */
   int8_t keywordIndex = ptr_uartStruct->commandKeywordIndex;
   if (0 <= keyNumber) {ptr_uartStruct->commandKeywordIndex = keyNumber;}

   createReceiveHeader(ptr_uartStruct, uart_message_string, BUFFER_SIZE);
   /* reset index to original value */
   ptr_uartStruct->commandKeywordIndex = keywordIndex;

   strncat_P(uart_message_string, (const char*) ( pgm_read_word( &(commandKeywords[index])) ), BUFFER_SIZE - 1);
   strncat_P(uart_message_string, PSTR(" "), BUFFER_SIZE - 1);
}


/*
 * getNumericLength(const char *string, const uint16_t maxLenght)
 *
 * return number of leading characters of string
 * being an digit (0x/0X of hex numbers are ignored) up to the maximum maxLength-1
 */

uint16_t getNumericLength(const char string[], const uint16_t maxLenght)
{
    /* check if argument contains of digits */
    uint16_t index = 0;
    if (
             0 == strncmp_P( string, PSTR("0x"),2) ||
             0 == strncmp_P( string, PSTR("0X"),2)
        )
    {
       index = 2;
    }

    /* calculate length of argument and check if all of them are hex numbers */
    while (index < maxLenght && isxdigit(string[index])) {index++;}

    return index;
}
