#ifndef __FLASH_H_
#define	__FLASH_H_

#include "stm32l4xx_hal.h"
#include "calib_model.h"
#include "calib_piecewise_linear.h"
/* ========================
 * STM32L431CCT6 256KB Flash 自定义三段式 IAP升级系统
 * 结构：APP1 + APP2 + IAPDataBuffer
 * 通信方式：UART1 (RS485)
 * 校验方式：MD5 
 * APP1：存放出厂固件，作为恢复镜像，加上写保护。
 * APP2：与 APP1 构成双镜像，支持回滚机制。
 * App2缓存区：OTA 升级时下载新固件的临时存储区，大小与应用程序分区一致。
 * 备用区：可存储日志、临时数据或未来扩展功能。
 * Param(MD5) 和 APP应用参数 固定在 Flash 末尾（最后 4KB），避免被应用程序擦写覆盖。
 * ========================
 */

/* ========== Flash 分区方案 ==========
 * STM32L431CCT6 Flash: 256KB (0x08000000 - 0x0803FFFF) 0x40000字节
 * 
 *   APP1 			 		: 0x08000000 - 0x08013FFF (80KB)  
 *   APP2        		: 0x08014000 - 0x08027FFF (80KB)
 *   IAPDataBuffer	: 0x08028000 - 0x0803BFFF (80KB)

 * 	 系统配置		 		：0x0803C000 - 0x0803C7FF (2KB)  （通讯地址 mac地址）
 * 	 标定参数		 		：0x0803C800 - 0x0803C7FF (2KB)	（ADC标定值 温度校正表）
 * 	 快照参数		 		：0x0803D000 - 0x0803D7FF (2KB)	（统计类、刻度类参数）
 * 	 日志文件		 		：0x0803D800 - 0x0803FFFF (10KB)
 */
 
//------------------------宏定义-----------------------------// 
#define APP1_ADDR   				0x08000000 	// 烧录区 0x14000
#define APP2_ADDR         	0x08014000	// APP2 
#define IAPDataBuffer_ADDR 	0x08028000	// IAPDataBuffer 

#define FLASH_PARAM_ADDR  	0x0803C000  // STM32L431CCT6 最后一页起始地址 系统配置
#define IAP_PARAM_ADDR    	0x0803D000	// 升级标志位区  快照参数
#define CALIB_PARAM_ADDR		0x0803C800	// 传感器标定区域

#define UART_TIMEOUT      1000
#define APP_SIZE          (80 * 1024) // 80KB
#define PAGE_SIZE         2048				// 2KB

#define PACKET_SIZE       256					// 一包数据256字节
#define FLASH_PARAMS_MAGIC  0xA5A5

#define FLASH_ADDR_MAX 0x08040000			//写入数据地址小于STM32L431CC的flash地址最大值

#define SUCCESS               0
#define ERROR                 1

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

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

/**************         FLASH操作接口         *****************/
uint32_t Flash_ReadOneWord(uint32_t faddr);
void Flash_ErasePages(uint32_t faddr,uint32_t fdataNum);
uint8_t Flash_WriteOneWord(uint32_t faddr,uint32_t fdata32);
uint8_t Flash_WriteDoubleWord(uint32_t faddr,uint64_t fdata64);
void Flash_Write32(uint32_t faddr,uint32_t *fdata32, uint32_t fdata32Num);
void Flash_Write64(uint32_t faddr,uint64_t *fdata64, uint32_t fdata64Num);
void Flash_Read32(uint32_t faddr,uint32_t *fdata32,uint32_t fdata32Num);
void Flash_ReadBytes(uint32_t faddr,uint8_t *fdata8,uint32_t fdata8Num);
void Flash_ReadBytesto32(uint32_t faddr, uint8_t *fdata8, uint32_t fdata8Num);
uint8_t Flash_WriteRead(uint32_t fAdress, uint8_t *wData, uint32_t wDataLen, uint8_t *rData);

void save_params_to_flash(void);
void load_params_from_flash(void);
void LoadBootloaderParams(void);
void SaveBootloaderParams(void) ;
void print_device_params(void);
void PrintBootloaderParams(void);

void Save_Calib_Coeffs_ToFlash(CalibCoeffs_t *coeffs);
void Load_Calib_Coeffs_FromFlash(CalibCoeffs_t *coeffs);
//void Save_CalibPoints_ToFlash(const CalibPoints_t *points);
void Save_CalibPoints_ToFlash(void);
void Load_CalibPoints_FromFlash(void);
void Save_Calib_residualheight_ToFlash(void);
void Save_Calib_rodvol_ToFlash(void)	;
void print_calibPoints_params(void);


#endif

/**************************END OF FILE*************************/

