You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
761 lines
21 KiB
C
761 lines
21 KiB
C
/******************************************************************************
|
|
* file Src/common.c
|
|
* author YuLiang
|
|
* version 1.0.0
|
|
* date 10-Jun-2022
|
|
* brief This file provides all the common functions.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* <h2><center>© COPYRIGHT(c) 2022 LandPower</center></h2>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "main.h"
|
|
#include "menu.h"
|
|
|
|
#include "common.h"
|
|
#include "flash_if.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* 中断中打印限制长度. */
|
|
#define USART_PRINT_BUF_LEN 128
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
dev_info_t dev_info;
|
|
dev_record_t dev_record;
|
|
uint8_t number_str[NUM_LEN];
|
|
|
|
static uint32_t crc32Table[256];
|
|
static uint32_t dev_magic;
|
|
static uint32_t dev_magic_bak;
|
|
|
|
extern uint8_t aPacketData[PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE];
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Convert an Integer to a string
|
|
* @param p_str: The string output pointer
|
|
* @param intnum: The integer to be converted
|
|
* @retval None
|
|
*/
|
|
void Int2Str(uint8_t *p_str, uint32_t intnum)
|
|
{
|
|
uint32_t i, divider = 1000000000, pos = 0, status = 0;
|
|
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
p_str[pos++] = (intnum / divider) + 48;
|
|
|
|
intnum = intnum % divider;
|
|
divider /= 10;
|
|
if ((p_str[pos-1] == '0') & (status == 0))
|
|
{
|
|
pos = 0;
|
|
}
|
|
else
|
|
{
|
|
status++;
|
|
}
|
|
}
|
|
|
|
p_str[pos] = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Convert a string to an integer
|
|
* @param p_inputstr: The string to be converted
|
|
* @param p_intnum: The integer value
|
|
* @retval 1: Correct
|
|
* 0: Error
|
|
*/
|
|
uint32_t Str2Int(uint8_t *p_inputstr, uint32_t *p_intnum)
|
|
{
|
|
uint32_t i = 0, res = 0;
|
|
uint32_t val = 0;
|
|
|
|
if ((p_inputstr[0] == '0') && ((p_inputstr[1] == 'x') || (p_inputstr[1] == 'X')))
|
|
{
|
|
i = 2;
|
|
while ( ( i < 11 ) && ( p_inputstr[i] != '\0' ) )
|
|
{
|
|
if (ISVALIDHEX(p_inputstr[i]))
|
|
{
|
|
val = (val << 4) + CONVERTHEX(p_inputstr[i]);
|
|
}
|
|
else
|
|
{
|
|
/* Return 0, Invalid input */
|
|
res = 0;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
/* valid result */
|
|
if (p_inputstr[i] == '\0')
|
|
{
|
|
*p_intnum = val;
|
|
res = 1;
|
|
}
|
|
}
|
|
else /* max 10-digit decimal input */
|
|
{
|
|
while ( ( i < 11 ) && ( res != 1 ) )
|
|
{
|
|
if (p_inputstr[i] == '\0')
|
|
{
|
|
*p_intnum = val;
|
|
/* return 1 */
|
|
res = 1;
|
|
}
|
|
else if (((p_inputstr[i] == 'k') || (p_inputstr[i] == 'K')) && (i > 0))
|
|
{
|
|
val = val << 10;
|
|
*p_intnum = val;
|
|
res = 1;
|
|
}
|
|
else if (((p_inputstr[i] == 'm') || (p_inputstr[i] == 'M')) && (i > 0))
|
|
{
|
|
val = val << 20;
|
|
*p_intnum = val;
|
|
res = 1;
|
|
}
|
|
else if (ISVALIDDEC(p_inputstr[i]))
|
|
{
|
|
val = val * 10 + CONVERTDEC(p_inputstr[i]);
|
|
}
|
|
else
|
|
{
|
|
/* return 0, Invalid input */
|
|
res = 0;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @brief Print a string on the HyperTerminal
|
|
* @param p_string: The string to be printed
|
|
* @retval None
|
|
*/
|
|
void Serial_PutString(uint8_t *p_string)
|
|
{
|
|
uint16_t length = 0;
|
|
|
|
while (p_string[length] != '\0')
|
|
{
|
|
length++;
|
|
}
|
|
HAL_UART_Transmit(UartHandle, p_string, length, TX_TIMEOUT);
|
|
}
|
|
|
|
/**
|
|
* @brief Transmit a byte to the HyperTerminal
|
|
* @param param The byte to be sent
|
|
* @retval HAL_StatusTypeDef HAL_OK if OK
|
|
*/
|
|
HAL_StatusTypeDef Serial_PutByte( uint8_t param )
|
|
{
|
|
HAL_StatusTypeDef rv = HAL_ERROR;
|
|
|
|
/* May be timeouted... */
|
|
if ( UartHandle->gState == HAL_UART_STATE_TIMEOUT )
|
|
{
|
|
UartHandle->gState = HAL_UART_STATE_READY;
|
|
}
|
|
rv = HAL_UART_Transmit(UartHandle, ¶m, 1, TX_TIMEOUT);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* @brief Transmit a bytes to the HyperTerminal
|
|
* @param param The byte to be sent
|
|
* @retval HAL_StatusTypeDef HAL_OK if OK
|
|
*/
|
|
HAL_StatusTypeDef Serial_PutBytes(uint8_t* buf, uint16_t len, uint32_t timeout)
|
|
{
|
|
HAL_StatusTypeDef rv = HAL_ERROR;
|
|
|
|
/* May be timeouted... */
|
|
if ( UartHandle->gState == HAL_UART_STATE_TIMEOUT )
|
|
{
|
|
UartHandle->gState = HAL_UART_STATE_READY;
|
|
}
|
|
rv = HAL_UART_Transmit(UartHandle, buf, len, timeout);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* 通过 usart1 输出格式化字符. 原地等待发送, 与操作系统无关,
|
|
* 可以在中断中使用, 尽量不要在中断中使用, 太耗时间. */
|
|
void vty_print(char *format, ...)
|
|
{
|
|
static char buf[USART_PRINT_BUF_LEN];
|
|
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
while(HAL_UART_STATE_BUSY_TX == UartHandle->gState)
|
|
continue;
|
|
|
|
if (vsnprintf(buf, USART_PRINT_BUF_LEN, format, ap) > 0)
|
|
{
|
|
HAL_UART_Transmit(UartHandle, (uint8_t*)buf, strlen(buf), 1000);
|
|
}
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
/* 计算crc32 table值. */
|
|
static uint32_t _crc32_reflect( uint32_t value, uint8_t bits )
|
|
{
|
|
uint32_t reflection = 0;
|
|
|
|
for(uint8_t i = 0; i < bits ; ++i)
|
|
{
|
|
if (value & (1u << i ))
|
|
reflection |= 1 << (bits - 1 - i);
|
|
}
|
|
|
|
return reflection;
|
|
}
|
|
|
|
/**
|
|
* @brief 初始化crc32表.
|
|
* @param none
|
|
* @retval none
|
|
*/
|
|
void crc32_table_init(void)
|
|
{
|
|
uint32_t int1 = 1;
|
|
uint32_t const value_high_bit = int1 << 31u;
|
|
uint8_t dividend = 0;
|
|
|
|
do
|
|
{
|
|
uint32_t remainder = 0;
|
|
for(uint8_t mask = 1u << (8 - 1u); mask; mask >>= 1)
|
|
{
|
|
if (dividend & mask)
|
|
remainder ^= value_high_bit;
|
|
|
|
if (remainder & value_high_bit)
|
|
{
|
|
remainder <<= 1;
|
|
remainder ^= 0x04C11DB7u;
|
|
}
|
|
else
|
|
remainder <<= 1;
|
|
}
|
|
|
|
crc32Table[_crc32_reflect(dividend, 8)] = _crc32_reflect(remainder, 32);
|
|
}
|
|
while(++dividend);
|
|
}
|
|
|
|
/**
|
|
* @brief 计算crc32值.
|
|
* @param buf: 数据.
|
|
* @param len: 数据长度.
|
|
* @retval crc32值.
|
|
*/
|
|
uint32_t crc32_update(uint32_t crc, char* buf, uint32_t len)
|
|
{
|
|
uint32_t i = 0;
|
|
|
|
for(i = 0; i < len; i++)
|
|
crc = crc32Table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
|
|
|
|
return crc;
|
|
}
|
|
|
|
/* 读取config主份存储区. */
|
|
static HAL_StatusTypeDef _dev_info_read(void)
|
|
{
|
|
uint8_t i = 0;
|
|
HAL_StatusTypeDef rv = HAL_ERROR;
|
|
|
|
memset(&dev_info, 0, sizeof(dev_info_t));
|
|
|
|
/* 读取主存储区. */
|
|
for(i = 0; i < DEV_FLASH_REPETITION; i++)
|
|
{
|
|
rv = spi_flash_read(INFO_ADDRESS, (uint8_t*)(&dev_info), sizeof(dev_info_t));
|
|
if (HAL_OK == rv)
|
|
break;
|
|
|
|
HAL_Delay(5000);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* 读取info备份存储区. */
|
|
static HAL_StatusTypeDef _dev_info_read_bak(void)
|
|
{
|
|
uint8_t i = 0;
|
|
HAL_StatusTypeDef rv = HAL_ERROR;
|
|
|
|
memset(&dev_info, 0, sizeof(dev_info_t));
|
|
|
|
/* 读取备存储区. */
|
|
for(i = 0; i < DEV_FLASH_REPETITION; i++)
|
|
{
|
|
rv = spi_flash_read(INFO_ADDRESS_BAK, (uint8_t*)(&dev_info), sizeof(dev_info_t));
|
|
if (HAL_OK == rv)
|
|
break;
|
|
|
|
HAL_Delay(5000);
|
|
}
|
|
|
|
if (HAL_OK == rv)
|
|
{
|
|
dev_magic = dev_info.magic;
|
|
dev_magic_bak = dev_info.magic_bak;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* 保存信息文件. */
|
|
static HAL_StatusTypeDef _dev_info_save(uint32_t addr)
|
|
{
|
|
uint8_t i = 0;
|
|
HAL_StatusTypeDef rv = HAL_OK;
|
|
|
|
/* 存多次失败才算失败. */
|
|
for(i = 0; i < DEV_FLASH_REPETITION; i++)
|
|
{
|
|
rv = spi_flash_erase(addr, SPI_CMD_SECTOR_ERASE);
|
|
rv |= spi_flash_write(addr, (uint8_t*)(&dev_info), sizeof(dev_info_t));
|
|
if (HAL_OK == rv)
|
|
break;
|
|
}
|
|
|
|
Serial_PutString("Info(");
|
|
Int2Str(number_str, addr);
|
|
Serial_PutString(number_str);
|
|
Serial_PutString(") save ");
|
|
Int2Str(number_str, rv);
|
|
Serial_PutString(number_str);
|
|
Serial_PutString(".\r\n");
|
|
return rv;
|
|
}
|
|
|
|
/* 恢复出厂信息. */
|
|
static HAL_StatusTypeDef _dev_info_default_set(void)
|
|
{
|
|
HAL_StatusTypeDef rv = HAL_OK;
|
|
|
|
memset(&dev_info, 0, sizeof(dev_info_t));
|
|
dev_info.magic = INIT_DONE_MAGIC;
|
|
dev_info.magic_bak = INIT_DONE_MAGIC;
|
|
|
|
dev_info.type_m = 0x2;
|
|
dev_info.type_s = 0x1;
|
|
dev_info.mac[0] = 0x00; dev_info.mac[1] = 0x19; dev_info.mac[2] = 0x20;
|
|
dev_info.mac[3] = 0x22; dev_info.mac[4] = 0x11; dev_info.mac[5] = 0x01;
|
|
dev_info.id[0] = dev_info.mac[5]; dev_info.id[1] = dev_info.mac[4];
|
|
dev_info.id[2] = dev_info.mac[3]; dev_info.id[3] = dev_info.mac[2];
|
|
dev_info.ip[0] = 10;
|
|
memcpy(&dev_info.ip[1], &dev_info.mac[3], 3);
|
|
dev_info.ip_mask[0] = 255;
|
|
dev_info.ip_gw[0] = 10; dev_info.ip_gw[3] = 1;
|
|
dev_info.server_ip[0] = 111;dev_info.server_ip[1] = 47;
|
|
dev_info.server_ip[2] = 21;dev_info.server_ip[3] = 141;
|
|
dev_info.server_port = 8809;
|
|
|
|
snprintf((char*)dev_info.boot_version, DEV_VERSION_STR_LEN, "V%d.%d.%d.%d", dev_info.type_m, dev_info.type_s,
|
|
VERSION_MAJOR, VERSION_MINOR);
|
|
strncpy((char*)dev_info.boot_compile_time, COMPILE_TIME, DEV_COMPILE_TIME_LEN - 1);
|
|
|
|
rv = dev_info_save();
|
|
|
|
Serial_PutString("Info set default ");
|
|
Int2Str(number_str, rv);
|
|
Serial_PutString(number_str);
|
|
Serial_PutString(".\r\n");
|
|
return rv;
|
|
}
|
|
|
|
/* 判断分区是否完整. */
|
|
static int32_t _dev_info_is_intact(uint32_t magic, uint32_t magic_bak)
|
|
{
|
|
if (magic != INIT_DONE_MAGIC && magic != UPDATE_MAGIC && magic != UPDATE_OK_MAGIC && magic != UPDATE_ERROR_MAGIC)
|
|
return FALSE;
|
|
if (magic_bak != INIT_DONE_MAGIC)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief 初始化设备信息文件.
|
|
* @param none
|
|
* @retval HAL_xx.
|
|
*/
|
|
HAL_StatusTypeDef dev_info_init(void)
|
|
{
|
|
HAL_StatusTypeDef rv = HAL_OK;
|
|
|
|
/* 检查结构体大小. */
|
|
if (sizeof(dev_info_t) != DEV_INFO_SIZE)
|
|
{
|
|
Serial_PutString("Info size is not 512.\r\n");
|
|
while(1)
|
|
{
|
|
HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
|
|
HAL_Delay(50);
|
|
}
|
|
}
|
|
|
|
/* 读取失败不做处理. */
|
|
_dev_info_read_bak();
|
|
_dev_info_read();
|
|
|
|
/* 主备存储区都正常,什么都不用做. */
|
|
if (_dev_info_is_intact(dev_info.magic, dev_info.magic_bak) && _dev_info_is_intact(dev_magic, dev_magic_bak))
|
|
NULL;
|
|
/* 主正常,备不正常,使用主配置覆盖备配置. */
|
|
else if(_dev_info_is_intact(dev_info.magic, dev_info.magic_bak) && !(_dev_info_is_intact(dev_magic, dev_magic_bak)))
|
|
rv = _dev_info_save(INFO_ADDRESS_BAK);
|
|
/* 主不正常,备正常,使用备配置覆盖主配置. */
|
|
else if(!(_dev_info_is_intact(dev_info.magic, dev_info.magic_bak)) && _dev_info_is_intact(dev_magic, dev_magic_bak))
|
|
{
|
|
/* 如果读取备失败,恢复出厂配置. */
|
|
if ((rv = _dev_info_read_bak()) != HAL_OK)
|
|
_dev_info_default_set();
|
|
else
|
|
rv = _dev_info_save(INFO_ADDRESS);
|
|
}
|
|
/* 其他情况一律视为flash没有被初始化. */
|
|
else
|
|
rv = _dev_info_default_set();
|
|
|
|
/* 版本发生变化,保存版本信息. */
|
|
if (IS_VERSION_CHG)
|
|
{
|
|
snprintf((char*)dev_info.boot_version, DEV_VERSION_STR_LEN, "V%d.%d.%d.%d", dev_info.type_m, dev_info.type_s,
|
|
VERSION_MAJOR, VERSION_MINOR);
|
|
strncpy((char*)dev_info.boot_compile_time, COMPILE_TIME, DEV_COMPILE_TIME_LEN - 1);
|
|
|
|
rv |= dev_info_save();
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* @brief 读取record主份存储区.
|
|
* @param none
|
|
* @retval HAL_xx.
|
|
*/
|
|
HAL_StatusTypeDef dev_record_read(void)
|
|
{
|
|
uint8_t i = 0;
|
|
HAL_StatusTypeDef rv = HAL_ERROR;
|
|
|
|
memset(&dev_record, 0, sizeof(dev_record_t));
|
|
|
|
/* 读取存储区. */
|
|
for(i = 0; i < DEV_FLASH_REPETITION; i++)
|
|
{
|
|
rv = spi_flash_read(RECORD_ADDRESS, (uint8_t*)(&dev_record), sizeof(dev_record_t));
|
|
if (HAL_OK == rv)
|
|
break;
|
|
|
|
HAL_Delay(5000);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief 保存设备信息文件.
|
|
* @param none
|
|
* @retval HAL_xx.
|
|
*/
|
|
HAL_StatusTypeDef dev_info_save(void)
|
|
{
|
|
HAL_StatusTypeDef rv = HAL_OK;
|
|
|
|
rv |= _dev_info_save(INFO_ADDRESS);
|
|
rv |= _dev_info_save(INFO_ADDRESS_BAK);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* 对需要写入内部flash的数据进行CRC32校验. */
|
|
void _updata_crc_check(uint32_t addr, uint32_t size)
|
|
{
|
|
uint16_t write_size = 0;
|
|
uint32_t crc32_value = 0xffffffff;
|
|
bin_pkt_tail_t *pkt_tail = NULL;
|
|
|
|
/* 计算crc32. */
|
|
size = size - 4;
|
|
while(size > 0)
|
|
{
|
|
/* 计算每次写入的数据大小. */
|
|
if (size > PACKET_1K_SIZE)
|
|
write_size = PACKET_1K_SIZE;
|
|
else
|
|
write_size = size;
|
|
|
|
/* 从spi flash读取升级包. */
|
|
if (spi_flash_read(addr, aPacketData, write_size) != HAL_OK)
|
|
goto CRC_CHECK_ERROR;
|
|
|
|
crc32_value = crc32_update(crc32_value, (char*)aPacketData, write_size);
|
|
|
|
/* 重新计算flash地址和剩余数据大小. */
|
|
addr += write_size;
|
|
size -= write_size;
|
|
}
|
|
|
|
/* 从spi flash读取报文头. */
|
|
if (spi_flash_read(addr + 4 - sizeof(bin_pkt_tail_t), aPacketData, sizeof(bin_pkt_tail_t)) != HAL_OK)
|
|
goto CRC_CHECK_ERROR;
|
|
pkt_tail = (bin_pkt_tail_t*)aPacketData;
|
|
|
|
/* 比较报文头信息 */
|
|
if (crc32_value != pkt_tail->crc32
|
|
|| dev_info.type_m != pkt_tail->dev_type_m
|
|
|| dev_info.type_s != pkt_tail->dev_type_s
|
|
|| pkt_tail->file_type != 2)
|
|
{
|
|
vty_print("Type %d %d %d %x %x\r\n", dev_info.type_m, dev_info.type_s, pkt_tail->file_type, pkt_tail->crc32, crc32_value);
|
|
goto CRC_CHECK_ERROR;
|
|
}
|
|
|
|
return;
|
|
|
|
CRC_CHECK_ERROR:
|
|
Serial_PutString(" Programming failure start with old APP!\n\r");
|
|
/* 设置升级标志. */
|
|
dev_info.magic = UPDATE_ERROR_MAGIC;
|
|
dev_info_save();
|
|
start_app();
|
|
}
|
|
|
|
/* 擦除内部app,并升级app. */
|
|
static void _updata_process(void)
|
|
{
|
|
uint32_t spi_flash_address = TFTP_APP_ADDRESS;
|
|
uint32_t flash_write_address = APP_ADDRESS;
|
|
uint32_t fireware_size = dev_info.spi_fireware_size;
|
|
uint16_t write_size = 0;
|
|
uint16_t write_flash_size = 0;
|
|
|
|
Serial_PutString("\r\nEntry updata.\r\n");
|
|
|
|
/* 擦除内部flash. */
|
|
if (FLASH_If_Erase(APP_ADDRESS) != FLASHIF_OK)
|
|
goto UPDATA_ERROR;
|
|
|
|
/* 循环写入内部flash. */
|
|
while(fireware_size > 0)
|
|
{
|
|
/* 计算每次写入的数据大小. */
|
|
if (fireware_size > PACKET_1K_SIZE)
|
|
write_size = PACKET_1K_SIZE;
|
|
else
|
|
write_size = fireware_size;
|
|
|
|
/* 从spi flash复制到内部flash. */
|
|
if (spi_flash_read(spi_flash_address, aPacketData, write_size) != HAL_OK)
|
|
goto UPDATA_ERROR;
|
|
|
|
/* 因为内部flash是4byte写的,如果img不是4byte对齐的可能最后几个字节写漏了,这里保证最后几个字节可以写入. */
|
|
write_flash_size = write_size / 4;
|
|
if (write_size % 4 != 0)
|
|
write_flash_size++;
|
|
|
|
if (FLASH_If_Write(flash_write_address, (uint32_t*)(aPacketData), write_flash_size) != FLASHIF_OK)
|
|
goto UPDATA_ERROR;
|
|
|
|
/* 重新计算flash地址和剩余数据大小. */
|
|
spi_flash_address += write_size;
|
|
flash_write_address += write_size;
|
|
fireware_size -= write_size;
|
|
}
|
|
|
|
/* 设置升级标志. */
|
|
fireware_size = spi_flash_address - TFTP_APP_ADDRESS;
|
|
dev_info.magic = INIT_DONE_MAGIC;
|
|
dev_info.fireware_size = fireware_size;
|
|
dev_info_save();
|
|
|
|
/* 打印升级信息. */
|
|
Serial_PutString(" Programming completed.\n\r");
|
|
Int2Str(number_str, fireware_size);
|
|
Serial_PutString(" Size: ");
|
|
Serial_PutString(number_str);
|
|
Serial_PutString(" Bytes\r\n");
|
|
start_app();
|
|
|
|
UPDATA_ERROR:
|
|
Serial_PutString(" Programming failure reset try again!\n\r");
|
|
/* 设置升级标志. */
|
|
dev_info.magic = UPDATE_ERROR_MAGIC;
|
|
dev_info_save();
|
|
HAL_NVIC_SystemReset();
|
|
}
|
|
|
|
/* 判断APP是否完整. */
|
|
static int32_t _is_app_intact(void)
|
|
{
|
|
bin_pkt_tail_t pkt_tail;
|
|
uint32_t size = 0;
|
|
uint32_t crc32_value = 0xffffffff;
|
|
|
|
/* 大小不对. */
|
|
if (dev_info.fireware_size < 1024)
|
|
return FALSE;
|
|
|
|
/* 计算crc. */
|
|
size = dev_info.fireware_size - 4;
|
|
crc32_value = crc32_update(crc32_value, (char*)APP_ADDRESS, size);
|
|
|
|
/* 读取包头. */
|
|
memcpy(&pkt_tail, (void*)(APP_ADDRESS + dev_info.fireware_size - sizeof(bin_pkt_tail_t)), sizeof(bin_pkt_tail_t));
|
|
|
|
/* 比较报文头信息 */
|
|
if (crc32_value != pkt_tail.crc32
|
|
|| dev_info.type_m != pkt_tail.dev_type_m
|
|
|| dev_info.type_s != pkt_tail.dev_type_s
|
|
|| pkt_tail.file_type != 2)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief 选择进入哪种IAP处理方式.
|
|
* @param none
|
|
* @retval none
|
|
*/
|
|
void menu_entry(void)
|
|
{
|
|
uint8_t key = 0;
|
|
uint8_t i = 0;
|
|
|
|
/* 如果软件设置了网口升级, 进入网口升级. */
|
|
if (UPDATE_MAGIC == dev_info.magic)
|
|
{
|
|
_updata_crc_check(TFTP_APP_ADDRESS, dev_info.spi_fireware_size);
|
|
_updata_process();
|
|
return;
|
|
}
|
|
|
|
/* 1. 如果APP校验不正确;
|
|
2. 看门狗重启;
|
|
3. 命令行iap模式重启.
|
|
以上3中情况则出现IAP启动进度条, 用户输入ctrl+P进入IAP, 超时自动启动APP. */
|
|
if (_is_app_intact()
|
|
&& dev_record.reset_type != RESET_IAP
|
|
&& dev_record.reset_type != RESET_WATCHDOG)
|
|
{
|
|
start_app();
|
|
}
|
|
|
|
Serial_PutString("Wait to boot 3s...");
|
|
|
|
/* 等待串口命令, 是否强制进入IAP. */
|
|
for(i = 0; i < ENTRY_IAP_DELAY_COUNTER; i++)
|
|
{
|
|
if (HAL_UART_Receive(UartHandle, &key, 1, ENTRY_IAP_RX_TIMEOUT) != HAL_OK)
|
|
continue;
|
|
|
|
/* 键盘输入 "ctrl+P" 或者 "*" 进入串口 boot. */
|
|
if (CONTROL('P') == key || '*' == key)
|
|
Main_Menu();
|
|
/* 键盘输入 "ctrl+U" 强制进入升级. */
|
|
else if(CONTROL('U') == key)
|
|
{
|
|
_updata_crc_check(TFTP_APP_ADDRESS, dev_info.spi_fireware_size);
|
|
_updata_process();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* 超时直接启动应用. */
|
|
start_app();
|
|
}
|
|
|
|
void watchdog_refresh(void)
|
|
{
|
|
HAL_GPIO_WritePin(WDG_GPIO_Port, WDG_Pin, GPIO_PIN_SET);
|
|
HAL_Delay(1);
|
|
HAL_GPIO_WritePin(WDG_GPIO_Port, WDG_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
#if !defined(iap_htons)
|
|
/**
|
|
* Convert an u16_t from host- to network byte order.
|
|
*
|
|
* @param n u16_t in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
uint16_t iap_htons(uint16_t n)
|
|
{
|
|
return (uint16_t)PP_HTONS(n);
|
|
}
|
|
#endif /* iap_htons */
|
|
|
|
#if !defined(iap_htonl)
|
|
/**
|
|
* Convert an u32_t from host- to network byte order.
|
|
*
|
|
* @param n u32_t in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
uint32_t iap_htonl(uint32_t n)
|
|
{
|
|
return (uint32_t)PP_HTONL(n);
|
|
}
|
|
#endif /* iap_htonl */
|
|
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
|
/************************ (C) COPYRIGHT LandPower *****END OF FILE****/
|