/*
 * njj29c2_drv.c
 *
 *  Created on: 2020Äê12ÔÂ4ÈÕ
 *      Author: nxa16228
 */


#include <NJJ29C2_Drv.h>
#include <PEPS_Util.h>
#include "Mcal.h"
#include "OsIf.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "Lpspi_Ip.h"
#include "Crc_Ip.h"
#include "retarget.h"
#include "string.h"

extern void OsIf_Delay_Us(uint32_t nUsec);
extern void OsIf_Delay_Ms(uint32_t nMsec);

/*******************************************************************************
 * Global Variables for NJJ29C2 Driver
 *******************************************************************************/
uint8_t txBufNjj[32];
uint8_t rxBufNjj[32];
uint32_t cenSpiStatus;
uint32_t respError;		//record latest response error status


/*************************************************************************************
 * API functions definition
 ************************************************************************************/
void cenDelayUs(uint32_t usec){
	OsIf_Delay_Us(usec);
}

void cenDelayMs(uint32_t msec){
	OsIf_Delay_Ms(msec);
}

void cenRequestBus(void){
	/* set CS pin low */
	Siul2_Dio_Ip_WritePin(NJJ_CS_PORT, NJJ_CS_PIN, 0);		//PTF26 is used as NJJ29C2 cs - LPSPI4_PCS1
}

void cenReleaseBus(void){
	/* set CS pin high */
	Siul2_Dio_Ip_WritePin(NJJ_CS_PORT, NJJ_CS_PIN, 1);		//PTF26 is used as NJJ29C2 cs - LPSPI4_PCS1
}

Std_ReturnType cenGetTxRxStat(void){
	/* return a variable in TX complete callback to indicate current Tx status */
	return 0;
}

void cenPortInit(void){
	/* Configure CS pin as GPIO and output 1 */
	/* Configure PTF26 LPSPI4 PCS1 as GPIO output */
	Siul2_Dio_Ip_WritePin(NJJ_CS_PORT, NJJ_CS_PIN, 1);		//PTF26 is used as NJJ29C2 cs - LPSPI4_PCS1
	Siul2_Port_Ip_SetOutputBuffer(PORTF_H_HALF, (26-16), TRUE, PORT_MUX_AS_GPIO);
}

/* wait till BUSY goes low */
void cenWaitForBusyLine(void){
	while(1 == Siul2_Dio_Ip_ReadPin(NJJ_BUSY_PORT, NJJ_BUSY_PIN));
}

/* wait till IRQ goes high */
void cenWaitForIrqLine(void){
	while(0 == Siul2_Dio_Ip_ReadPin(NJJ_INT_PORT, NJJ_INT_PIN));
}

status_t cenSpiTxRx(uint8_t *txBuf, uint8_t *rxBuf){
	status_t result;
	/* wait busy line get low */
	cenWaitForBusyLine();
	cenSpiStatus = 1;
	cenRequestBus();
	result = (status_t) Lpspi_Ip_SyncTransmit(
				  &Lpspi_Ip_DeviceAttributes_SPI4_PCS1_NJJ29C2_Instance_4_BOARD_InitPeripherals,
				  txBuf,
				  rxBuf,
				  NJJ_SPI_FRAME_LEN,
				  NJJ_SPI_TIMEOUT);
	if (STATUS_SUCCESS == result){
	}
	cenDelayUs(NJJ_SPI_CS_DELAY);
	cenReleaseBus();
	cenDelayMs(1);
	return result;
}

void cenCrcInit(void)
{
#if 0
	crc_user_config_t chksumConfig;
	chksumConfig.crcWidth = CRC_BITS_16;
	chksumConfig.seed = NJJ_CRC_SEED;
	chksumConfig.polynomial = NJJ_CRC_POLY;
	chksumConfig.writeTranspose = CRC_TRANSPOSE_NONE;
	chksumConfig.readTranspose = CRC_TRANSPOSE_NONE;
	chksumConfig.complementChecksum = false;

	/* Call init function */
	CRC_DRV_Init(NJJ_CRC_INST,	(const crc_user_config_t *) &chksumConfig);
#endif
	Crc_Ip_Init(&CrcIp_xConfigInit);

}

void cenGenSpiCrc(uint8_t *data, uint8_t len)
{
#if 0
	uint32_t chkResult = 0u;
	(void) CRC_DRV_SetSeed(NJJ_CRC_INST, NJJ_CRC_SEED);
	CRC_DRV_WriteData(NJJ_CRC_INST, data, (uint32_t) ((uint32_t) len - 2u));
	chkResult = CRC_DRV_GetCrcResult(NJJ_CRC_INST);
#endif
	uint32_t chkResult;
	chkResult = (uint32_t) Crc_Ip_SetChannelCalculate(
			0, /* const uint32 LogicChannel, */
			data, /* const uint8  *DataPtr, */
			len-2, /* const uint32  Length, */
			0xFFFFFFFF, /* const uint64 StartValue, */
			TRUE);

	/* Append CRC value to data */
	data[len - 1u] = (uint8_t) ((uint16_t) (chkResult & 0x00FFu));
	data[len - 2u] = (uint8_t) ((uint16_t) (chkResult & 0xFF00u) >> 8u);
}

/* verify CRC, return 0 if correct. */
#if 0
Std_ReturnType cenVerifySpiCrc(const uint8_t *data, uint8_t len)
{
	Std_ReturnType result = 0;
	uint32_t chkResult = 0x0000u;
	(void) CRC_DRV_SetSeed(NJJ_CRC_INST, NJJ_CRC_SEED);
	CRC_DRV_WriteData(NJJ_CRC_INST, data, len-2);
	chkResult = CRC_DRV_GetCrcResult(NJJ_CRC_INST);
	/* Verify CRC result */
//	if (0x0000u	!= ((uint16_t) (chkResult & 0xFFFFu) ^ 0x0000u)) {
//		result = 1;
//	}
	if(((chkResult>>8)!=data[len-2]) || (chkResult&0xFF)!=data[len-1]){
		result = 0x10;
	}
	return result;
}
#endif

status_t cenSendNopCmd(void){
	status_t result;
	memset(txBufNjj, 0, NJJ_SPI_FRAME_LEN);
	cenGenSpiCrc(txBufNjj, NJJ_SPI_FRAME_LEN);
	memset(rxBufNjj, 0xFF, NJJ_SPI_FRAME_LEN);
	result = cenSpiTxRx(txBufNjj, rxBufNjj);
	cenLogSpiTxRx();	//print SPI msg
	return result;
}
/* CMD_STOP_ALL: 0x08, 0x00, 0x00, 0xFF, 0xFF, 0xFF,  */
status_t cenSendStopCmd(void) {
	status_t result;
	memset(txBufNjj, 0, NJJ_SPI_FRAME_LEN);
	txBufNjj[0] = 0x08;
	txBufNjj[1] = 0x00;
	txBufNjj[2] = 0x00;
	txBufNjj[3] = 0xFF;
	txBufNjj[4] = 0xFF;
	txBufNjj[5] = 0xFF;
	cenGenSpiCrc(txBufNjj, NJJ_SPI_FRAME_LEN);
	memset(rxBufNjj, 0xFF, NJJ_SPI_FRAME_LEN);
	result = cenSpiTxRx(txBufNjj, rxBufNjj);
	cenLogSpiTxRx();	//print SPI msg
	//LOGI("Cendric", "CMD_STOP_ALL.\r\n");
	return result;
}

status_t cenRespParse(const uint8_t respData[]){
	uint8_t respCode = 0u;
	/* Get response code */
	respCode = respData[0u];
	return (status_t)respCode;
}

void cenResetPin(void){
	Siul2_Dio_Ip_WritePin(NJJ_RST_PORT, NJJ_RST_PIN, 0);	//PTF30 = NJJ RST
	cenDelayUs(10u);
	Siul2_Dio_Ip_WritePin(NJJ_RST_PORT, NJJ_RST_PIN, 1);	//PTF30 = NJJ RST
	//LOGI("Cendric", "Reset pin assert and release.\r\n");
}

status_t cenResetCmd(void){
	status_t result;
	memset(txBufNjj, 0, NJJ_SPI_FRAME_LEN);
	txBufNjj[0] = 0x0A;	//reset cmd
	txBufNjj[1] = 0x01;
	cenGenSpiCrc(txBufNjj, NJJ_SPI_FRAME_LEN);
	memset(rxBufNjj, 0xFF, NJJ_SPI_FRAME_LEN);
	result = cenSpiTxRx(txBufNjj, rxBufNjj);
	cenLogSpiTxRx();	//print SPI msg
	return result;
}

/*************************************************************************
 * Initialize Cendric:
 * 1) CRC module init, CE GPIO init
 * 2) reset and release;
 * 3) Wait for IRQ high
 * 4) Send initial NOP cmd
 * 5) Check CRC of the received response.
 * Return: 0=OK, 1=SPI COM error, 0x10=Response CRC error.
 **************************************************************************/
status_t cenInitialCheck(void){
	status_t result;
	cenPortInit();
	cenCrcInit();
	cenResetPin();
	cenWaitForIrqLine();
	result = cenSendNopCmd();
	if(result == 0){
		respError |= cenVerifySpiCrc(rxBufNjj, NJJ_SPI_FRAME_LEN);
	}
	if(result == 0){
		result = cenResetCmd();
	}
	if(result == 0){
		respError |= cenVerifySpiCrc(rxBufNjj, NJJ_SPI_FRAME_LEN);
	}
	//result = cenSendStopCmd();
	//LOGI("Cendric", "Initial SPI check.\r\n");
	return result;
}


/* check response */
status_t cenCheckResp(void){
	status_t result = 0;
	return result;
}
