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

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

#include "stm32f4xx_hal.h"
#include "OCPP.h"
#include "w25qxx.h"
#include "iwdg.h"
#include <string.h>
#include <stdio.h>
/***********INCLUDE BLOCK END*************/


/***** Data Type, Constant, and Macro Definitions *****/
#define FLASH_USER_START_ADDR   0X0807FF00   /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR     0X0807FFFF  /* End @ of user Flash area */
#define DATA_32                 ((uint32_t)0x12345678)

/* Global variables*/
uint32_t Address = 0, PageError = 0;

const struct Config_Parameter default_params =
{
	 3,
	 "/fota.bin", //link
	 "113.20.17.179", //192.168.15.51
	 "no",  // username
	 "no",//  password
	 "8080",   //port
	 2,     //Communication Mode
	"EV",  //ssid
	"onlyforlubiev", // password
	"1111",
	"1111",
	"1111",
	 2,//ipv4V6				//V5.0.0
	 "m2misafe",//apn		//V5.0.0
	 0xbbaa,//boot loader magic value
	 0,
	"1234", //Password
	10,
	5,
	10,
	5,
	 "/services/CentralSystemServiceJson16/LUBI-BS-007",//"/services/CentralSystemServiceJson16/LUBI-BS-007", //link
	 "ocpp.grid-scape.com",// "api.plugeasy.in",
	 "no",
	 "1234@123",
	 "80",
	 {1,1}, //ocpp status
	 120, 	//4.X.8
	 600,
	 17,
	 40,	//4.X.8
	 "LUBI-type2",
	 "12345678",
//V501change
	 3810,
	 3280,
	 2810,
	 2260,
	 0,
	 0,	//energy1
	 0,	//energy2
	 0,	//energy3
//V501change
	 0xAA77 //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,   //AllowOfflineTXUnknownId	//4.X.8
	300, //HeartbeatIntvl
	{0,0,0,0},   //Operative
	0,
	0,
	20,
	100,
	0,
	0,
	0xAA55, //Magic Value
};


/* Extern Data Declarations */

extern UART_HandleTypeDef huart6;

/* Static Data Declarations */

uint8_t InProcess = 0;

__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;

/***** 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);
////////V4.1.4//////////
void Read_CACH_Params(void);
void Write_CACH_Params(void);
/////////////////////////

/***** Public Function Bodies END *****/

/* Base address of the Flash sectors */

/**
 * @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;
}
/**
 * @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;
}
/**
 * @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));
		   HAL_IWDG_Refresh(&hiwdg);
		}

	//	 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));
			}
			   HAL_IWDG_Refresh(&hiwdg);
		}

		//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));
			}
			 HAL_IWDG_Refresh(&hiwdg);
		}
	}
	InProcess =0;
}
/**
 * @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;
}
/**
 * @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];
    char *ptr= &Cash_Memory.Tag_Id[0][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 *ptr= &Cash_Memory.transaction_id[0];
	char *data = &Cash_Memory.Tag_Id[0][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;
}
