/*==================================================================================================

FILE INFORMATION HEADER

USED IN PROJECT:			S1003065-01 PPS-TX/S1003067-01 PPS-RX software application
ITEM TYPE:					Source Code
ITEM NAME:					xlru_message_mng.h
ITEM DESCRIPTION:			This file contains the implementation of the class for handling messages between LCU/PPS/PSM and REP
TARGET:						ATSAM4LC8B / ATSAM4LS8B
DOC REFERENCES:				SWDS1003065-01/SWDS1003065-01
PROGRAMMER NAME(S):			A.Chessa, L.Vallongo
COPYRIGHT:					LEONARDO-FINMECCANICA S.p.A
REVISION HISTORY:
- 01.00: first release

====================================================================================================
© Copyright LEONARDO S.p.A.. All rights reserved
Any right of industrial and intellectual property on this document,
and of technical Know-how herein contained, belongs to
LEONARDO S.p.A. and/or third parties.
According to the law, it is forbidden to disclose, reproduce or however
use this document and any data herein contained for any use without
previous written authorization by LEONARDO S.p.A.
==================================================================================================*/
#include <string.h>
#include "xlru_message_mng.h"
#include "xlru_message_def.h"
#include "xlru_common_func.h"

#include "xlru_log.h"

using namespace xlru;

#define MESSAGE_VALID 		1
#define MESSAGE_NOT_VALID 	0

char*  xlru_send_lcu_set_message(void)
{
	char *pMessage = (char*)"";

	xlru_lcu::lcu_reset_buffer_TX_RX();

	pMessage = xlru_lcu::lcu_set_message_master();

	return pMessage;
}

char*  xlru_send_lcu_test_status_message(void)
{
	char *pMessage = (char*)"";

	xlru_lcu::lcu_reset_buffer_TX_RX();

	pMessage = xlru_lcu::lcu_set_test_status_master();

	return pMessage;
}

char*  xlru_send_lcu_get_message(void)
{
	char *pMessage = (char*)"";

	xlru_lcu::lcu_reset_buffer_TX_RX();

	pMessage = xlru_lcu::lcu_get_message_master();

	return pMessage;
}

char*  xlru_send_pps_set_message(void)
{
	char *pMessage = (char*)"";

	xlru_pps::pps_reset_buffer_TX_RX();

	pMessage = xlru_pps::pps_set_message_master();

	return pMessage;
}

char*  xlru_send_pps_test_status_message(void)
{
	char *pMessage = (char*)"";

	xlru_pps::pps_reset_buffer_TX_RX();

	pMessage = xlru_pps::pps_set_test_status_master();

	return pMessage;
}

char*  xlru_send_psm_set_message(void)
{
	char *pMessage = (char*)"";

	xlru_psm::psm_reset_buffer_TX_RX();

	pMessage = xlru_psm::psm_set_message_master();

	return pMessage;
}

/*char*  xlru_send_psm_test_status_message(void)
{
	char *pMessage = (char*)"";

	xlru_psm::psm_reset_buffer_TX_RX();

	pMessage = xlru_psm::psm_set_test_status_master();

	return pMessage;
}*/


char*  xlru_send_lcu_reset_eti_message(void)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_reset_eti_message_master();

    return pMessage;
}

char*  xlru_send_lcu_active_download_message(void)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_active_download_message_master();

    return pMessage;
}

char*  xlru_send_lcu_sw_status_message(void)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_sw_status_message_master();

    return pMessage;
}


char* xlru_send_lcu_override_set_value_message(lcu_override_param_id_t _param_id,int _value)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_override_set_value_message(_param_id, _value);

    return pMessage;
}

char* xlru_send_lcu_override_get_value_message(lcu_override_param_id_t _param_id)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_override_get_value_message(_param_id);

    return pMessage;
}

char* xlru_send_lcu_override_get_factory_message(lcu_override_param_id_t _param_id)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_override_get_factory_message(_param_id);

    return pMessage;
}

char* xlru_send_lcu_override_set_to_factory_message(lcu_override_param_id_t _param_id)
{
    char *pMessage = (char*)"";

    xlru_lcu::lcu_reset_buffer_TX_RX();

    pMessage = xlru_lcu::lcu_override_set_to_factory_message(_param_id);

    return pMessage;
}

void set_correct_last_error(char* msg, char device)
{
	switch (device)
	{
		case DSTID_LCU:
			xlru_lcu::xlru_set_last_error(msg);
			break;
		case DSTID_PPS:
			xlru_pps::xlru_set_last_error(msg);
			break;
		case DSTID_PSM:
			xlru_psm::xlru_set_last_error(msg);
			break;
		default:	//ALL
			xlru_psm::xlru_set_last_error(msg);
			xlru_pps::xlru_set_last_error(msg);
			xlru_lcu::xlru_set_last_error(msg);
			break;
		}
}

//*******************************************************
//It analyzes the content of the message, extracts the id of the device from which it is sent and its consistency.
//Then it passes to the interpretation of the data contained in the payload
//return
//			0 all ok
//			1 error
int xlru_check_message(xlru_message_received_t *mess)
{
	mess->valid=false;

	//unsigned int master_failure=0;

	int failure = 0;

	//Check input string len

	mess->full_message[(sizeof mess->full_message)-1]=0;	//Simple overflow protection
	unsigned int len_mess=strlen(mess->full_message);
	if (len_mess<BUFFER_DIM_MIN_RESPONSE)
	{
		//message is too short to analyzed
		log_error(STR_TOO_SHOORT);
		set_correct_last_error((char*)STR_TOO_SHOORT, ' ');
		return DECODE_TOO_SHORT;
	}

    //check if in the message appears SOM_REPLY char -> "!"

    //char* start_message_to_decode=strchr(mess->full_message, SOM_REPLY);

    //if (start_message_to_decode==NULL)
    //{
    //SOM
    if (mess->full_message[SOM_INDEX]!=SOM_REPLY) 		//	"!", start response message
    {
		log_error(STR_NOT_SOM_REPLY);
		set_correct_last_error((char*)STR_NOT_SOM_REPLY, ' ');
		failure |= (1<<SOM_INDEX);
        return DECODE_NOT_VALID;
	}

	char fcs_prev = '\0';

	bool unit_id_ok=true;

	//DSTID, check which device response

	mess->device=0;

	char dst_id=mess->full_message[DSTID_INDEX];
	switch (dst_id)
	{
	case DSTID_LCU:
		mess->device = DSTID_LCU_INT;
		fcs_prev =  xlru_lcu::xlru_lcu_fcs_prev;
		xlru_lcu::xlru_counter.last_decode_error = 0;
		break;
	case DSTID_PPS:
		mess->device = DSTID_PPS_INT;
		fcs_prev =  xlru_pps::xlru_pps_fcs_prev;
		xlru_pps::xlru_counter.last_decode_error = 0;
		break;
	case DSTID_PSM:
		mess->device = DSTID_PSM_INT;
		fcs_prev =  xlru_psm::xlru_psm_fcs_prev;
		xlru_psm::xlru_counter.last_decode_error = 0;
		break;
	default:
		unit_id_ok=false;
		log_error(STR_DEVICE_NOT_CORRECT);
		failure |= (1<<DSTID_INDEX);
		set_correct_last_error((char*)STR_DEVICE_NOT_CORRECT, ' ');
		break;
	}

	//FCS, check message in order
	if(mess->full_message[FCS_INDEX] != fcs_prev)
	{
		log_error(STR_INDEX_MSG_WRONG);
		failure |= (1<<FCS_INDEX);
		set_correct_last_error((char*)STR_INDEX_MSG_WRONG, dst_id);
	}

	//ACK, check error flag
	char ackChar = mess->full_message[ACK_INDEX];
	switch (ackChar)
	{
		case ACK_NO_ERROR:
			//all ok
		break;
		case ACK_GENERIC_ERROR:
			//printf(STR_GENERIC_ERROR);
			//log_error(STR_GENERIC_ERROR);
			set_correct_last_error((char*)STR_GENERIC_ERROR, dst_id);
			//master_failure=1;
			break;
		case ACK_CHECKSUM_ERROR:
			//printf(STR_CHECKSUM_REC_ERROR);
			//log_error(STR_CHECKSUM_REC_ERROR);
			set_correct_last_error((char*)STR_CHECKSUM_REC_ERROR, dst_id);
			//master_failure=2;
			break;
		case ACK_PAYLOAD_ERROR:
			//printf(STR_PAYLOAD_ERROR);
			//log_error(STR_PAYLOAD_ERROR);
			set_correct_last_error((char*)STR_PAYLOAD_ERROR, dst_id);
			//master_failure=3;
		break;
		default:
			failure |= (1<<ACK_INDEX);
		break;
	}

	//control checksum
	//char ck_receive[3] = { 0 };
	char* eom=strchr(mess->full_message, '\r');
	if (eom)
	{
		len_mess = (eom-mess->full_message); //strlen(mess->full_message);

		//return unit_id_ok ? 0 : 100;
	}
	else
	{
		//use previous strlen()
	}

	//ck_receive[0] = mess->full_message[len_mess-2];
	//ck_receive[1] = mess->full_message[len_mess-1];

	//char payload[BUFFER_DIM] = {0};

	//strncpy (payload, mess->full_message, (len_mess-2));	//1 for CR + 2 for checksum digit = 3 digit.

	unsigned int checksum=0;
	bool ok=xlru::hex2u8(&checksum, &mess->full_message[len_mess-2]);
	if (!ok)
	{
		log_error("[%u] Checksum: invalid encoding (0x%2.2s)", mess->device, &mess->full_message[len_mess-3]);
		failure |= DEF_RX_CHECKSUM;
		set_correct_last_error((char*)"Checksum: invalid encoding",dst_id);
	}
	else
	{
		unsigned int checksum_rx = check_sum_calculus(mess->full_message, 0, len_mess-2);
		checksum_rx=checksum_rx & 0x0FF;
		if (checksum_rx!=checksum)
		{
			//log_error("[%u] Checksum error: calculated=0x%2X != 0x%2X", mess->device, checksum_rx, checksum_);
			log_error("[%u] 0x%2X -> %s", mess->device, checksum_rx, mess->full_message);
			failure |= DEF_RX_CHECKSUM;
			set_correct_last_error((char*)STR_CHECKSUM_ERROR,dst_id);

			switch (dst_id)
			{
				case DSTID_LCU:
					xlru_lcu::xlru_counter.checksum_error++;
					break;
				case DSTID_PPS:
					xlru_pps::xlru_counter.checksum_error++;
					break;
				case DSTID_PSM:
					xlru_psm::xlru_counter.checksum_error++;
					break;
				default:
					break;
			}
		}

	}

	strncpy(mess->payload, mess->full_message, (len_mess-2)); //strcpy(mess->payload, payload);
	mess->pos_checksum = len_mess-2;

	//fflush_stdout();

	int res = DECODE_NO_ERROR;

	//Analyze the payload.
	switch (mess->device)
	{
	case DSTID_LCU_INT:
		res = xlru_lcu::xlru_lcu_command_message_decoder(mess->payload);

		xlru_lcu::xlru_add_error(res);

		if (res==DECODE_TOO_SHORT)
		{
			//message is too short
			printf(STR_TOO_SHOORT);
			log_error("[%u] Message is too short", mess->device);
			failure |= DEF_TOO_SHORT;
			xlru_lcu::xlru_add_rx_error(1);
			xlru_lcu::xlru_add_rx(1);
			set_correct_last_error((char*)STR_TOO_SHOORT, dst_id);
		}
		else
		if (res>DECODE_TOO_SHORT)
		{
			printf(STR_ERROR_DECODING);
			log_error(STR_ERROR_DECODING, res);
			failure |= DEF_ERROR_DECODING;
			xlru_lcu::xlru_add_rx_error(1);
			xlru_lcu::xlru_add_rx(1);
			set_correct_last_error((char*)STR_ERROR_DECODING,dst_id);
		}
		else
		{
			xlru_lcu::xlru_add_rx(1);
		}
		break;
	case DSTID_PPS_INT:
		res = xlru_pps::xlru_pps_command_message_decoder(mess->payload);
		xlru_pps::xlru_add_error(res);

		if (res==DECODE_TOO_SHORT)
		{
			//message is too short
			printf(STR_TOO_SHOORT);
			log_error("[%u] Message is too short", mess->device);
			failure |= DEF_TOO_SHORT;
			xlru_pps::xlru_add_rx_error(1);
			xlru_pps::xlru_add_rx(1);
			set_correct_last_error((char*)STR_TOO_SHOORT, dst_id);
		}
		else
		if (res>DECODE_TOO_SHORT)
		{
			printf(STR_ERROR_DECODING);
			log_error(STR_ERROR_DECODING, res);
			failure |= DEF_ERROR_DECODING;
			xlru_pps::xlru_add_rx_error(1);
			xlru_pps::xlru_add_rx(1);
			set_correct_last_error((char*)STR_ERROR_DECODING,dst_id);
		}
		else
		{
			xlru_pps::xlru_add_rx(1);
		}
		break;
	case DSTID_PSM_INT:
		res = xlru_psm::xlru_psm_command_message_decoder(mess->payload);
		xlru_psm::xlru_add_error(res);

		if (res==DECODE_TOO_SHORT)
		{
			//message is too short
			printf(STR_TOO_SHOORT);
			log_error("[%u] Message is too short", mess->device);
			set_correct_last_error((char*)STR_TOO_SHOORT, dst_id);
			failure |= DEF_TOO_SHORT;
			xlru_psm::xlru_add_rx_error(1);
			xlru_psm::xlru_add_rx(1);
		}
		else
		if (res>DECODE_TOO_SHORT)
		{
			printf(STR_ERROR_DECODING);
			log_error(STR_ERROR_DECODING, res);
			set_correct_last_error((char*)STR_ERROR_DECODING,dst_id);
			failure |= DEF_ERROR_DECODING;
			xlru_psm::xlru_add_rx_error(1);
			xlru_psm::xlru_add_rx(1);
		}
		else
		{
			xlru_psm::xlru_add_rx(1);
		}
		break;
	default:
		break;
	}

	mess->valid=failure ? false : true;

	return unit_id_ok ? 0 : failure;	//all ok, 1 error
}




