/*
 * Command_proc.c
 *
 * Created: 20.3.2016 1:02:46
 *  Author: Chenda
 */ 

#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include "common/DataOperations.h"
#include "common/PeipherialFunctions.h"
#include "Command_defs.h"

// Config
#include "conf/config.h"
#include "conf/conf_brd.h"

/*  API  */
#include "modules/API_common_defs.h"
#include "modules/uart/UART_API_Layer.h"

//#include "DeviceAddresses.h"
#include "DebugSettings.h"
#include "DeviceStatus.h"
#include "TaskExecuter.h"
#include "Command_proc.h"

#include <stdio.h>
#include <avr/io.h>

/************************************************************************/
/* Global variable                                                      */
/************************************************************************/
static struct stApplicationStructure *spAPP;
static const char idn[] = IDENTIFICATION_DEVICE_STRING;

static int16_t TempIntNo;	
// static int16_t TempTenthNo;	
// static char buff[40];
/************************************************************************/
/* Private function prototypes                                          */
/************************************************************************/
// Command functions
void CMD_CORE_RESET (void);
void CMD_INST_SEL_PAR_QRY (void);
void CMD_SRC_IMM_CURR (void);
void CMD_SRC_IMM_CURR_QRY (void);
void CMD_SRC_IMM_VOLT (void);
void CMD_SRC_IMM_VOLT_QRY (void);
void CMD_MEAS_CURR_QRY (void);
void CMD_MEAS_VOLT_QRY (void);
void CMD_OUT_STAT (void);
void CMD_OUT_STAT_QRY (void);
void CMD_OUT_STAT_ALL (void);

void CMD_PING (void);
void CMD_GET_ERROR_QRY (void);

void NumericCmdHandling (int16_t *Int, int16_t *Tenth, bool Query);

/************************************************************************/
/* Public functions                                                     */
/************************************************************************/
void CMD_PROC_INIT(struct stApplicationStructure *spApplication)
{
	spAPP = spApplication;
}

void CMD_PROC_EXEC(void)
{	
	if (spAPP->CMD.CMD_No != NO_COMMAND) mStatusLed_On();
	
	if (spAPP->CMD.CMD_No == CORE_RESET) CMD_CORE_RESET();
	if (spAPP->CMD.CMD_No == ERROR_QRY) CMD_GET_ERROR_QRY();
	if (spAPP->CMD.CMD_No == INST_SEL_PAR_QRY) CMD_INST_SEL_PAR_QRY();
	if (spAPP->CMD.CMD_No == SRC_IMM_CURR) CMD_SRC_IMM_CURR();
	if (spAPP->CMD.CMD_No == SRC_IMM_CURR_QRY) CMD_SRC_IMM_CURR_QRY();
	if (spAPP->CMD.CMD_No == SRC_IMM_VOLT) CMD_SRC_IMM_VOLT();
	if (spAPP->CMD.CMD_No == SRC_IMM_VOLT_QRY) CMD_SRC_IMM_VOLT_QRY();
	if (spAPP->CMD.CMD_No == MEAS_CURR_QRY) CMD_MEAS_CURR_QRY();
	if (spAPP->CMD.CMD_No == MEAS_VOLT_QRY) CMD_MEAS_VOLT_QRY();
	if (spAPP->CMD.CMD_No == OUT_STAT) CMD_OUT_STAT();
	if (spAPP->CMD.CMD_No == OUT_STAT_QRY) CMD_OUT_STAT_QRY();
	if (spAPP->CMD.CMD_No == OUT_STAT_ALL) CMD_OUT_STAT_ALL();
	
	if (spAPP->CMD.CMD_No == NONSCPI_PING_QRY) CMD_PING();
	if (spAPP->CMD.CMD_No == NONSCPI_ERROR_QRY) CMD_GET_ERROR_QRY();
	
	if (spAPP->CMD.CMD_No != NO_COMMAND && spAPP->CMD.CMD_phase == DEF_CMD_START_PHASE) {
		// Unknown command
		spAPP->ERROR.ERROR_No = APP_E_UNKNOWN_CMD;
		spAPP->ERROR.DATA_cmd = spAPP->CMD.CMD_No;
		spAPP->ERROR.ERROR_src = spAPP->CMD.SrcAPI->RX.SourceAdd;
		spAPP->ERROR.DATA_len = spAPP->CMD.DATA_len;
		DAT_OPS_MoveData(spAPP->CMD.DATA_buff,spAPP->ERROR.DATA_buff,spAPP->ERROR.DATA_len,true);
		CMD_PROC_CLR();
	}
	
	// command was finished -> clear command structure
	if (spAPP->CMD.CMD_phase == DEF_CMD_LAST_PHASE) {
		CMD_PROC_CLR();
		mStatusLed_Off();
	}
}

void CMD_PROC_CHECK(void)
{
	// check periphery incoming commands, execution start on next main loop
	if (spAPP->API.UART0->RX.Event > API_RECEIVING &&
		spAPP->API.UART0->RX.Event != API_ERROR &&
		spAPP->CMD.CMD_No == NO_COMMAND &&
		spAPP->API.UART0->RX.CmdAckNack_type == API_CMD_MESS) {
		if (spAPP->API.UART0->RX.Event ==API_PRIVATE_MESS || spAPP->API.UART0->RX.Event==API_GROUP_MESS || spAPP->API.UART0->RX.Event==API_PUBLIC_MESS) {
			spAPP->CMD.CMD_No = spAPP->API.UART0->RX.Command;
			spAPP->CMD.CMD_src = spAPP->API.UART0->RX.SourceAdd;
			spAPP->CMD.CMD_trg = spAPP->API.UART0->RX.TargetAdd;
			spAPP->CMD.DATA_len = spAPP->API.UART0->RX.DataLength;
			DAT_OPS_MoveData(spAPP->API.UART0->RX.Data,spAPP->CMD.DATA_buff,spAPP->CMD.DATA_len,false);
			spAPP->CMD.DATA_buff[spAPP->CMD.DATA_len] = 0;
			spAPP->CMD.SrcAPI = spAPP->API.UART0;
			spAPP->API.UART0->TX.TargetAdd = spAPP->API.UART0->RX.SourceAdd;
		}
		else {
			spAPP->API.UART0->RX.Event=API_NO_ACTION;
		}
		
		//BlinkLed(2);
	}
	/*
	if (spAPP->API.UART0->RX.Event > API_RECEIVING) {
		BlinkLed(1);
	}
	if (spAPP->API.UART0->RX.Event != API_ERROR) {
		BlinkLed(2);
	}
	if (spAPP->CMD.CMD_No == NO_COMMAND) {
		BlinkLed(3);
	}
	if (spAPP->API.UART0->RX.CmdAckNack_type == API_CMD_MESS) {
		BlinkLed(4);
	}
	*/
}

void CMD_PROC_CLR(void)
{
	spAPP->CMD.CMD_No = NO_COMMAND;
	spAPP->CMD.CMD_phase = DEF_CMD_START_PHASE;
	spAPP->CMD.CMD_src = 0;
	spAPP->CMD.SrcAPI = 0;
	spAPP->CMD.CMD_trg = 0;
	spAPP->CMD.TrgAPI = 0;
	spAPP->CMD.DATA_len = 0;
}

/************************************************************************/
/* PRIVATE - Command function                                           */
/************************************************************************/
void CMD_CORE_RESET (void)			// DONE
{
	switch(spAPP->CMD.CMD_phase) {
		case DEF_CMD_START_PHASE:
			spAPP->ERROR.InitiateReset = true;
			mVoltRegInDrv_20V();
			spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
			break;
		default:
			spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
			break;
	}
}
	
void CMD_INST_SEL_PAR_QRY (void)	// DONE
{
	if (spAPP->CMD.SrcAPI->TX.Event == API_NO_ACTION) {
		sprintf((char*)spAPP->CMD.SrcAPI->TX.Data,"%s",PS_INST_PAR);
		spAPP->CMD.SrcAPI->TX.DataLength = sizeof(PS_INST_PAR)-1;
		// generate ACK respond
		spAPP->CMD.SrcAPI->TX.CmdAckNack_type = API_ACK_MESS;
		spAPP->CMD.SrcAPI->TX.Event = API_SEND;
		// command finishing
		spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
		spAPP->CMD.SrcAPI->RX.Event = API_NO_ACTION;
	}
	/*
	TERMINAL DEBUG:
	USB CMD:
	PS RESPOND:	$AB$05$01$08$FE$04$41$48$4F$4A$00$5B$70$BA
	*/
}
	
void CMD_SRC_IMM_CURR (void)		// 
{
	NumericCmdHandling (&spAPP->API.REG->Req.ReqI.Int,&spAPP->API.REG->Req.ReqI.Tenth,false);
	//BlinkLed((uint8_t)spAPP->API.REG->Req.ReqI.Int);
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 40 05 00 05 00 00 00 E8 BE BA
	PS RESPOND:	$AB$01$05$08$FE$00$00$F5$FC$BA
	*/
}
	
void CMD_SRC_IMM_CURR_QRY (void)	// DONE
{
	NumericCmdHandling (&spAPP->API.REG->Req.ReqI.Int,&spAPP->API.REG->Req.ReqI.Tenth,true);
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 41 00 00 F2 BD BA
	PS RESPOND:	$AB$01$05$08$FE$05$00$05$00$00$00$EB$FC$BA
	*/
}

void CMD_SRC_IMM_VOLT (void)		// DONE
{
	NumericCmdHandling (&spAPP->API.REG->Req.ReqU.Int,&spAPP->API.REG->Req.ReqU.Tenth,false);
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 42 05 00 0A 00 00 00 E3 BC BA
	PS RESPOND:	$AB$01$05$08$FE$00$00$F5$FC$BA	
	*/
}
	
void CMD_SRC_IMM_VOLT_QRY (void)	// DONE
{
	NumericCmdHandling (&spAPP->API.REG->Req.ReqU.Int,&spAPP->API.REG->Req.ReqU.Tenth,true);
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 43 00 00 F2 BB BA
	PS RESPOND:	$AB$01$05$08$FE$05$00$05$00$00$00$EB$FC$BA
	*/
}

void CMD_MEAS_CURR_QRY (void)		// DONE
{
	NumericCmdHandling (&spAPP->API.REG->Meas.MeasC.Int,&spAPP->API.REG->Meas.MeasC.Tenth,true);
	//NumericCmdHandling (&spAPP->API.REG->Meas.MeasPostRegU.Int,&spAPP->API.REG->Meas.MeasPostRegU.Tenth,true);
	//NumericCmdHandling (&spAPP->API.REG->Meas.MeasPreRegU.Int,&spAPP->API.REG->Meas.MeasPreRegU.Tenth,true);
	//NumericCmdHandling (&spAPP->API.REG->Meas.MeasTermU.Int,&spAPP->API.REG->Meas.MeasTermU.Tenth,true);
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 50 00 00 F2 AE BA
	PS RESPOND:	$AB$01$05$08$FE$05$00$05$00$00$00$EB$FC$BA
	*/
}
	
void CMD_MEAS_VOLT_QRY (void)		// DONE
{
	//if (PS_TERMINAL_MEASURING) NumericCmdHandling (&spAPP->API.REG->Meas.MeasTermU.Int,&spAPP->API.REG->Meas.MeasTermU.Tenth,true);
	//else NumericCmdHandling (&spAPP->API.REG->Meas.MeasPostRegU.Int,&spAPP->API.REG->Meas.MeasPostRegU.Tenth,true);
	//NumericCmdHandling (&spAPP->API.REG->Meas.MeasPostRegU.Int,&spAPP->API.REG->Meas.MeasPostRegU.Tenth,true);
	NumericCmdHandling (&spAPP->API.REG->Meas.MeasTermU.Int,&spAPP->API.REG->Meas.MeasTermU.Tenth,true);
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 51 00 00 F2 AD BA
	PS RESPOND:	$AB$01$05$08$FE$05$00$05$00$00$00$EB$FC$BA
	*/
}

void CMD_OUT_STAT (void)			// DONE
{
	//mVoltRegInDrv_Enab();
	//mVoltOutDrv_Enab();
	NumericCmdHandling (&TempIntNo,NULL,false);
	if (TempIntNo) {
		spAPP->API.REG->Req.OutputOn = true;
		//mVoltOutDrv_On();
		//mVoltRegInDrv_20V();
	}
	else {
		spAPP->API.REG->Req.OutputOn = false;
		//mVoltOutDrv_Off();
		//mVoltRegInDrv_40V();
	}
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 60 05 00 01 00 00 00 EC 9E BA
	PS RESPOND:	$AB$01$05$08$FE$00$00$F5$FC$BA	
	*/
}
	
void CMD_OUT_STAT_QRY (void)		// DONE
{
	if (spAPP->API.REG->Req.OutputOn) {
		TempIntNo = 1;
	}
	else {
		TempIntNo = 0;
	}
	NumericCmdHandling (&TempIntNo,NULL,true);
	
	/*
	TERMINAL DEBUG:
	USB CMD:	AB 05 01 08 61 00 00 F2 9D BA
	PS RESPOND:	$AB$01$05$08$FE$05$00$01$00$00$00$EF$FC$BA
	*/
}

void CMD_OUT_STAT_ALL (void)
{
	DAT_OPS_GetNumber(spAPP->CMD.SrcAPI->RX.Data,&TempIntNo,NULL);
	if (TempIntNo) {
		spAPP->API.REG->Req.OutputOn = true;
	}
	else {
		spAPP->API.REG->Req.OutputOn = false;
	}
	
	// command finishing
	spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
	spAPP->CMD.SrcAPI->RX.Event = API_NO_ACTION;
}

void CMD_PING(void)
{
	if (spAPP->CMD.SrcAPI->TX.Event == API_NO_ACTION) {
		// generate ACK respond
		spAPP->CMD.SrcAPI->TX.CmdAckNack_type = API_ACK_MESS;
		spAPP->CMD.SrcAPI->TX.Event = API_SEND;
		// command finishing
		spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
		spAPP->CMD.SrcAPI->RX.Event = API_NO_ACTION;
	}
}


void CMD_GET_ERROR_QRY (void)			// DONE
{
	TempIntNo = (int16_t) spAPP->SCPI_StatStr->ErrEvent.ErrorEvent[spAPP->SCPI_StatStr->ErrEvent.ReadPointer];	
	NumericCmdHandling (&TempIntNo,NULL,true);
	if (TempIntNo == 0) {
		// no error put read pointer on the same place as write pointer
		spAPP->SCPI_StatStr->ErrEvent.ReadPointer = spAPP->SCPI_StatStr->ErrEvent.WritePointer;
	}
	else {
		spAPP->SCPI_StatStr->ErrEvent.ErrorEvent[spAPP->SCPI_StatStr->ErrEvent.ReadPointer] = 0;
		mSRS_ERREV_INC_R_PTR(spAPP->SCPI_StatStr);
	}
}

// Common numeric communication function
void NumericCmdHandling (int16_t *Int, int16_t *Tenth, bool Query) 
{
	if (spAPP->CMD.SrcAPI->TX.Event == API_NO_ACTION) {
		// generate ACK respond
		spAPP->CMD.SrcAPI->TX.CmdAckNack_type = API_ACK_MESS;
		if (Query) {
			spAPP->CMD.SrcAPI->TX.DataLength = DAT_OPS_PutNumber(spAPP->CMD.SrcAPI->TX.Data,Int,Tenth);
		}
		else {
			if (spAPP->CMD.SrcAPI->RX.DataLength >= 4) {
				DAT_OPS_GetNumber(spAPP->CMD.SrcAPI->RX.Data,Int,Tenth);
			}
			else {
				// bad data length
				spAPP->CMD.SrcAPI->TX.CmdAckNack_type = API_NACK_MESS;
				TempIntNo = APP_E_BAD_CMD_DATA_LEN;
				spAPP->CMD.SrcAPI->TX.DataLength = DAT_OPS_PutNumber(spAPP->CMD.SrcAPI->TX.Data,&TempIntNo,NULL);
			}	
		}
		spAPP->CMD.SrcAPI->TX.Event = API_SEND;
		// command finishing
		spAPP->CMD.CMD_phase = DEF_CMD_LAST_PHASE;
		spAPP->CMD.SrcAPI->RX.Event = API_NO_ACTION;
	}
}