/*
 * VERSION 1.0 Januar 7th 2010 LATE  File: 'can.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 "one_wire.h"
#include "one_wire_adc.h"
#include "one_wire_dualSwitch.h"
#include "one_wire_simpleSwitch.h"
#include "read_write_register.h"
#include "one_wire_temperature.h"

#include "adc.h"
#include "api.h"
#include "api_define.h"
#include "api_global.h"
#include "can.h"
#include "mem-check.h"

/*variable to subscribe and unsubcribe some messages via CAN bus */
uint16_t subscribe_ID[MAX_LENGTH_SUBSCRIBE];
uint16_t subscribe_mask[MAX_LENGTH_SUBSCRIBE];

/*
 * this function will read certain messages on the bus
 * the function has a pointer of the serial structure as input and returns no parameter
 */

void Subscribe_Message( struct uartStruct *ptr_uartStruct )
{
   int8_t findMob;
   uint8_t equality = 1;

   for ( uint8_t count_subscribe = 2 ; count_subscribe <= 14 ; count_subscribe++ )
   {
      if ( ( ptr_uartStruct->Uart_Message_ID ) == ( subscribe_ID[count_subscribe] ) && ( ptr_uartStruct->Uart_Mask ) == ( subscribe_mask[count_subscribe] ) )
      {
         equality = 0;
         mailbox_errorCode = CommunicationError(ERRM, MOB_ERROR_this_message_already_exists, 0, NULL, 0);
      }
   }
   if ( 1 == equality )
   {
      subscribe_ID[ptr_subscribe] = ( ptr_uartStruct->Uart_Message_ID );
      subscribe_mask[ptr_subscribe] = ( ptr_uartStruct->Uart_Mask );
      ptr_subscribe++;

      findMob = Get_FreeMob();

      if ( 14 < ptr_subscribe )
      {
         ptr_subscribe = 2;
      }

      if ( ( -1 ) == findMob )
      {
         mailbox_errorCode = CommunicationError(ERRM, MOB_ERROR_all_mailboxes_already_in_use, 0, NULL, 0);
      }
      else
      {
         CANPAGE = ( findMob << MOBNB0 );
         CANSTMOB = 0x00; /* cancel pending operation */
         CANCDMOB = 0x00;
         CANHPMOB = 0x00; /* enable direct mob indexing */

         if ( ( ( MAX_ELF_BIT ) >= ( ptr_uartStruct->Uart_Message_ID ) ) || ( ( MAX_ELF_BIT ) >= ( ptr_uartStruct->Uart_Mask ) ) )
         {
            /*set identifier to send*/
            CANIDT2 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 5;
            CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 3;
            /* enable comparison*/
            CANIDM4 = ( 1 << RTRMSK );

            /* set identifier Mask*/
            CANIDM2 = ( ( ptr_uartStruct->Uart_Mask ) & 0x7 ) << 5;
            CANIDM1 = ( ptr_uartStruct->Uart_Mask ) >> 3;
         }
         else
         {
            /*set identifier to send  */
            CANIDT4 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 3;
            CANIDT3 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
            CANIDT2 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
            CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 3;
            /*set identifier mask  */
            CANIDM4 = ( ( ptr_uartStruct->Uart_Mask ) & 0x7 ) << 3;
            CANIDM3 = ( ptr_uartStruct->Uart_Mask ) >> 5;
            CANIDM2 = ( ptr_uartStruct->Uart_Mask ) >> 5;
            CANIDM1 = ( ptr_uartStruct->Uart_Mask ) >> 3;
         }
         CANCDMOB = ( 1 << CONMOB1 ); /* enable reception mode */
         unsigned mask = 1 << findMob;
         CANIE2 |= mask;
         CANIE1 |= ( mask >> 8 );
      }
   }
}//END of Subscribe_Message function


/*
 * this function does not read certain messages on the bus
 *the function has a pointer of the serial structure as input and returns no parameter
 */

void Unsubscribe_Message( struct uartStruct *ptr_uartStruct )
{
   uint8_t inequality = 1;

   for ( uint8_t count_mob = 2 ; count_mob <= 14 ; count_mob++ )
   {
      CANPAGE = ( count_mob << MOBNB0 );

      if ( ((( CANIDT2 >> 5 ) | ( CANIDT1 << 3 ) ) == ptr_uartStruct->Uart_Message_ID ) &&
           ((( CANIDM2 >> 5 ) | ( CANIDM1 << 3 ) ) == ptr_uartStruct->Uart_Mask )         )
      {
         CANSTMOB = 0x00; /* cancel pending operation */
         CANCDMOB = 0x00; /* very important,that disable MOB*/
         CANHPMOB = 0x00;
         CANIDM1 = 0X00;
         CANIDM2 = 0X00;
         CANIDT1 = 0X00;
         CANIDT2 = 0X00;
         unsigned mask = 1 << count_mob;
         CANIE2 &= ~mask;
         CANIE1 &= ~( mask >> 8 );
         inequality = 0;
         for ( int count_subscribe = 2 ; count_subscribe <= 14 ; count_subscribe++ )
         {
            if ( ( ( ptr_uartStruct->Uart_Message_ID ) == ( subscribe_ID[count_subscribe] ) ) && ( ( ( ptr_uartStruct->Uart_Mask )
                     == ( subscribe_mask[count_subscribe] ) ) ) )
            {
               subscribe_ID[count_subscribe] = 0;
               subscribe_mask[count_subscribe] = 0;
            }
         }
      }
   }
   if ( 1 == inequality )
   {
      mailbox_errorCode = CommunicationError(ERRM, MOB_ERROR_message_ID_not_found, 0, NULL, 0);
   }
} //END of Unsubscribe_Message


/*
 * this function runs a command and expects no data
 *the function has a pointer of the serial structure as input and returns no parameter
 */

void Send_Message( struct uartStruct *ptr_uartStruct )
{

	CANPAGE = ( 1 << MOBNB0 );/*set channel number  */
	CANIDT4 = ( ptr_uartStruct->Uart_Rtr << RTRTAG ); /* enable remote transmition request */
	CANCDMOB = ( ptr_uartStruct->Uart_Length << DLC0 ); /* set lenght of data*/

	if ( ( MAX_ELF_BIT ) >= ( ptr_uartStruct->Uart_Message_ID ) )
	{
		CANCDMOB |= ( 0 << IDE ); /* enable CAN standard 11 bit */
		/*set Identifier to send */
		CANIDT2 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 5;
		CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 3;
	}
	else
	{
		CANCDMOB |= ( 1 << IDE ); /* enable CAN standard 29 bit */
		/*set Identifier to send  */
		CANIDT2 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 3;
		CANIDT2 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
		CANIDT2 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
		CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
	}

	/*put data in mailbox*/
	for ( uint8_t count_data = 0 ; count_data < 8 ; count_data++ )
	{
		CANMSG = ptr_uartStruct->Uart_Data[count_data];
	}

	CANSTMOB = 0x00;
	CANCDMOB |= ( 1 << CONMOB0 ); /*enable transmition mode*/
	/*call the function verify that the sending of data is complete*/
	Wait_for_Can_Send_Message_Finished();
}//END of Send_Message function

/*
 * this function runs a command and expects data
 * the function has a pointer of the serial structure as input and returns no parameter
 */

void Receive_Message( struct uartStruct *ptr_uartStruct )
{
	CANPAGE = ( 0 << MOBNB0 );/*set channel number */
	CANSTMOB = 0x00; /* cancel pending operation */
	CANCDMOB = 0x00;
	CANIDT4 = ( ptr_uartStruct->Uart_Rtr << RTRTAG ); /* enable remote transmission request */
	CANCDMOB = ( ptr_uartStruct->Uart_Length << DLC0 ); /* set length of data*/

	if ( ( ( MAX_ELF_BIT ) >= ( ptr_uartStruct->Uart_Message_ID ) )
			|| ( ( MAX_ELF_BIT ) >= ( ptr_uartStruct->Uart_Mask ) ) )
	{
		CANCDMOB |= ( 0 << IDE ); /* enable CAN standard 11 bit */
		/*set Identifier to send */
		CANIDT2 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 5;
		CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 3;
		/*set Mask to receive only Message */
		CANIDM1 = 0xFF;
		CANIDM2 = 0xFF;
		CANIDM3 = 0xFF;
		CANIDM4 = 0xFF;
	}
	else
	{
		CANCDMOB |= ( 1 << IDE ); /* enable CAN standard 29 bit */
		/*set Identifier to send  */
		CANIDT2 = ( ( ptr_uartStruct->Uart_Message_ID ) & 0x7 ) << 3;
		CANIDT2 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
		CANIDT2 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
		CANIDT1 = ( ptr_uartStruct->Uart_Message_ID ) >> 5;
	}

	/* put data in mailbox*/
	for ( uint8_t count_data = 0 ; count_data < 8 ; count_data++ )
	{
		CANMSG = ptr_uartStruct->Uart_Data[count_data];
	}
	CANSTMOB = 0;

	CANCDMOB |= ( 1 << CONMOB0 ); /*enable transmition mode*/

	/*call the function verify that the sending of data is complete*/
	Wait_for_Can_Receive_message_Finished();

}//END of Receive_Message function

/*
 *this function wait until the command is sent
 *the function has no input and output parameter
 */
void Wait_for_Can_Send_Message_Finished( void )
{
	double can_timeout1 = TIMEOUT_C; /*Timeout for CAN-communication*/
	while ( !( CANSTMOB & ( 1 << TXOK ) ) && ( --can_timeout1 > 0 ) )
	{
		/* do nothing  */
	}
	if ( 1 >= can_timeout1 )
	{
		can_errorCode = CommunicationError(ERRC, CAN_ERROR_timeout_for_CAN_communication, 0, NULL, 0);
		can_timeout1 = TIMEOUT_C;
	}

	CANSTMOB &= ~( 1 << TXOK ); /* reset transmition flag */
	CANCDMOB &= ~( 1 << CONMOB0 ); /* disable transmition mode */
	snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("RECV %s"), READY);
	UART0_Send_Message_String(NULL,0);
	/* all parameter initialisieren */
	Reset_Parameter_CANSend_Message();

}//END of Wait_for_Can_Send_Message_Finished


/*
 *this function wait until the command in case the request is sent
 *the function has no input and output parameter
 */

void Wait_for_Can_Receive_message_Finished( void )
{

	double can_timeout2 = TIMEOUT_C; /*Timeout for CAN-communication*/
	while ( !( CANSTMOB & ( 1 << RXOK ) ) && ( --can_timeout2 > 0 ) )
	{
		/* do nothing  */
	}

	if ( ( 1 >= can_timeout2 ) && ( CANSTMOB & ( 1 << TXOK ) ) )
	{
		can_errorCode = CommunicationError(ERRC, CAN_ERROR_timeout_for_CAN_communication, 0, NULL, 0);
		can_timeout2 = TIMEOUT_C;
	}
	else
	{
		CANSTMOB &= ~( 1 << TXOK ); /* reset transmition flag */
		CANCDMOB &= ~( 1 << CONMOB0 ); /* disable transmition mode */
	}

	/* all parameter initialisieren */
	Reset_Parameter_CANSend_Message();

}//END of Wait_for_Can_Receive_message_Finished function

/*
 *This function grabs the CAN data received in a string
 *the function has a poimter of the CAN structur as input and returns no parameter
 */

void Convert_pack_canFrame_to_UartFormat( struct canStruct *ptr_canStruct )
{
	uint16_t pack_canFrame[11];/* variable for storage received a complete CAN-Frame via CAN-Bus */
	uint8_t ptr_pack_canFrame = 3; /*pointer to receive CAN-data */
	char temp_canString[MAX_LENGTH_CAN_DATA];/*temporary variable for storage received CAN data*/
	char tmp_str[BUFFER_SIZE];

	pack_canFrame[0] = ptr_canStruct->Can_Mob;
	pack_canFrame[1] = ptr_canStruct->Can_Message_ID;
	pack_canFrame[2] = ptr_canStruct->Can_Length;

	for ( uint8_t count_can_data = 0 ; count_can_data < 8 ; count_can_data++ )
	{
		pack_canFrame[ptr_pack_canFrame] = ptr_canStruct->Can_Data[count_can_data];
		ptr_pack_canFrame++;
	}

	/* grabs the received data in a string */
	for ( uint8_t i = 0 ; i < 11 ; i++ )
	{
		snprintf_P(tmp_str, BUFFER_SIZE - 1, PSTR("%x"), pack_canFrame[i]);
		strncat(temp_canString, tmp_str, BUFFER_SIZE - 1); /* the next word attach the rear */
		strncat_P(temp_canString, PSTR(" "), BUFFER_SIZE - 1); /* insert space*/
	}

	strncat_P(canString, PSTR("RECV"), BUFFER_SIZE - 1);
	strncat_P(canString, PSTR(" "), BUFFER_SIZE - 1);
	strncat(canString, temp_canString, BUFFER_SIZE - 1);
	snprintf_P(uart_message_string, BUFFER_SIZE - 1, PSTR("%s"), canString);
	UART0_Send_Message_String(NULL,0);
	clearCanStruct(ptr_canStruct); /*clear Can-structure*/
	clearString(canString, MAX_LENGTH_CAN_DATA); /*clear the variable CanString */
	clearString(temp_canString, MAX_LENGTH_CAN_DATA); /*clear the variable temp_canString*/
	/*all parameter initialisieren*/
	Reset_Parameter_CANReceive();
}//END of Convert_pack_canFrame_to_UartFormat function

/*
 *this function deletes some variable
 *the  function has no input and output variable
 */

void Reset_Parameter_CANSend_Message( void )
{
	/* all parameter initialisieren */
	clearString(decrypt_uartString, BUFFER_SIZE);
	clearString(uart_message_string, BUFFER_SIZE);
	clearUartStruct(ptr_uartStruct);

}//END of Reset_Parameter_CANSend_Message


/*
 *this function deletes some variable
 *the  function has no input and output parameters
 */

void Reset_Parameter_CANReceive( void )
{

	/* initialize all parameters of structure  */
	//memset(ptr_canStruct, 0, sizeof(struct canStruct));
	clearCanStruct(ptr_canStruct);
}//END of Reset_Parameter_CANReceive function


/*
 *this function deletes some variable
 *the  function has no input and output parameters
 */

void clearCanStruct( struct canStruct *ptr_canStruct)
{ /*resets the canStruct structure to "0" */
   if ( NULL != ptr_canStruct )
   {
      ptr_canStruct->Can_Length = 0;
      ptr_canStruct->Can_Mask = 0;
      ptr_canStruct->Can_Message_ID = 0;
      ptr_canStruct->Can_Mob = 0;
      for ( uint8_t clearIndex = 0 ; clearIndex < CAN_MAX_DATA_ELEMENTS ; clearIndex++ )
      {
         ptr_canStruct->Can_Data[clearIndex] = 0;
      }
   }
}//END of clearCanStruct

