Files
gd32e230_bootloader/Src/bootloader.c

476 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "bootloader.h"
#include "board_config.h"
#include "gd32e23x.h"
#include "uart_ring_buffer.h"
#include "systick.h"
uint8_t ymodem_rx_buffer[YMODEM_RX_BUFFER_SIZE] = {0};
uint16_t ymodem_rx_count = 0;
static uint8_t temp_buffer[PACKET_1K_SIZE]; // 临时缓冲区,用于接收数据包
/**
* @brief 擦除Flash页面适配同事的flash_earse函数
* @param page_address 要擦除的页面地址
* @return 擦除结果状态
*/
uint8_t flash_erase_page(uint32_t page_address)
{
fmc_state_enum fmc_state = FMC_READY;
// 清除Flash状态标志
fmc_flag_clear(FMC_FLAG_BUSY | FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR | FMC_FLAG_END);
// 解锁Flash
fmc_unlock();
// 执行页面擦除
fmc_state = fmc_page_erase(page_address);
// 返回结果0=成功1=失败)
return (fmc_state == FMC_READY) ? 0 : 1;
}
/**
* @brief 写入数据到Flash适配同事的write_data函数
* @param flash_address Flash地址指针会被更新
* @param data 要写入的数据指针
* @param data_length 数据长度以32位字为单位
* @return 写入结果0=成功1=写入错误2=验证错误
*/
uint8_t flash_write_data(__IO uint32_t* flash_address, uint32_t* data, uint32_t data_length)
{
uint32_t i = 0;
// 清除Flash状态标志可选根据需要启用
// fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR | FMC_FLAG_END);
// 逐字写入数据
for (i = 0; (i < data_length) && (*flash_address <= (APP_FLASH_END_ADDRESS - 4)); i++) {
// 写入32位数据到Flash
if (fmc_word_program(*flash_address, *(uint32_t*)(data + i)) == FMC_READY) {
// 验证写入的数据
if (*(uint32_t*)*flash_address != *(uint32_t*)(data + i)) {
// Flash内容与写入数据不匹配
return 2;
}
// 增加Flash地址指针下一个32位字
*flash_address += 4;
} else {
// Flash写入过程中发生错误
return 1;
}
}
// 写入成功
return 0;
}
/**
* @brief Check flash flag and jump to application if valid
* @param buf Pointer to flash memory location to check
* @return uint8_t 1=stay in bootloader, 0=jumped to application (won't return)
*/
uint8_t check_flash_and_jump(uint8_t *buf)
{
uint32_t jump_address;
pFunction jump_to_application;
if (*buf == 0xFF) {
// Flash为空继续bootloader模式
return 1;
}
fmc_lock(); // 锁定FMC以防止意外修改
// 读取应用程序的栈指针和复位向量
jump_address = *(__IO uint32_t*)(APPLICATION_ADDRESS + 4);
// 验证栈指针是否有效应该在SRAM范围内
// if ((app_stack_pointer & 0xFFF00000) != 0x20000000) {
// // 栈指针无效继续bootloader模式
// return 1;
// }
// 验证跳转地址是否有效应该在Flash应用程序区域内且为奇数-Thumb模式
// if ((jump_address < APPLICATION_ADDRESS) ||
// (jump_address > 0x08010000) || // 假设Flash大小为64KB
// ((jump_address & 0x01) == 0)) { // Thumb模式地址应为奇数
// // 跳转地址无效继续bootloader模式
// return 1;
// }
/* Ensure flash operations are complete */
/* Get application reset vector */
jump_address = *(__IO uint32_t*)(APPLICATION_ADDRESS + 4);
/* Basic validity check - reset vector should be in flash and odd (Thumb mode) */
// if ((jump_address < APPLICATION_ADDRESS) || ((jump_address & 0x01) == 0)) {
// /* Invalid jump address, stay in bootloader */
// return 1;
// }
/* Create function pointer */
jump_to_application = (pFunction)jump_address;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*)APPLICATION_ADDRESS);
/* Disable interrupts for safe transition */
__disable_irq();
/* Jump to user application - this function will not return */
jump_to_application();
/* Should never reach here */
return 0; /* Should never reach here */
}
/**
* @brief Convert string to integer (supports hex, decimal, K, M suffixes)
* @param input_str Input string to convert
* @param int_num Pointer to store converted integer
* @return 1 if successful, 0 if failed
*/
uint32_t str_to_int(uint8_t *input_str, int32_t *int_num)
{
uint32_t i = 0, res = 0;
uint32_t val = 0;
if (input_str[0] == '0' && (input_str[1] == 'x' || input_str[1] == 'X')) {
// Hexadecimal input
if (input_str[2] == '\0') {
return 0;
}
for (i = 2; i < 11; i++) {
if (input_str[i] == '\0') {
*int_num = val;
res = 1;
break;
}
if (ISVALIDHEX(input_str[i])) {
val = (val << 4) + CONVERTHEX(input_str[i]);
} else {
res = 0;
break;
}
}
if (i >= 11) {
res = 0; // Over 8 digit hex - invalid
}
} else {
// Decimal input (max 10-digit)
for (i = 0; i < 11; i++) {
if (input_str[i] == '\0') {
*int_num = val;
res = 1;
break;
} else if ((input_str[i] == 'k' || input_str[i] == 'K') && (i > 0)) {
val = val << 10; // Multiply by 1024
*int_num = val;
res = 1;
break;
} else if ((input_str[i] == 'm' || input_str[i] == 'M') && (i > 0)) {
val = val << 20; // Multiply by 1024*1024
*int_num = val;
res = 1;
break;
} else if (ISVALIDDEC(input_str[i])) {
val = val * 10 + CONVERTDEC(input_str[i]);
} else {
res = 0;
break;
}
}
if (i >= 11) {
res = 0; // Over 10 digit decimal - invalid
}
}
return res;
}
/**
* @brief Update CRC16 value with a single byte
* @param crc_in Current CRC value
* @param byte Byte to process
* @return Updated CRC value
*/
uint16_t crc16_update(uint16_t crc_in, uint8_t byte)
{
uint32_t crc = crc_in;
uint32_t in = byte | 0x100;
do {
crc <<= 1;
in <<= 1;
if (in & 0x100) {
++crc;
}
if (crc & 0x10000) {
crc ^= 0x1021;
}
} while (!(in & 0x10000));
return crc & 0xFFFFU;
}
/**
* @brief Calculate CRC16 for data buffer
* @param data Pointer to data buffer
* @param size Size of data in bytes
* @return Calculated CRC16 value
*/
uint16_t crc16_calculate(const uint8_t* data, uint32_t size)
{
uint32_t crc = 0;
const uint8_t* data_end = data + size;
while (data < data_end) {
crc = crc16_update(crc, *data++);
}
crc = crc16_update(crc, 0);
crc = crc16_update(crc, 0);
return crc & 0xFFFFU;
}
/**
* @brief 接收Ymodem数据包数据
* 等待并读取完整的数据包到缓冲区中
* 该函数保持与原始实现相同的行为逻辑
*/
void ymodem_read_packet_data(void)
{
// 重置接收计数器
ymodem_rx_count = 0;
// 等待数据到达(阻塞等待)
while (uart_ring_buffer_available() <= 0) {
// 可选:发送确认字节(当前被禁用)
// ymodem_send_response(YMODEM_ACK);
delay_ms(1000); // 等待1秒后重新检查
}
// 等待数据传输完成,确保接收到完整数据包
delay_ms(200);
// 读取环形缓冲区中的所有可用数据
while (uart_ring_buffer_available() > 0) {
int received_byte = uart_ring_buffer_get();
if (received_byte >= 0) {
ymodem_rx_buffer[ymodem_rx_count++] = (uint8_t)received_byte;
}
}
}
/**
* @brief Ymodem接收函数直接移植同事的逻辑
* @param buf 未使用(保持接口兼容)
* @return 接收的文件大小,负数表示错误
*/
int32_t ymodem_receive(uint8_t *buf)
{
uint8_t file_size[FILE_SIZE_LENGTH], *file_ptr;
int32_t i, j = 0, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0, isize = 0, singledata = 0;
uint32_t flash_destination, ram_source;
uint8_t temp = 0, eot_flag = 0, crc_high = 0, crc_low = 0;
uint16_t crc_value = 0;
uint32_t erase_page = APPLICATION_ADDRESS; // 从应用程序地址开始擦除
uint8_t pack = 1;
// 解锁Flash并擦除应用程序区域
fmc_unlock();
flash_destination = APPLICATION_ADDRESS;
// 擦除应用程序区域从APPLICATION_ADDRESS到FLASH_END_ADDRESS
for (; erase_page < FLASH_END_ADDRESS; erase_page += 1024) {
flash_erase_page(erase_page);
}
temp = 0;
// 发送CRC16请求等待数据
while (uart_ring_buffer_available() <= 0) {
rs485_send_byte(CRC16);
delay_ms(1000);
}
delay_ms(200);
// 读取第一个数据包
ymodem_read_packet_data();
// 主循环
for (session_done = 0, errors = 0, session_begin = 0;;) {
for (packets_received = 0, file_done = 0;;) {
delay_ms(2000);
switch (temp) {
case 0: // 处理文件头数据包
if (ymodem_rx_buffer[0] == SOH) { // 128字节数据包
// 验证包序号
if (ymodem_rx_buffer[1] != ((ymodem_rx_buffer[2] ^ 0xFF) & 0xFF))
break;
if (ymodem_rx_buffer[3] != 0) { // 有文件信息
// 提取文件名
for (i = 0, file_ptr = ymodem_rx_buffer + PACKET_HEADER;
(*file_ptr != 0) && (i < FILE_NAME_LENGTH);) {
file_ptr++;
}
// 提取文件大小
for (i = 0, file_ptr++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);) {
file_size[i++] = *file_ptr++;
}
file_size[i++] = '\0';
// 转换文件大小
str_to_int(file_size, &size);
// 计算需要的1K数据包数量
isize = size / PACKET_1K_SIZE;
singledata = size - (isize * PACKET_1K_SIZE);
// 验证CRC
crc_value = crc16_calculate(&ymodem_rx_buffer[3], 128);
crc_low = crc_value & 0xFF;
crc_value >>= 8;
crc_high = crc_value & 0xFF;
if (crc_high != ymodem_rx_buffer[131] || crc_low != ymodem_rx_buffer[132]) {
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(NAK);
ymodem_read_packet_data();
break;
}
temp = 1;
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
rs485_send_byte(CRC16);
ymodem_read_packet_data();
}
} else if (ymodem_rx_buffer[0] == CA) { // 取消传输
if (ymodem_rx_buffer[1] == CA && ymodem_rx_buffer[2] == CA &&
ymodem_rx_buffer[3] == CA && ymodem_rx_buffer[4] == CA) {
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
temp = 0;
}
ymodem_rx_count = 0;
return -3;
}
break;
case 1: // 处理数据包
if (ymodem_rx_buffer[0] == STX) { // 1K字节数据包
// 验证包序号
if (ymodem_rx_buffer[1] != ((ymodem_rx_buffer[2] ^ 0xFF) & 0xFF) &&
ymodem_rx_buffer[1] == pack) {
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(NAK);
break;
}
// 验证CRC
crc_value = crc16_calculate(&ymodem_rx_buffer[3], PACKET_1K_SIZE);
crc_low = crc_value & 0xFF;
crc_value >>= 8;
crc_high = crc_value & 0xFF;
if (crc_high != ymodem_rx_buffer[PACKET_1K_SIZE + 3] ||
crc_low != ymodem_rx_buffer[PACKET_1K_SIZE + 4]) {
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(NAK);
break;
}
// 处理单独数据最后一包可能不满1K
if (singledata != 0) {
// 预留处理不完整数据包的逻辑
}
// 复制数据到临时缓冲区
memcpy(temp_buffer, ymodem_rx_buffer + PACKET_HEADER, PACKET_1K_SIZE);
ram_source = (uint32_t)temp_buffer;
fmc_unlock();
// 写入Flash
if (flash_write_data(&flash_destination, (uint32_t*)ram_source, PACKET_1K_SIZE) == 0) {
isize--;
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
pack++;
rs485_send_byte(ACK);
// 如果是最后一包,写入应用程序标志
if (isize == 1) {
fmc_unlock();
// flash_write_app_flag();
fmc_word_program(FLASH_FLAG_ADDRESS, 0xEEEE);
}
ymodem_read_packet_data();
} else {
rs485_send_byte(CA);
rs485_send_byte(CA);
temp = 0;
ymodem_rx_count = 0;
return -2;
}
} else if (ymodem_rx_buffer[0] == EOT) { // 传输结束
if (eot_flag == 1) {
eot_flag = 0;
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
rs485_send_byte(CRC16);
ymodem_read_packet_data();
temp = 3;
}
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
temp = 3;
} else if (ymodem_rx_buffer[0] == CA) { // 取消传输
if (ymodem_rx_buffer[1] == CA && ymodem_rx_buffer[2] == CA &&
ymodem_rx_buffer[3] == CA && ymodem_rx_buffer[4] == CA) {
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
temp = 0;
}
ymodem_rx_count = 0;
return -3;
}
ymodem_rx_count = 0;
break;
case 3: // 传输完成
temp = 0;
fmc_lock();
ymodem_rx_count = 0;
ymodem_rx_buffer[0] = 0;
rs485_send_byte(ACK);
ymodem_rx_count = 0;
return size;
}
}
}
}