/*
 * user_flash.c
 *
 *  Created on: May 30, 2018
 *      Author: sparr1
 */

/**************INCLUDE BLOCK**************/
#include "stm32f4xx_hal.h"
#include "OCPP.h"
#include "w25qxx.h"

/***********INCLUDE BLOCK END*************/

/***** Data Type, Constant, and Macro Definitions *****/

/* Constant DATA */

#define DATA_32                 ((uint32_t)0x12345678)
#define FLASH_USER_START_ADDR   0X0807FF00   /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR     0X0807FFFF  /* End @ of user Flash area */

/* enum struct parameters */

const struct Config_Parameter default_params =
{
		3,
		"/uploads/fota.bin", 	//link
		"113.20.17.179", 		//192.168.15.51
		"no",  					// username
		"no", 					//  password
		"8080",  				//port
		2,     					//Communication Mode
		"LubiJio",  			//ssid
		"onlyforlubiev", 		// password
		"1111",
		"1111",
		"1111",
		2, 						//ipv4V6							//V5.0
		"jionet", 				//apn for ION charge	//V5.0
		0xbbaa, 				//boot loader magic value
		0,
		"1234", 				//Password
		10,
		5,
		10,
		5,
		"/v1.6/LUBIBASEAC001", 	//"/services/CentralSystemServiceJson16/LUBI-BS-007", //"/EVNERGY/IONUPAC00",//"/services/CentralSystemServiceJson16/LUBI-BS-007",//"/services/CentralSystemServiceJson16/LUBI-BS-007", //link
		"api.plugeasy.in", 		//"ocpp.grid-scape.com",	//	"api.plugeasy.in"//"ioneconnect.electreefi.com",// //ocpp.grid-scape.com",
		"no",
		"1234@123",
		"80",
		{ 1, 1 }, 				//ocpp status
		120,					//4.X.8
		300,
		17,
		40,						//4.X.8
		"Smart-Socket",
		"12345678 ",
//V501change
		3650,
		3150,
		2722,
		2260,
		100,
		0,
//V501change
		0xAA55, 				//Magic Value
		};

const struct Config_Parameter_OCPP default_params_ocpp =
{
		1, 					// LocalAuthListEnbl
		3600, 				//FailedTx_Intvl
		3,  				//FailedAttempt
		1,   				//StopTxInvalidId
		3,   				// ResetRetry
		0,  				//StatusDuration		//4.X.8
		30,  				// MeterIntvl
		0,   				//LocalPreAuth
		1,					//LocalAuthOffln
		0, 					//ClkAlgnIntvl
		1,   				//AuthRemotTx
		1,   				//AuthCachEnable
		0,   				//Ground Fault Detection	//4.X.8
		300,				//HeartbeatIntvl
		{ 0, 0, 0, 0 },   	//Operative
		0,
		1,					//stoptransinternetLoss
		10,					//1second
		100,
		0,
		0xAA55, 			//Magic Value
		};

/* Global variables*/

uint8_t InProcess = 0;
uint32_t Address = 0, PageError = 0;
__IO uint32_t data32 = 0, MemoryProgramStatus = 0;
/* Extern Data Declarations */

extern UART_HandleTypeDef huart6;

/* Static Data Declarations */

/***** Data Type, Constant, and Macro Definitions END *****/

/***** Public Function Bodies *****/
void Internal_Flash_Program(unsigned long int*, unsigned int);
void Internal_Flash_Read(unsigned long int*, unsigned int);
void Write_Params(void);
void Read_Params(void);
void Read_CACH_Params(void);
void Write_CACH_Params(void);
/***** Public Function Bodies END *****/

/* Base address of the Flash sectors */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

/*Variable used for Erase procedure*/
//static FLASH_EraseInitTypeDef EraseInitStruct;

/////////////////////////
/**
 * @brief Program data into the internal flash memory.
 *
 * This function programs data into the internal flash memory. It unlocks the flash,
 * erases the specified sector, and then programs the data word by word.
 *
 * @param ram_addr Pointer to the data in RAM.
 * @param size Size of the data to be programmed in bytes.
 * @return None
 */
void Internal_Flash_Program(unsigned long int *ram_addr, unsigned int size)
{
	InProcess = 1;
	unsigned int addr = 0, bal_size;
	char lcl_buff[50];

	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();

	/* Erase the user Flash area
	 (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
	FLASH_Erase_Sector(FLASH_SECTOR_11, VOLTAGE_RANGE_3);

	/* Program the user Flash area word by word
	 (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

	bal_size = size % 4;
	if (bal_size)
		size = size + bal_size;

	Address = FLASH_USER_START_ADDR;

	while (Address < FLASH_USER_END_ADDR)
	{
		if (addr >= (size / 4)) break;
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, *ram_addr++) == HAL_OK)
		{
			Address = Address + 4;
			addr++;
		}
		else
		{
			/* Error occurred while writing data in Flash memory.
			 User can add here some code to deal with this error */
			while (1)
			{
				//HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_8);
//				  sprintf(lcl_buff,"internal flash error.....\r\n");
//					HAL_UART_Transmit(&huart6, (uint8_t*)lcl_buff, strlen(lcl_buff),500);
			}
		}
	}
	HAL_FLASH_Lock();
	InProcess = 0;
}
/**
 * @brief Read data from the internal flash memory.
 *
 * This function reads data from the internal flash memory. It reads the data word by word.
 *
 * @param addr_toread Pointer to store the read data.
 * @param size Size of the data to be read in bytes.
 * @return None
 */
void Internal_Flash_Read(unsigned long int *addr_toread, unsigned int size)
{
	unsigned int addr = 0, bal_size;

	bal_size = size % 4;
	if (bal_size)
		size = size + bal_size;

	Address = FLASH_USER_START_ADDR;
	MemoryProgramStatus = 0x0;

	while (Address < FLASH_USER_END_ADDR)
	{
		if (addr >= (size / 4)) break;
		*addr_toread = *(__IO uint32_t*) Address;
		addr_toread++;
		addr++;
		Address = Address + 4;
	}
}
/**
 * @brief Read parameters from internal flash memory.
 *
 * This function reads parameters from internal flash memory.
 * It reads the data word by word and updates the OCPP structure.
 *
 * @return None
 */
void Read_Params(void)
{
//	Internal_Flash_Read((unsigned long int*)&OCPP, sizeof(struct Config_Parameter));

	uint8_t lcltemp_buff[2]; //,hour_ok=0;;
	uint16_t i = 0; //j=0;//variable=0;
	uint32_t add = (3840 * w25qxx.SectorSize);

	uint16_t frame_length;
	uint16_t data_len = 0;

	if (sizeof(struct Config_Parameter) % 2)
		data_len = sizeof(OCPP) - 1; 		// SFlash_write(ptr,sizeof(data_to_flash)-1);
	else
		data_len = sizeof(OCPP); 			//SFlash_write(ptr,sizeof(data_to_flash));

	frame_length = data_len;
	char *ptr = &OCPP.fw_status;

	for (i = 0; i < frame_length; i++) //while(data_len--)
	{
		W25qxx_ReadByte(&lcltemp_buff, add);
		*ptr = lcltemp_buff[0];
		ptr++;
		add++;
	}
	data_len = 0;
	//  free(ptr);
	//  ptr = NULL;
}
/**
 * @brief Reads key parameters from the internal flash and updates the Ocpp_Setting structure.
 * @param None
 * @return None
 */
void Read_Key_Params(void)
{
//	Internal_Flash_Read((unsigned long int*)&OCPP, sizeof(struct Config_Parameter));

	uint8_t lcltemp_buff[2]; 		//,hour_ok=0;;
	uint16_t i = 0; 				//j=0;//variable=0;
	uint32_t add = (3809 * w25qxx.SectorSize);

	uint16_t frame_length;

	uint16_t data_len = 0;

	if (sizeof(struct Config_Parameter_OCPP) % 2)
		data_len = sizeof(Ocpp_Setting) - 1; // SFlash_write(ptr,sizeof(data_to_flash)-1);
	else
		data_len = sizeof(Ocpp_Setting); //SFlash_write(ptr,sizeof(data_to_flash));

	frame_length = data_len;
	char *ptr = &Ocpp_Setting.LocalAuthListEnbl;

	for (i = 0; i < frame_length; i++) //while(data_len--)
	{
		W25qxx_ReadByte(&lcltemp_buff, add);
		*ptr = lcltemp_buff[0];
		ptr++;
		add++;
	}
	data_len = 0;
	//  free(ptr);
	//  ptr = NULL;
}
/**
 * @brief Writes key parameters from the Ocpp_Setting structure to the internal flash.
 * @param None
 * @return None
 */
void Write_Key_Params(void)
{
	char *data = &Ocpp_Setting.LocalAuthListEnbl;
	static uint32_t add = 0; //pointer_loc;//(w25qxx.SectorCount-1)*w25qxx.SectorSize;
	uint16_t page_len;
	uint16_t len = sizeof(Ocpp_Setting);

	if (InProcess == 0)
	{
		InProcess = 1;
		//Internal_Flash_Program((unsigned long int*)&OCPP, );
		add = (3809 * w25qxx.SectorSize);
		if (!(add % 4096))
		{
			W25qxx_EraseSector((add / 4096));
		}

		//	 First Page not starts from 00 and data length not in page boundary
		page_len = (add | 0xff) + 1 - add;
		if ((add & 0xff) && len > page_len)
		{
			//if (!writePage(add, data, page_len))
			//	return false;

			W25qxx_WritePage(data, add, 0, page_len);

			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}

		//if(add>=3824*w25qxx.SectorSize)
		//add=0;

		while (len)
		{
			page_len = len > 256 ? 256 : len;

			//if (!writePage(add, data, page_len))
			//	return false;
			W25qxx_WritePage(data, add, 0, page_len);
			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}
	}
	InProcess = 0;
	//free(data);
	//data = NULL;
}
/**
 * @brief Writes parameters from the OCPP structure to the internal flash.
 * @param None
 * @return None
 */
void Write_Params(void)
{
	char *data = &OCPP.fw_status;
	static uint32_t add = 0;//pointer_loc;//(w25qxx.SectorCount-1)*w25qxx.SectorSize;
	uint16_t page_len;
	uint16_t len = sizeof(OCPP);

	if (InProcess == 0)
	{
		InProcess = 1;
		//Internal_Flash_Program((unsigned long int*)&OCPP, );
		add = (3840 * w25qxx.SectorSize);
		if (!(add % 4096))
		{
			W25qxx_EraseSector((add / 4096));
		}

		//	 First Page not starts from 00 and data length not in page boundary
		page_len = (add | 0xff) + 1 - add;
		if ((add & 0xff) && len > page_len)
		{
			//if (!writePage(add, data, page_len))
			//	return false;

			W25qxx_WritePage(data, add, 0, page_len);

			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}

		//if(add>=3824*w25qxx.SectorSize)
		//add=0;

		while (len)
		{
			page_len = len > 256 ? 256 : len;

			//if (!writePage(add, data, page_len))
			//	return false;
			W25qxx_WritePage(data, add, 0, page_len);
			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}
		InProcess = 0;
	}

	//free(data);
	//data =NULL;
}
/**
 * @brief Reads CACH parameters from the internal flash and updates the Cash_Memory structure.
 * @param None
 * @return None
 */
void Read_CACH_Params(void)
{
//	Internal_Flash_Read((unsigned long int*)&OCPP, sizeof(struct Config_Parameter));

	uint8_t lcltemp_buff[2]; 		//,hour_ok=0;;
	uint16_t i = 0; 				//j=0;//variable=0;
	uint32_t add = (3848 * w25qxx.SectorSize);

	uint16_t frame_length;

	uint16_t data_len = 0;

	if (sizeof(struct Config_Parameter_Cach_Memory) % 2)
		data_len = sizeof(Cash_Memory) - 1; // SFlash_write(ptr,sizeof(data_to_flash)-1);
	else
		data_len = sizeof(Cash_Memory); //SFlash_write(ptr,sizeof(data_to_flash));

	frame_length = data_len;
	char *ptr = &Cash_Memory.transaction_id[0];

	for (i = 0; i < frame_length; i++) //while(data_len--)
	{
		W25qxx_ReadByte(&lcltemp_buff, add);
		*ptr = lcltemp_buff[0];
		ptr++;
		add++;
	}
	data_len = 0;
}
/**
 * @brief Writes CACH parameters from the Cash_Memory structure to the internal flash.
 * @param None
 * @return None
 */
void Write_CACH_Params(void)
{
	char *data = &Cash_Memory.transaction_id[0];
	static uint32_t add = 0; //pointer_loc;//(w25qxx.SectorCount-1)*w25qxx.SectorSize;
	uint16_t page_len;
	uint16_t len = sizeof(Cash_Memory);

	if (InProcess == 0)
	{
		InProcess = 1;
		//Internal_Flash_Program((unsigned long int*)&OCPP, );
		add = (3848 * w25qxx.SectorSize);
		if (!(add % 4096))
		{
			W25qxx_EraseSector((add / 4096));
		}

		//	 First Page not starts from 00 and data length not in page boundary
		page_len = (add | 0xff) + 1 - add;
		if ((add & 0xff) && len > page_len)
		{
			//if (!writePage(add, data, page_len))
			//	return false;
			W25qxx_WritePage(data, add, 0, page_len);

			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}

		//if(add>=3824*w25qxx.SectorSize)
		//add=0;

		while (len)
		{
			page_len = len > 256 ? 256 : len;

			//if (!writePage(add, data, page_len))
			//	return false;
			W25qxx_WritePage(data, add, 0, page_len);
			len -= page_len;
			data += page_len;
			add += page_len;

			if (!(add % 4096))
			{
				W25qxx_EraseSector((add / 4096));
			}
		}
	}
	InProcess = 0;
}
