/*
 * UART_API_Layer.c
 *
 * Created: 27.2.2016 19:04:32
 *  Author: Chenda
 */ 

#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>

#include "../API_common_defs.h"
#include "../../common/DataOperations.h"
#include "../../common/PeipherialFunctions.h"

#include "UART_LinkLayer_V10.h"
#include "UART_NetworkLayer_V10.h"
#include "UART_API_Layer.h"

/************************************************************************/
/* Global variables                                                     */
/************************************************************************/
static struct stComAPI_layer stAPIL_UART0;
static struct stComAPI_layer *spAPI = &stAPIL_UART0;

static struct stLL_UARTx *spLL;
static struct stNL_UARTx *spNL;

static bool RespondExpected = false;
static uint8_t QueryCommand;

/************************************************************************/
/* Private functions prototypes                                         */
/************************************************************************/
void Send(void);
void Receive (void);

/************************************************************************/
/* Public functions                                                     */
/************************************************************************/
struct stComAPI_layer* UART_API_U0_INIT(void)
{
	spNL = UART_NL_U0_INIT();
	spLL = UART_NL_U0_GET_LL();
	spAPI->RX.Data = spNL->NL_Int.RX.Buff+2;	// points to 3rd position (1st data position)
	spAPI->TX.Data = spNL->NL_Int.TX.Buff+2;	// points to 3rd position (1st data position)
	
	return spAPI;
}

void UART_API_U0(void)
{
	spAPI->RX.Data = spNL->NL_Int.RX.Buff+2;	// points to 3rd position (1st data position)
	spAPI->TX.Data = spNL->NL_Int.TX.Buff+2;	// points to 3rd position (1st data position)
	UART_NL_U0();
	/* Receiver processing */
	if (spAPI->RX.Event <= API_RECEIVING)
	{
		switch(spNL->NL_Int.RX.Event) {
			case UART_NL_NO_ACTION:
				if (RespondExpected) {
					spAPI->RX.Event = API_RESP_WAITING;
				}
				else {
					spAPI->RX.Event = API_NO_ACTION;
				}
				break;
			case UART_NL_RECEIVING:
				spAPI->RX.Event = API_RECEIVING;
				break;
			case UART_NL_FOREIGN_MESS:
				spAPI->RX.Event = API_FOREIGN_MESS;
				Receive();
				break;
			case UART_NL_PUBLIC_MESS:
				spAPI->RX.Event = API_PUBLIC_MESS;
				Receive();
				break;
			case UART_NL_GROUP_MESS:
				spAPI->RX.Event = API_GROUP_MESS;
				Receive();
				break;
			case UART_NL_PRIVATE_MESS:
				spAPI->RX.Event = API_PRIVATE_MESS;
				Receive();
				break;
			case UART_NL_ERROR_REC:
				spAPI->RX.Event = API_ERROR;
				spAPI->RX.ErrorNumber = spNL->NL_Int.RX.E_Nr;
				spAPI->RX.DataLength = spNL->NL_Int.RX.Length;
				spAPI->RX.Command = QueryCommand;
				spAPI->RX.SourceAdd = spNL->NL_Int.RX.SenderAddress;
				spAPI->RX.TargetAdd = spNL->NL_Int.RX.RecipientAddress;
				break;
			default:
				break;
		}
		if (spNL->NL_Int.RX.Event > UART_NL_RECEIVING) {
			RespondExpected = false;
			spNL->NL_Int.RX.Event = UART_NL_NO_ACTION;
			
		}
	}
	
	/* Transmitter processing */
	switch(spNL->NL_Int.TX.Event) {
		case UART_NL_NO_ACTION:
			if (RespondExpected) {
				spAPI->TX.Event = API_WAIT_FOR_REC;
			}
			else if (spAPI->TX.Event == API_SEND) {
				Send();
			}
			else if (spAPI->TX.Event == API_SEND_ACK_NACK) {
				//spAPI->TX.DataLength = 0;
				Send();
			}
			else {
				spAPI->TX.Event = API_NO_ACTION;
			}
			break;
		case UART_NL_TRANSMITTING:
			spAPI->TX.Event = API_SENDING;
			break;
		case UART_NL_TRANSMITED:
			spNL->NL_Int.TX.Event = UART_NL_NO_ACTION;
			if (RespondExpected) {
				spAPI->TX.Event = API_WAIT_FOR_REC;
			}
			else {
				spAPI->TX.Event = API_NO_ACTION;
			}
			break;
		case UART_NL_ERROR_TRANS:
			spNL->NL_Int.TX.Event = UART_NL_NO_ACTION;
			spAPI->TX.Event = API_ERROR;
			spAPI->TX.Event = spNL->NL_Int.TX.E_Nr;
			RespondExpected = false;				// clearing expectation because message wasn't send
			break;
		default:
			break;
	}
}

/************************************************************************/
/* Private functions                                                    */
/************************************************************************/
void Send(void)
{
	// there is data to send
	spAPI->TX.Event = API_SENDING;
	if (spAPI->TX.CmdAckNack_type == API_ACK_MESS) {
		// ACK respond
		spNL->NL_Int.TX.Buff[0] = API_RESP_ACK_MARK;
	}
	if (spAPI->TX.CmdAckNack_type == API_NACK_MESS) {
		// NACK respond
		spNL->NL_Int.TX.Buff[0] = API_RESP_NACK_MARK;
	}
	if (spAPI->TX.CmdAckNack_type == API_CMD_MESS) {
		// command message
		spNL->NL_Int.TX.Buff[0] = spAPI->TX.Command;
	}
	spNL->NL_Int.TX.Buff[1] = spAPI->TX.DataLength;
	spNL->NL_Int.TX.Length = spAPI->TX.DataLength + 2;	// command + data length bytes 
	spNL->NL_Int.TX.RecipientAddress = spAPI->TX.TargetAdd;
	if (spAPI->TX.SourceAdd == 0) {
		// use periphery address
		spNL->NL_Int.TX.SenderAddress = spNL->NL.PeriphAddress;
	}
	else {
		spNL->NL_Int.TX.SenderAddress = spAPI->TX.SourceAdd;	
	}
	spNL->NL_Int.TX.ExpectRespond = spAPI->TX.ExpectRespond;
	RespondExpected = spAPI->TX.ExpectRespond;
	if (RespondExpected) {
		QueryCommand = spAPI->TX.Command;
		spAPI->RX.Event = API_RESP_WAITING;
	}
	else {
		QueryCommand = 0;
	}
	// API clearing 
	spAPI->TX.ExpectRespond = false;
	spAPI->TX.DataLength = 0;
	spAPI->TX.Command = 0;
}

void Receive (void)
{
	if (spNL->NL_Int.RX.Length < 2) {
		spNL->NL_Int.RX.Length = 2;
		spNL->NL_Int.RX.Buff[1] = 0;
	}
	if (spNL->NL_Int.RX.Buff[1] > (spNL->NL_Int.RX.Length - 2)) {
		spAPI->RX.DataLength = spNL->NL_Int.RX.Length-2;
	}
	else {
		spAPI->RX.DataLength = spNL->NL_Int.RX.Buff[1];
	}
	spAPI->RX.SourceAdd = spNL->NL_Int.RX.SenderAddress;
	spAPI->RX.TargetAdd = spNL->NL_Int.RX.RecipientAddress;
		
	if (RespondExpected && spNL->NL_Int.RX.Buff[0] == API_RESP_ACK_MARK) {
		// OK - successful respond
		spAPI->RX.CmdAckNack_type = API_ACK_MESS;
		spAPI->RX.Command = QueryCommand;
	}
	else if (RespondExpected && spNL->NL_Int.RX.Buff[0] == API_RESP_NACK_MARK) {
		// OK - unsuccessful respond
		spAPI->RX.CmdAckNack_type = API_NACK_MESS;
		spAPI->RX.Command = QueryCommand;
	}
	else if (RespondExpected){
		// ERROR - Expected respond but command message received
		spAPI->RX.CmdAckNack_type = API_CMD_MESS;
		spAPI->RX.Command = spNL->NL_Int.RX.Buff[0];
		spAPI->RX.ErrorNumber = API_E_NOT_RESP_MESS;
		spAPI->RX.Event = API_ERROR;
	}
	else if (spNL->NL_Int.RX.Buff[0] == API_RESP_NACK_MARK) {
		// ERROR - respond not expected but NACK respond message received	
		spAPI->RX.Command = 0;
		spAPI->RX.CmdAckNack_type = API_NACK_MESS;	
		spAPI->RX.ErrorNumber = API_E_NOT_CMD_MESS;
		spAPI->RX.Event = API_ERROR;
	}
	else if (spNL->NL_Int.RX.Buff[0] == API_RESP_ACK_MARK) {
		// ERROR - respond not expected but ACK respond message received
		spAPI->RX.Command = 0;
		spAPI->RX.CmdAckNack_type = API_ACK_MESS;
		spAPI->RX.ErrorNumber = API_E_NOT_CMD_MESS;
		spAPI->RX.Event = API_ERROR;
	}
	else {
		// OK - command message received
		spAPI->RX.CmdAckNack_type = API_CMD_MESS;
		spAPI->RX.Command = spNL->NL_Int.RX.Buff[0];
	}
}