/*
 * drv_flash.c
 *
 *  Created on: 28 мар. 2025 г.
 *      Author: basov.g
 */

#include "drv_flash.h"
#include "MDR32VF0xI_rst_clk.h"
#include "MDR32VF0xI_port.h"
#include "MDR32VF0xI_ssp.h"
#include "stdbool.h"
#include "../utils/utils.h"

flashAdcuiSaveStruct flashAdcui = {0};
#define FLASH_PORT      MDR_PORTA
#define FLASH_PORT_CLK  RST_CLK_PCLK_PORTA
#define FLASH_CS      	PORT_PIN_12
#define FLASH_MOSI     	PORT_PIN_15
#define FLASH_MISO     	PORT_PIN_14
#define FLASH_SCK    	PORT_PIN_13
#define FLASH_SSP_CLK	RST_CLK_PCLK_SSP1
#define FLASH_SSP    	MDR_SSP1
#define FLASH_ID		0x1DC
#define FLASH_MAGIC		0x20171353
bool initFlash = false;
uint16_t flashId = 0;
flashAdcuiSaveStruct saveAdcuiStruct;

uint8_t drv_flash_spiReadWriteByte(uint8_t data)
{

	while(!SSP_GetFlagStatus(FLASH_SSP,SSP_FLAG_TNF));
    SSP_SendData(FLASH_SSP,data);
    while(!SSP_GetFlagStatus(FLASH_SSP,SSP_FLAG_RNE));
    while(SSP_GetFlagStatus(FLASH_SSP,SSP_FLAG_BSY));
    return (uint8_t)SSP_ReceiveData(FLASH_SSP);
}

void drv_flash_checId(void)
{
	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x9f);
	flashId = (uint16_t)(drv_flash_spiReadWriteByte(0)<<8 | drv_flash_spiReadWriteByte(0));
	PORT_SetBits(FLASH_PORT, FLASH_CS);
	initFlash = (flashId == FLASH_ID);
}

//cannot clear 512 byte, need 2024 byte
void drv_flash_ClearSector(uint32_t numberPage)
{
	if(numberPage > 100) numberPage = 100;
	numberPage*=512;

	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x06);
	PORT_SetBits(FLASH_PORT, FLASH_CS);
	delayUs(10000);
	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x20);
	drv_flash_spiReadWriteByte((numberPage>>16)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>8)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>0)&0xFF);
	PORT_SetBits(FLASH_PORT, FLASH_CS);
	delayUs(100000);
}

void drv_flash_writePage(uint32_t numberPage, uint32_t *data, uint16_t count)
{
	if(numberPage > 100) numberPage = 100;
	numberPage*=512;

	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x06);
	PORT_SetBits(FLASH_PORT, FLASH_CS);
	delayUs(10000);
	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x02);
	drv_flash_spiReadWriteByte((numberPage>>16)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>8)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>0)&0xFF);
	for(int i = 0; i < count; i+=4)
	{
		drv_flash_spiReadWriteByte((uint8_t)(data[i/4]>>24)&0xFF);
		drv_flash_spiReadWriteByte((uint8_t)(data[i/4]>>16)&0xFF);
		drv_flash_spiReadWriteByte((uint8_t)(data[i/4]>>8)&0xFF);
		drv_flash_spiReadWriteByte((uint8_t)data[i/4]&0xFF);
	}
	PORT_SetBits(FLASH_PORT, FLASH_CS);
}

void drv_flash_readPage(uint32_t numberPage, uint32_t *data, uint16_t count)
{
	if(numberPage > 100) numberPage = 100;
	numberPage*=512;
	PORT_ResetBits(FLASH_PORT, FLASH_CS);
	drv_flash_spiReadWriteByte(0x03);
	drv_flash_spiReadWriteByte((numberPage>>16)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>8)&0xFF);
	drv_flash_spiReadWriteByte((numberPage>>0)&0xFF);
	for(int i = 0; i < count; i+=4)
	{
		data[i/4] = drv_flash_spiReadWriteByte(0)<<24;
		data[i/4] |= drv_flash_spiReadWriteByte(0)<<16;
		data[i/4] |= drv_flash_spiReadWriteByte(0)<<8;
		data[i/4] |= drv_flash_spiReadWriteByte(0)<<0;
	}
	PORT_SetBits(FLASH_PORT, FLASH_CS);
}

void drv_flash_initPins(void)
{
	RST_CLK_PCLKCmd(FLASH_PORT_CLK, ENABLE);
	PORT_InitTypeDef PORT_InitStructure;
	PORT_InitStructure.PORT_Direction    	= PORT_DIRECTION_OUTPUT;
	PORT_InitStructure.PORT_Function  		= PORT_FUNCTION_PORT;
	PORT_InitStructure.PORT_Mode  			= PORT_MODE_DIGITAL;
	PORT_InitStructure.PORT_Power 			= PORT_POWER_NOMINAL_UPTO_2mA;
	PORT_InitStructure.PORT_PullDown  		= PORT_PULL_DOWN_OFF;
	PORT_InitStructure.PORT_PullUp  		= PORT_PULL_UP_OFF;
	PORT_InitStructure.PORT_Pin = (FLASH_CS);
	PORT_Init(FLASH_PORT, &PORT_InitStructure);

	PORT_InitStructure.PORT_Function  		= PORT_FUNCTION_MAIN;
	PORT_InitStructure.PORT_Pin =  (FLASH_MOSI  | FLASH_SCK);
	PORT_Init(FLASH_PORT, &PORT_InitStructure);

	PORT_InitStructure.PORT_Direction    	= PORT_DIRECTION_INPUT;
	PORT_InitStructure.PORT_Pin =  (FLASH_MISO);
	PORT_Init(FLASH_PORT, &PORT_InitStructure);
}

void drv_flash_initSpi(void)
{
	RST_CLK_PCLKCmd(FLASH_SSP_CLK, ENABLE);
	RST_CLK_PER1_C2_Cmd(RST_CLK_PER1_C2_SSP1,ENABLE);
	RST_CLK_PER1_C2_SetPrescaler(RST_CLK_PER1_C2_SSP1,RST_CLK_PER1_PRESCALER_DIV_1);

	SSP_InitTypeDef SSP_InitStructure = {0};
	SSP_InitStructure.SSP_CPSDVSR=16;
	SSP_InitStructure.SSP_SCR=1;

	SSP_InitStructure.SSP_FrameFormat = SSP_FRAME_FORMAT_SPI;
	SSP_InitStructure.SSP_Mode = SSP_MODE_MASTER;
	SSP_InitStructure.SSP_WordLength = SSP_WORD_LENGTH_8BIT;
	SSP_InitStructure.SSP_LoopbackMode = DISABLE;
	SSP_InitStructure.SSP_FastSPISlave = DISABLE;

	SSP_InitStructure.SSP_ClockPolarity = SSP_CLOCK_POLARITY_LOW;
	SSP_InitStructure.SSP_ClockPhase    = SSP_CLOCK_PHASE_1EDGE;

	SSP_Init(FLASH_SSP, &SSP_InitStructure);
	SSP_Cmd(FLASH_SSP,ENABLE);
}

void drv_flash_init(void)
{
	drv_flash_initPins();
	drv_flash_initSpi();
	drv_flash_checId();
	if(initFlash)
	{
		drv_flash_load();
	}
}

void drv_flash_update(void)
{

}


void drv_flash_save(void)
{
	if(!initFlash) return;
	saveAdcuiStruct.magicValue    = FLASH_MAGIC;
	saveAdcuiStruct.registerF0AC  = MDR_ADCUI->F0AC;
	saveAdcuiStruct.registerF1AC  = MDR_ADCUI->F1AC;
	saveAdcuiStruct.registerF2AC  = MDR_ADCUI->F2AC;
	saveAdcuiStruct.registerCCAL1 = MDR_ADCUI->CCAL1;
	saveAdcuiStruct.registerCCAL2 = MDR_ADCUI->CCAL2;
	saveAdcuiStruct.registerCCAL3 = MDR_ADCUI->CCAL3;
	saveAdcuiStruct.registerCCAL4 = MDR_ADCUI->CCAL4;
	saveAdcuiStruct.registerF0CTR = MDR_ADCUI->F0CTR;
	saveAdcuiStruct.registerF1CTR = MDR_ADCUI->F1CTR;
	saveAdcuiStruct.registerF2CTR = MDR_ADCUI->F2CTR;
	saveAdcuiStruct.registerF0WC  = MDR_ADCUI->F0WC;
	saveAdcuiStruct.registerF1WC  = MDR_ADCUI->F1WC;
	saveAdcuiStruct.registerF2WC  = MDR_ADCUI->F2WC;
	saveAdcuiStruct.registerF0VC  = MDR_ADCUI->F0VC;
	saveAdcuiStruct.registerF1VC  = MDR_ADCUI->F1VC;
	saveAdcuiStruct.registerF2VC  = MDR_ADCUI->F2VC;

	drv_flash_ClearSector(0);
	drv_flash_writePage(0, (uint32_t*)(&saveAdcuiStruct), sizeof(flashAdcuiSaveStruct));
}

void drv_flash_load(void)
{
	drv_flash_readPage(0,(uint32_t*)(&saveAdcuiStruct), sizeof(flashAdcuiSaveStruct));
	if(saveAdcuiStruct.magicValue == FLASH_MAGIC)
	{
		MDR_ADCUI->F0AC  =	saveAdcuiStruct.registerF0AC;
		MDR_ADCUI->F1AC  =	saveAdcuiStruct.registerF1AC;
		MDR_ADCUI->F2AC  =	saveAdcuiStruct.registerF2AC;
		MDR_ADCUI->CCAL1 =	saveAdcuiStruct.registerCCAL1;
		MDR_ADCUI->CCAL2 =	saveAdcuiStruct.registerCCAL2;
		MDR_ADCUI->CCAL3 =	saveAdcuiStruct.registerCCAL3;
		MDR_ADCUI->CCAL4 =	saveAdcuiStruct.registerCCAL4;
		MDR_ADCUI->F0WC  =	saveAdcuiStruct.registerF0WC;
		MDR_ADCUI->F1WC  =	saveAdcuiStruct.registerF1WC;
		MDR_ADCUI->F2WC  =	saveAdcuiStruct.registerF2WC;
		MDR_ADCUI->F0VC  =	saveAdcuiStruct.registerF0VC;
		MDR_ADCUI->F1VC  =	saveAdcuiStruct.registerF1VC;
		MDR_ADCUI->F2VC  =	saveAdcuiStruct.registerF2VC;
		MDR_ADCUI->F0CTR &= ~0xFFF3FC00;
		MDR_ADCUI->F1CTR &= ~0xFFF3FC00;
		MDR_ADCUI->F2CTR &= ~0xFFF3FC00;
		MDR_ADCUI->F0CTR |= saveAdcuiStruct.registerF0CTR & 0xFFF3FC00;
		MDR_ADCUI->F1CTR |= saveAdcuiStruct.registerF1CTR & 0xFFF3FC00;
		MDR_ADCUI->F2CTR |= saveAdcuiStruct.registerF2CTR & 0xFFF3FC00;
	}
}

uint16_t drv_flash_getId(void)
{
	return flashId;
}
