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

/******************************************************************************
* 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>&copy; 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, &param, 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****/