/*
 * LWM_MSSY_deRF.c
 *
 * Created: 14.4.2017 12:56:52
 * Author : Ondra
 */ 

#include <avr/io.h>
/*- Includes ---------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "config.h"
#include "hal.h"
#include "phy.h"
#include "sys.h"
#include "nwk.h"
#include "sysTimer.h"
#include "halBoard.h"
#include "halUart.h"
//#include "mssy_endpoints.h"
//#include "mssy_requests.h"
#include "mssy_functions.h"
#include "util/delay.h"
#include "ADC_lib.h"
#include "main.h"
#include "sensors_interface.h"

/////USB//////////////
#include "USB_Stack/usb.h"

/////BIG N libs///////
#include "BigN/bigd.h"
#include "BigN/bigdRand.h"

#define EMPTYLINE printf("\n\r");
#define BB BIGD

/*- Definitions ------------------------------------------------------------*/
#ifdef NWK_ENABLE_SECURITY
#define APP_BUFFER_SIZE     (NWK_MAX_PAYLOAD_SIZE - NWK_SECURITY_MIC_SIZE)
#else
#define APP_BUFFER_SIZE     NWK_MAX_PAYLOAD_SIZE
#endif

/*- Types ------------------------------------------------------------------*/
typedef enum AppState_t
{
	APP_STATE_Init,
	APP_STATE_FazeA,
	APP_STATE_FazeB,
	APP_STATE_FazeC,
	APP_STATE_END,
} AppState_t;

/*- Prototypes -------------------------------------------------------------*/
static void appSendData(void);

//int TestB(void);

/*- Variables --------------------------------------------------------------*/
static AppState_t appState = APP_STATE_Init;    // Incialiazation

static SYS_Timer_t appTimerA;
static SYS_Timer_t appTimerB;

static NWK_DataReq_t appDataReq;

static bool appDataReqBusy = false;

// USB printf
FILE usb_stream = FDEV_SETUP_STREAM(usb_putc_std, usb_getc_std,_FDEV_SETUP_RW);

/*- Variables BIGD --------------------------------------------------------------*/
BB MOD, a_parameter, b_parameter;
volatile BB resultsA[2];

//Faze B
BB Order, Xf, Yf;
volatile BB resultsBA[2];
volatile BB resultsBB[2];

///Faze C
BB Xm, Ym, Xo, Yo, KEY;

unsigned char s[100];

int8_t comaparsionA, comaparsionB;
BB ZEROB;



/*- Implementations --------------------------------------------------------*/

/*************************************************************************//**
*****************************************************************************/
static void appDataConf(NWK_DataReq_t *req)
{
appDataReqBusy = false;
(void)req;
}

/*************************************************************************//**
*****************************************************************************/
static void SendDataToBB(void)
{
	// varible for stored data as array
	BB data[6];
	
	for(uint8_t i = 0; i <= 5; i++){
		
		data[i] = bdNew();              // block activation 
	}
			
	data[0] = MOD;          // MOD
	data[1] = a_parameter;  // A_parametr
	data[2] = b_parameter;  // b_parametr
	data[3] = resultsA[0];  // Xf
	data[4] = resultsA[1];  // Yf
	data[5] = resultsA[2];  // Order
 

	appDataReq.dstAddr = 0xFFFF;
	appDataReq.dstEndpoint = 2;
	appDataReq.srcEndpoint = 1;
	//appDataReq.options = NWK_OPT_ENABLE_SECURITY;
	appDataReq.data = data;
	appDataReq.size = 7;
	appDataReq.confirm = appDataConf;
	NWK_DataReq(&appDataReq);
	
	
	appDataReqBusy = true;
	
	
	for(uint8_t i = 0; i <= 5; i++){
		
		bdFree(&data[i]);            // block deactivation
	}
}


static void SendDataToC(void)
{
	BB data[3];
	
	for(uint8_t i = 0; i <= 2; i++){
		
		data[i] = bdNew();              // block DEactivation
	}

	
	data[0] = resultsBA;  // X
	data[1] = resultsBA;  // Y
	

	appDataReq.dstAddr = 0xFFFF;
	appDataReq.dstEndpoint = 3;
	appDataReq.srcEndpoint = 2;
	//appDataReq.options = NWK_OPT_ENABLE_SECURITY;
	appDataReq.data = data;
	appDataReq.size = 4;
	appDataReq.confirm = appDataConf;
	NWK_DataReq(&appDataReq);


	appDataReqBusy = true;
	
	
	for(uint8_t i = 0; i <= 2; i++){
		
		bdFree(&data[i]);            // block DEactivation
	}

	
}



/*************************************************************************//**
*****************************************************************************/
//static void SendDataA_TimerHandler(SYS_Timer_t *timer)
//{
	//SendDataA();
	////(void)timer; 
//}


/*************************************************************************//**
*****************************************************************************/



static bool SendFromAToB_BB(NWK_DataInd_t *ind)  // Version BA
{
	
	// Activate block
	MOD = bdNew();
	a_parameter = bdNew();
	b_parameter = bdNew();
	resultsBB[0] = bdNew();
	resultsBB[1] = bdNew();
	ZEROB = bdNew();

	bdSetZero(ZEROB);

	MOD = ind->data[0];
	a_parameter = ind->data[1];
	a_parameter = ind->data[2];
	
	ECDH_PHASE_BB_BIGD(MOD, a_parameter, b_parameter, resultsBB);
	
	comaparsionA = bdCompare(resultsBB[1], ZEROB);  // Variable filling control
	
	// Deatcivate block
	bdFree(&MOD);
	bdFree(&a_parameter);
	bdFree(&b_parameter);

}



static bool ExchangePoint(NWK_DataInd_t *ind)
{
	Xm = bdNew();
	Ym = bdNew();
	Xo = bdNew();
	Yo = bdNew();
	MOD = bdNew();
	a_parameter = bdNew();
	ZEROB = bdNew();

	bdSetZero(ZEROB);
	
	KEY = bdNew();

	
	ECDH_PHASE_C_BIGD(Xm, Ym, Xo, Yo, MOD, a_parameter, KEY);
	
	
	comaparsionB = bdCompare(KEY, ZEROB);
	
	bdConvToDecimal(KEY, s, sizeof(s));
	key = atoi(s);
	
	
	bdFree(&Xm);
	bdFree(&Ym);
	bdFree(&Xo);
	bdFree(&Yo);
	bdFree(&MOD);
	bdFree(&a_parameter);
	
	bdFree(&KEY);
	
}



/*************************************************************************//**
*****************************************************************************/
static void appInit(void)
{
NWK_SetAddr(APP_ADDR);
NWK_SetPanId(APP_PANID);
PHY_SetChannel(APP_CHANNEL);
#ifdef PHY_AT86RF212
PHY_SetBand(APP_BAND);
PHY_SetModulation(APP_MODULATION);
#endif
PHY_SetRxState(true);

NWK_OpenEndpoint(2, SendFromAToB_BB);              // Endpoint 2
NWK_OpenEndpoint(3, ExchangePoint);              // Endpoint 3



HAL_BoardInit();



}

/*************************************************************************//**
*****************************************************************************/
static void APP_TaskHandler(void)
{
	// Block activation
	MOD = bdNew();
	a_parameter = bdNew();
	b_parameter = bdNew();
	resultsA[0] = bdNew();
	resultsA[1] = bdNew();
	resultsA[2] = bdNew();
	Order = bdNew();
	Xf = bdNew();
	Yf = bdNew();
	
	resultsBA[0] = bdNew();
	resultsBA[1] = bdNew();
	resultsBA[2] = bdNew();
	
	resultsBB[0] = bdNew();
	resultsBB[1] = bdNew();
	resultsBB[2] = bdNew();

	Xm = bdNew();
	Ym = bdNew();
	Xo = bdNew();
	Yo = bdNew();
	KEY = bdNew();
	
	
switch (appState)
{
case APP_STATE_Init:
{
	appInit();
	appState = APP_STATE_FazeA;

} break;

case APP_STATE_FazeA:
{ 
	ECDH_PHASE_A_BIGD(MOD, a_parameter, b_parameter, resultsA);
	appState = APP_STATE_FazeB;
		
} break;

case APP_STATE_FazeB:
{
	if(comaparsionA != 0){
		appState =  APP_STATE_FazeC;
		}
} break;

case APP_STATE_FazeC:

if(comaparsionB != 0){
	appState =  APP_STATE_END;
}

APP_STATE_END:
break;

default:
break;
}

// FLUSH objects
bdFree(&MOD);
bdFree(&a_parameter);
bdFree(&b_parameter);
bdFree(&resultsA[0]);
bdFree(&resultsA[1]);
bdFree(&resultsA[2]);
bdFree(&Order);
bdFree(&Xf);
bdFree(&Yf);

bdFree(&resultsBA[0]);
bdFree(&resultsBA[1]);
bdFree(&resultsBA[2]);

bdFree(&resultsBB[0]);
bdFree(&resultsBB[1]);
bdFree(&resultsBB[2]);

bdFree(&Xm);
bdFree(&Ym);
bdFree(&Xo);
bdFree(&Yo);

bdFree(&ZEROB);

}



/*************************************************************************/
int main(void)
{
	usb_init();
   /* redirect standard input/output (like printf()) to USB stream */
	stdout = &usb_stream;
	stdin  = &usb_stream;
	LED1ON;

	

	SYS_Init();
	while(1)
	{
		SYS_TaskHandler();
		APP_TaskHandler();
		
	}
}