/*************************** (C) COPYRIGHT 2017 CXHY ****************************
 * 文件名  ：stmflash.c
 * 描  述  ：STM32-FLASH操作函数
 * 版  本  ：V1.0
 * 作  者  ：XuZhongPing
 * 日  期  ：2017/07/23 
*********************************************************************************/
#include "stmflash.h"
#include "stdio.h"
#include "delay.h"
#include "timer.h"
#include "gsm_gprs.h"
#include "data_typedef.h"
 
#if STM32_FLASH_SIZE < 256									//中容量和小容量的MCU一页的大小都为1K字节
#define STM_SECTOR_SIZE 1024 								//一页字节数
#else 
#define STM_SECTOR_SIZE	2048
#endif	
	 
uint16_t STMFLASH_BUF[STM_SECTOR_SIZE/2];		//用于保存一个扇区的数据缓存，擦除扇区时需先读取原来保存的数据，然后再重新写入

/*
***********************************************************************
*	函 数 名: STMFLASH_ReadHalfWord
*	功能说明: 读取指定地址的半字(16位数据)
*	形    参：faddr:读地址(此地址必须为2的倍数!!)
*	返 回 值: 对应地址保存的数据
***********************************************************************
*/
uint16_t STMFLASH_ReadHalfWord(uint32_t faddr)
{
	return *(vu16*)faddr; 
}

/*
***********************************************************************
*	函 数 名: STMFLASH_Write_NoCheck
*	功能说明: 不检查的向指定地址写入数据
*	形    参：WriteAddr:起始地址
*						pBuffer:数据指针
*						NumToWrite:半字(16位)数
*	返 回 值: 无 
***********************************************************************
*/
void STMFLASH_Write_NoCheck(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite)   
{ 			 		 
	uint16_t i;
	
	for(i = 0; i < NumToWrite; i++)
	{
		FLASH_ProgramHalfWord(WriteAddr, pBuffer[i]);
		WriteAddr += 2;																		//地址增加2.
	}  
} 

/*
***********************************************************************
*	函 数 名: STMFLASH_Write
*	功能说明: 从指定地址开始写入指定长度的数据
*	形    参：WriteAddr:起始地址(此地址必须为2的倍数!!)
*						pBuffer:数据指针
*						NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
*	返 回 值: 无 
***********************************************************************
*/
void STMFLASH_Write(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite)	
{
	uint32_t secpos;	   								//扇区地址
	uint16_t secoff;	   								//扇区内偏移地址(16位字计算)
	uint16_t secremain; 								//扇区内剩余地址(16位字计算)	    
	uint32_t offaddr;   								//去掉0X08000000后的地址
	uint16_t i;   
	
	if((WriteAddr < STM32_FLASH_BASE) || (WriteAddr >= (STM32_FLASH_BASE + 1024*STM32_FLASH_SIZE)))return;	//非法地址
	FLASH_Unlock();																		//解锁
	offaddr = WriteAddr-STM32_FLASH_BASE;							//实际偏移地址.
	secpos = offaddr/STM_SECTOR_SIZE;									//扇区地址  0~127 for STM32F103RBT6
	secoff = (offaddr%STM_SECTOR_SIZE)/2;							//在扇区内的偏移(2个字节为基本单位.)
	secremain = STM_SECTOR_SIZE/2 - secoff;						//扇区剩余空间大小   
	if(NumToWrite <= secremain)												//不大于该扇区范围
	{
		secremain = NumToWrite;
	}
	while(1) 
	{	
		STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE/2);		//读出整个扇区的内容
		for(i = 0; i < secremain; i++)									//校验数据
		{
			if(STMFLASH_BUF[secoff + i] != 0XFFFF)break;	//需要擦除  	  
		}
		if(i<secremain)			//需要擦除
		{
			FLASH_ErasePage(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE);	//擦除这个扇区
			for(i = 0; i < secremain; i++)								//复制要写入的数据
			{
				STMFLASH_BUF[i + secoff] = pBuffer[i];	  
			}
			STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE/2);		//写入整个扇区  
		}else{			//写已经擦除了的,直接写入扇区剩余区间.
			STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);
		}
			 				   
		if(NumToWrite == secremain)		//写入结束了
		{
			break;								
		}else{		//写入未结束
			secpos++;																			//扇区地址增1
			secoff = 0;																		//偏移位置为0 	 
			pBuffer += secremain;  												//指针偏移
			WriteAddr += secremain;												//写地址偏移	   
			NumToWrite -= secremain;											//字节(16位)数递减
			if(NumToWrite > (STM_SECTOR_SIZE/2))					//下一个扇区还是写不完
			{
				secremain = STM_SECTOR_SIZE/2;
			}else{		//下一个扇区可以写完了
				secremain = NumToWrite;
			}
		}	 
	}
	FLASH_Lock();																			//上锁
}

/*
***********************************************************************
*	函 数 名: STMFLASH_Read
*	功能说明: 从指定地址开始读出指定长度的数据
*	形    参：ReadAddr:起始地址
*						pBuffer:数据指针
*						NumToRead:半字(16位)数
*	返 回 值: 无 
***********************************************************************
*/
void STMFLASH_Read(uint32_t ReadAddr, uint16_t *pBuffer, uint16_t NumToRead)   	
{
	uint16_t i;
	
	for(i = 0; i < NumToRead; i++)
	{
		pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr);				//读取2个字节.
		ReadAddr += 2;																			//偏移2个字节.	
	}
}


/*
***********************************************************************
*	函 数 名: STMFLASH_WriteHalfWord
*	功能说明: 向指定FLASH地址写入一个16位数据
*	形    参：WriteAddr:起始地址
*						WriteData:要写入的数据
*	返 回 值: 无 
***********************************************************************
*/
void STMFLASH_WriteHalfWord(uint32_t WriteAddr, uint16_t WriteData)   	
{
// 	STMFLASH_Write(WriteAddr, &WriteData, 1);			//写入一个字（16位） 
	FLASH_ProgramHalfWord(WriteAddr, WriteData);
}

/*
***********************************************************************
*	函 数 名: DeviceConfigErase
*	功能说明: 擦除参数保存区的flash
*	形    参：无
*	返 回 值: 无 
***********************************************************************
*/
void DeviceConfigErase(uint32_t WriteAddr)
{
	uint32_t secpos;	   								//扇区地址
	uint16_t secoff;	   								//扇区内偏移地址(16位字计算)  
	uint32_t offaddr;   								//去掉0X08000000后的地址
	
	if((WriteAddr < STM32_FLASH_BASE) || (WriteAddr >= (STM32_FLASH_BASE + 1024*STM32_FLASH_SIZE)))return;	//非法地址
	
	offaddr = WriteAddr-STM32_FLASH_BASE;							//实际偏移地址.
	secpos = offaddr/STM_SECTOR_SIZE;									//扇区地址  0~127 for STM32F103RBT6

	FLASH_ErasePage(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE);	//擦除这个扇区
}

/*
***********************************************************************
*	函 数 名: SaveDeviceConfig
*	功能说明: 保存设备配置的参数
*	形    参：无
*	返 回 值: 无 
***********************************************************************
*/
void SaveDeviceConfig(void)
{
	uint8_t i = 0;
	uint16_t uTempData = 0;
	uint32_t flashSaveAddr = 0;
	
	flashSaveAddr = FLASH_SAVE_ADDR;
	printf("\r\nTime1 = %d\r\n", time_value);
	
	FLASH_Unlock();																		//解锁
	DeviceConfigErase(FLASH_SAVE_ADDR);
	
	//数据保存成功标志位
	uTempData = 0xFFFF;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//设备操作密码
	uTempData = (uint16_t)(setPassword >> 16);
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);	
	flashSaveAddr += 2;
	uTempData = (uint16_t)setPassword;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//设备客户号
	uTempData = (uint16_t)(setCustomerID >> 16);
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);	
	flashSaveAddr += 2;
	uTempData = (uint16_t)setCustomerID;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//设备类型及通道数量
	uTempData = (uint16_t)(setDeviceType << 8) | setDevChannelNumbers;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//第1路投口相关参数
	uTempData = (uint16_t)(setDevChannel1Type << 8) | setDevChannel1DisDepthVal;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	uTempData = (uint16_t)(setDevChannel1DisMaxVal << 8) | setDevChannel1DisAlarmPercent;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//第2路投口相关参数
	uTempData = (uint16_t)(setDevChannel2Type << 8) | setDevChannel2DisDepthVal;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	uTempData = (uint16_t)(setDevChannel2DisMaxVal << 8) | setDevChannel2DisAlarmPercent;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//第3路投口相关参数
	uTempData = (uint16_t)(setDevChannel3Type << 8) | setDevChannel3DisDepthVal;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	uTempData = (uint16_t)(setDevChannel3DisMaxVal << 8) | setDevChannel3DisAlarmPercent;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//第4路投口相关参数
	uTempData = (uint16_t)(setDevChannel4Type << 8) | setDevChannel4DisDepthVal;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	uTempData = (uint16_t)(setDevChannel4DisMaxVal << 8) | setDevChannel4DisAlarmPercent;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	flashSaveAddr += 24;			//预留32个字节用于保存投口通道参数
	
	//禁用IC卡用户功能和启用收运IC卡二维码功能标志位
	uTempData = (uint16_t)(setDisableICCardFunStatus << 8) | setEnableCleanQRCodeStatus;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	
	//设备编号长度
	STMFLASH_WriteHalfWord(flashSaveAddr, setDeviceIdLength);
	flashSaveAddr += 2;
	
	printf("\r\nTime2 = %d\r\n", time_value);
	//设备编号
	for(i = 0; i < 32; i+=2)
	{
		uTempData = (uint16_t)(setDeviceIdBuf[i] << 8) | setDeviceIdBuf[i+1];
		STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
		flashSaveAddr += 2;
	}
	printf("\r\nTime3 = %d\r\n", time_value);
	
	//服务器IP地址及端口号
	uTempData = (uint16_t)(setIpAddr0 << 8) | setIpAddr1;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	uTempData = (uint16_t)(setIpAddr2 << 8) | setIpAddr3;
	STMFLASH_WriteHalfWord(flashSaveAddr, uTempData);
	flashSaveAddr += 2;
	STMFLASH_WriteHalfWord(flashSaveAddr, setIpPort);
	flashSaveAddr += 2;
	
	//标志参数保存完成
	uTempData = 0x0A0B;
	STMFLASH_WriteHalfWord(FLASH_SAVE_ADDR, uTempData);
	FLASH_Lock();																			//上锁
	
	printf("\r\nTime4 = %d\r\n", time_value);
	printf("\r\n参数保存成功！\r\n");
}

/*
***********************************************************************
*	函 数 名: GetDeviceConfig
*	功能说明: 取得设备配置参数
*	形    参：无
*	返 回 值: 无 
***********************************************************************
*/
uint8_t GetDeviceConfig(void)
{
	uint8_t i = 0;
	uint16_t uTempData = 0;
	uint32_t flashSaveAddr = 0;
	
	flashSaveAddr = FLASH_SAVE_ADDR;
	
	uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
	flashSaveAddr += 2;

	if(uTempData == 0x0A0B)
	{
		//设备操作密码
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setPassword = uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setPassword = (setPassword << 16) | uTempData;
		
		//设备客户号
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setCustomerID = uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setCustomerID = (setCustomerID << 16) | uTempData;
		
		//设备类型
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDeviceType = uTempData >> 8;
		setDevChannelNumbers = (uint8_t)uTempData;
		
		//第1路投口相关参数
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel1Type = uTempData >> 8;
		setDevChannel1DisDepthVal = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel1DisMaxVal = uTempData >> 8;
		setDevChannel1DisAlarmPercent = (uint8_t)uTempData;
		
		//第2路投口相关参数
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel2Type = uTempData >> 8;
		setDevChannel2DisDepthVal = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel2DisMaxVal = uTempData >> 8;
		setDevChannel2DisAlarmPercent = (uint8_t)uTempData;
		
		//第3路投口相关参数
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel3Type = uTempData >> 8;
		setDevChannel3DisDepthVal = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel3DisMaxVal = uTempData >> 8;
		setDevChannel3DisAlarmPercent = (uint8_t)uTempData;
		
		//第4路投口相关参数
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel4Type = uTempData >> 8;
		setDevChannel4DisDepthVal = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDevChannel4DisMaxVal = uTempData >> 8;
		setDevChannel4DisAlarmPercent = (uint8_t)uTempData;
		
		flashSaveAddr += 24;
		
		//禁用IC卡用户功能和启用收运IC卡二维码功能标志位
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDisableICCardFunStatus = uTempData >> 8;
		setEnableCleanQRCodeStatus = (uint8_t)uTempData;	
		
		//设备编号长度
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setDeviceIdLength = uTempData;
		
		//设备编号
		for(i = 0; i < 32; i+=2)
		{
			uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
			flashSaveAddr += 2;
			setDeviceIdBuf[i] = uTempData >> 8;
			setDeviceIdBuf[i+1] = (uint8_t)uTempData;				
		}
		
		//服务器IP地址及端口号
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setIpAddr0 = uTempData >> 8;
		setIpAddr1 = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setIpAddr2 = uTempData >> 8;
		setIpAddr3 = (uint8_t)uTempData;
		uTempData = STMFLASH_ReadHalfWord(flashSaveAddr);
		flashSaveAddr += 2;
		setIpPort = uTempData;
		
		printf("\r\n参数读取成功！\r\n");
		
		printf("\r\nSet P=%d; ID=%d; Type=%d; Cnt=%d; T1=%d, h1=%d, H1=%d, A1=%d; T2=%d, h2=%d, H2=%d, A2=%d, ICE=%d; ICQR=%d; "\
						"devLen=%d; devID=%s; IP=%d.%d.%d.%d:%d\r\n",
						setPassword,
						setCustomerID,
						setDeviceType,
						setDevChannelNumbers,
						setDevChannel1Type, setDevChannel1DisDepthVal, setDevChannel1DisMaxVal, setDevChannel1DisAlarmPercent,
						setDevChannel2Type, setDevChannel2DisDepthVal, setDevChannel2DisMaxVal, setDevChannel2DisAlarmPercent,
						setDisableICCardFunStatus,
						setEnableCleanQRCodeStatus,
						setDeviceIdLength,
						setDeviceIdBuf,
						setIpAddr0,setIpAddr1,setIpAddr2,setIpAddr3,setIpPort
					);
						
		return 0;
	}else{
		printf("\r\n还没有保存过设备参数！\r\n");
		return 1;
	}
}

/*
***********************************************************************
*	函 数 名: ResetDeviceConfig
*	功能说明: 恢复设备配置参数到出厂设置
*	形    参：无
*	返 回 值: 无 
***********************************************************************
*/
void ResetDeviceConfig(void)
{
	FLASH_Unlock();																		//解锁
	DeviceConfigErase(FLASH_SAVE_ADDR);
	FLASH_Lock();																			//上锁
	printf("\r\n设备配置参数已恢复成出厂设置！\r\n");
}

/******************** (C) COPYRIGHT 2017 CXHY *****END OF FILE*******************/
