feat: 完善Mesh继电器OTA升级闭环
This commit is contained in:
@@ -12,12 +12,14 @@ static uint16_t current_milliamperes;
|
||||
static uint8_t current_ready;
|
||||
/** 启动校准得到的 ADC 零点码值。 */
|
||||
static uint16_t zero_code;
|
||||
/** 启动校准期间用于累加 ADC 码值的 32 位累加器。 */
|
||||
static uint32_t zero_accumulator;
|
||||
/** 启动校准期间用于累加 ADC 码值的16位累加器。
|
||||
* 64个样本的最大和为64×1023=65472,不超过uint16_t范围。 */
|
||||
static uint16_t zero_accumulator;
|
||||
/** 已经完成的零点校准样本数。 */
|
||||
static uint8_t zero_count;
|
||||
/** 正常运行期间用于累加偏差样本的累加器。 */
|
||||
static uint32_t signal_accumulator;
|
||||
/** 正常运行期间用于累加偏差样本的16位累加器。
|
||||
* 16个样本的最大和为16×1023=16368,不超过uint16_t范围。 */
|
||||
static uint16_t signal_accumulator;
|
||||
/** 当前平均窗口已经积累的偏差样本数。 */
|
||||
static uint8_t signal_count;
|
||||
|
||||
@@ -57,9 +59,9 @@ void Current_Init(void)
|
||||
current_milliamperes = 0u;
|
||||
current_ready = 0u;
|
||||
zero_code = 512u;
|
||||
zero_accumulator = 0ul;
|
||||
zero_accumulator = 0u;
|
||||
zero_count = 0u;
|
||||
signal_accumulator = 0ul;
|
||||
signal_accumulator = 0u;
|
||||
signal_count = 0u;
|
||||
|
||||
/* ADC1 单次转换,右对齐,选择 PC4 对应的 ADC 通道由后续封装核对。 */
|
||||
@@ -92,7 +94,7 @@ void Current_Task(void)
|
||||
++zero_count;
|
||||
if (zero_count == 64u)
|
||||
{
|
||||
zero_code = (uint16_t)(zero_accumulator / 64ul);
|
||||
zero_code = (uint16_t)(zero_accumulator / 64u);
|
||||
current_ready = 1u;
|
||||
}
|
||||
return;
|
||||
@@ -104,11 +106,11 @@ void Current_Task(void)
|
||||
++signal_count;
|
||||
if (signal_count >= 16u)
|
||||
{
|
||||
difference = (uint16_t)(signal_accumulator / 16ul);
|
||||
difference = (uint16_t)(signal_accumulator / 16u);
|
||||
milliamperes = ((uint32_t)difference * 977ul + 5ul) / 10ul;
|
||||
current_milliamperes = (milliamperes > 65535ul) ? 65535u :
|
||||
(uint16_t)milliamperes;
|
||||
signal_accumulator = 0ul;
|
||||
signal_accumulator = 0u;
|
||||
signal_count = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "system_tick.h"
|
||||
#include "stm8s003_registers.h"
|
||||
|
||||
/** TIM4 中断递增的全局毫秒计数,溢出后按无符号差值继续工作。 */
|
||||
/** TIM4 中断递增的32位毫秒计数,溢出后按无符号差值继续工作。 */
|
||||
static volatile uint32_t system_tick_ms;
|
||||
|
||||
/**
|
||||
|
||||
+50
-23
@@ -16,7 +16,24 @@ static volatile uint8_t rx_write_index;
|
||||
/** 环形缓存读取位置,由上层协议任务推进。 */
|
||||
static volatile uint8_t rx_read_index;
|
||||
|
||||
/** 初始化 UART1;后续接入 JDY-28M 的 9600 baud 配置。 */
|
||||
/**
|
||||
* 将一个字节写入接收环形缓冲区。
|
||||
*
|
||||
* 该函数只由 UART1 接收中断调用。缓冲区满时丢弃新字节,绝不覆盖尚未
|
||||
* 被主循环读取的数据,避免破坏正在解析的 Mesh 帧。
|
||||
*/
|
||||
static void Uart1_RxPush(uint8_t value)
|
||||
{
|
||||
uint8_t next_index = (uint8_t)((rx_write_index + 1u) &
|
||||
(UART1_RX_BUFFER_SIZE - 1u));
|
||||
if (next_index != rx_read_index)
|
||||
{
|
||||
rx_buffer[rx_write_index] = value;
|
||||
rx_write_index = next_index;
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 UART1,并开启 UART1 接收寄存器非空中断。 */
|
||||
void Uart1_Init(void)
|
||||
{
|
||||
/* 先关闭 UART,再配置 9600 baud@16 MHz:BRR=0x0683。 */
|
||||
@@ -25,36 +42,21 @@ void Uart1_Init(void)
|
||||
REG8(UART1_BRR1_ADDR) = 0x68u;
|
||||
REG8(UART1_CR1_ADDR) = 0x00u;
|
||||
REG8(UART1_CR3_ADDR) = 0x00u;
|
||||
/* RE=1、TE=1、接收中断暂不打开,环形缓冲区接入后再开启。 */
|
||||
REG8(UART1_CR2_ADDR) = 0x0Cu;
|
||||
rx_write_index = 0u;
|
||||
rx_read_index = 0u;
|
||||
/* RE=1、TE=1、RIEN=1:接收数据由UART1中断保存到环形缓冲区。 */
|
||||
REG8(UART1_CR2_ADDR) = 0x2Cu;
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮询 UART1 接收状态并保存字节。
|
||||
* UART1接收任务入口。
|
||||
*
|
||||
* 本阶段先采用轮询方式,避免在尚未建立中断向量表前引入中断链接问题。
|
||||
* 后续如果业务帧速率提高,可将同一环形缓冲区写入逻辑迁移到 UART RX 中断。
|
||||
* 接收字节已经由 UART1 接收中断写入环形缓冲区,因此主循环不再轮询UART
|
||||
* 硬件寄存器。保留该接口是为了维持主循环结构和后续扩展接口兼容性。
|
||||
*/
|
||||
void Uart1_Task(void)
|
||||
{
|
||||
uint8_t next_index;
|
||||
|
||||
while ((REG8(UART1_SR_ADDR) & 0x20u) != 0u)
|
||||
{
|
||||
next_index = (uint8_t)((rx_write_index + 1u) & (UART1_RX_BUFFER_SIZE - 1u));
|
||||
|
||||
/* 缓冲区满时丢弃当前字节,避免覆盖尚未处理的完整帧。 */
|
||||
if (next_index == rx_read_index)
|
||||
{
|
||||
(void)REG8(UART1_DR_ADDR);
|
||||
continue;
|
||||
}
|
||||
|
||||
rx_buffer[rx_write_index] = REG8(UART1_DR_ADDR);
|
||||
rx_write_index = next_index;
|
||||
}
|
||||
/* UART硬件接收由Uart1_InterruptHandler()完成,此处无需执行任何操作。 */
|
||||
}
|
||||
|
||||
/** 发送一个字节;当前阶段不连接真实 UART 寄存器。 */
|
||||
@@ -85,7 +87,32 @@ uint8_t Uart1_Available(void)
|
||||
return (uint8_t)((rx_write_index - rx_read_index) & (UART1_RX_BUFFER_SIZE - 1u));
|
||||
}
|
||||
|
||||
/** UART1 接收中断入口占位。 */
|
||||
/**
|
||||
* UART1接收中断处理函数。
|
||||
*
|
||||
* STM8S003F3 UART1接收中断向量为19。中断中只读取状态和数据寄存器,
|
||||
* 将无错误字节快速放入环形缓冲区;协议解析、CRC和业务控制全部放在主循环。
|
||||
*/
|
||||
void Uart1_InterruptHandler(void)
|
||||
{
|
||||
uint8_t status = REG8(UART1_SR_ADDR);
|
||||
uint8_t value;
|
||||
|
||||
if ((status & 0x0Fu) != 0u)
|
||||
{
|
||||
/* STM8 UART错误标志需要先读SR再读DR清除;错误字节不送入协议层。 */
|
||||
value = REG8(UART1_DR_ADDR);
|
||||
(void)value;
|
||||
}
|
||||
else if ((status & 0x20u) != 0u)
|
||||
{
|
||||
value = REG8(UART1_DR_ADDR);
|
||||
Uart1_RxPush(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** UART1接收寄存器非空中断向量,IRQ号19。 */
|
||||
void Uart1_RX_IRQHandler(void) __interrupt(19)
|
||||
{
|
||||
Uart1_InterruptHandler();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** @file w25q64_app.c @brief 主程序侧W25Q64只读结果访问驱动。 */
|
||||
/** @file w25q64_app.c @brief 主程序侧W25Q80BV访问驱动。 */
|
||||
#include "w25q64_app.h"
|
||||
#include "stm8s003_registers.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define W25_CMD_RDSR 0x05u
|
||||
#define W25_CMD_ERASE_4K 0x20u
|
||||
#define W25_BUSY 0x01u
|
||||
#define W25_RESULT_ADDR 0x030010ul
|
||||
#define W25_RESULT_ADDR 0x005010ul
|
||||
|
||||
static uint8_t Xfer(uint8_t value)
|
||||
{
|
||||
@@ -82,6 +82,10 @@ uint8_t W25Q64App_PageProgram(uint32_t address,const uint8_t *data,
|
||||
uint8_t W25Q64App_ClearUpgradeResult(void)
|
||||
{
|
||||
uint8_t zero=0u;
|
||||
WriteEnable(); Select(); Xfer(W25_CMD_PROGRAM); Xfer(0x03u); Xfer(0x00u); Xfer(0x10u); Xfer(zero); Deselect();
|
||||
WriteEnable(); Select(); Xfer(W25_CMD_PROGRAM);
|
||||
Xfer((uint8_t)(W25_RESULT_ADDR >> 16));
|
||||
Xfer((uint8_t)(W25_RESULT_ADDR >> 8));
|
||||
Xfer((uint8_t)W25_RESULT_ADDR);
|
||||
Xfer(zero); Deselect();
|
||||
return Ready();
|
||||
}
|
||||
|
||||
@@ -22,3 +22,21 @@ void Watchdog_Refresh(void)
|
||||
{
|
||||
REG8(IWDG_KR_ADDR) = 0xAAu;
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即触发看门狗复位。
|
||||
*
|
||||
* UART发送函数在返回前会等待最后一个字节写入发送寄存器,因此OTA校验
|
||||
* 成功分支可以先发送0x8B,再调用本函数。这里把看门狗重装值改为最小值,
|
||||
* 随后不再刷新计数器,避免等待原先约5秒的完整超时时间。
|
||||
*/
|
||||
void Watchdog_ResetNow(void)
|
||||
{
|
||||
REG8(IWDG_KR_ADDR) = 0x55u;
|
||||
REG8(IWDG_RLR_ADDR) = 0x01u;
|
||||
REG8(IWDG_KR_ADDR) = 0xAAu;
|
||||
while (1)
|
||||
{
|
||||
/* 等待硬件看门狗复位;故意不刷新计数器。 */
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -21,6 +21,9 @@
|
||||
#include "interrupt_control.h"
|
||||
#include "ota_manager.h"
|
||||
|
||||
/** 标记本次上电是否已经完成设备上线广播,避免主循环重复发送。 */
|
||||
static uint8_t startup_broadcast_sent;
|
||||
|
||||
/**
|
||||
* @brief 固件主函数。
|
||||
*
|
||||
@@ -43,6 +46,7 @@ int main(void)
|
||||
BluetoothManager_Init();
|
||||
OtaManager_Init();
|
||||
Watchdog_Init();
|
||||
startup_broadcast_sent = 0u;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -56,8 +60,23 @@ int main(void)
|
||||
{
|
||||
MeshFrame_Task();
|
||||
BluetoothManager_Task();
|
||||
/* 所有基础模块已完成初始化且蓝牙进入可通信状态后,向Mesh
|
||||
* 广播一次上线通知。业务帧SRC字段会自动携带本机短地址,
|
||||
* 其他设备无需回复,避免广播上线时形成应答风暴。 */
|
||||
if ((startup_broadcast_sent == 0u) &&
|
||||
(BluetoothManager_IsReady() != 0u))
|
||||
{
|
||||
if (MeshFrame_SendBusiness(0xFFFFu,
|
||||
CMD_DEVICE_ONLINE,
|
||||
(const uint8_t *)0,
|
||||
0u) != 0u)
|
||||
{
|
||||
startup_broadcast_sent = 1u;
|
||||
}
|
||||
}
|
||||
}
|
||||
FaultManager_Task();
|
||||
BusinessProtocol_Task();
|
||||
/* 蓝牙完成初始化后再上报Bootloader升级结果,避免结果帧丢在AT阶段。 */
|
||||
if (BluetoothManager_IsReady() != 0u)
|
||||
{
|
||||
|
||||
@@ -286,8 +286,5 @@ void BluetoothManager_Task(void)
|
||||
/** 返回蓝牙初始化完成状态。 */
|
||||
uint8_t BluetoothManager_IsReady(void) { return (bluetooth_state == BT_READY) ? 1u : 0u; }
|
||||
|
||||
/** 返回蓝牙初始化故障状态。 */
|
||||
uint8_t BluetoothManager_IsFault(void) { return (bluetooth_state == BT_FAULT) ? 1u : 0u; }
|
||||
|
||||
/** 返回本次上电从模块查询到的短地址。 */
|
||||
uint16_t BluetoothManager_GetShortAddress(void) { return short_address; }
|
||||
|
||||
@@ -12,6 +12,59 @@
|
||||
#include "fault_manager.h"
|
||||
#include "bluetooth_manager.h"
|
||||
#include "ota_manager.h"
|
||||
#include "system_tick.h"
|
||||
|
||||
/** 广播应答的最小随机延时,避免多个设备同时发送。 */
|
||||
#define BROADCAST_RESPONSE_DELAY_MIN_MS 20u
|
||||
/** 广播应答随机延时的时间片,采用10ms量化以减少计算开销。 */
|
||||
#define BROADCAST_RESPONSE_DELAY_STEP_MS 10u
|
||||
/** 广播应答随机延时的时间片数量,实际范围为20ms至170ms。 */
|
||||
#define BROADCAST_RESPONSE_DELAY_SLOTS 16u
|
||||
|
||||
/** 待延迟发送的广播应答。当前设备一次只处理一条业务请求,因此单条队列足够。 */
|
||||
static uint8_t delayed_response_pending;
|
||||
static uint16_t delayed_response_target;
|
||||
static uint8_t delayed_response_command;
|
||||
static uint8_t delayed_response_length;
|
||||
static uint8_t delayed_response_data[BUSINESS_MAX_DATA_LENGTH];
|
||||
static uint32_t delayed_response_due_ms;
|
||||
static uint8_t response_random_state;
|
||||
|
||||
/** 生成一个轻量伪随机数,用于把广播应答分散到不同时间片。 */
|
||||
static uint8_t BusinessProtocol_NextRandom(void);
|
||||
|
||||
/** 发送或排队发送业务应答;只有广播请求才进行随机延时。 */
|
||||
static void BusinessProtocol_SendResponse(uint16_t address,
|
||||
uint8_t command,
|
||||
const uint8_t *data,
|
||||
uint8_t length);
|
||||
|
||||
/** 将异步应答写入随机延迟队列,不立即发送。 */
|
||||
void BusinessProtocol_QueueDelayedResponse(uint16_t address,
|
||||
uint8_t command,
|
||||
const uint8_t *data,
|
||||
uint8_t length)
|
||||
{
|
||||
uint8_t index;
|
||||
if ((data == (const uint8_t *)0 && length != 0u) ||
|
||||
(length > BUSINESS_MAX_DATA_LENGTH))
|
||||
{
|
||||
return;
|
||||
}
|
||||
delayed_response_target = address;
|
||||
delayed_response_command = command;
|
||||
delayed_response_length = length;
|
||||
for (index = 0u; index < length; ++index)
|
||||
{
|
||||
delayed_response_data[index] = data[index];
|
||||
}
|
||||
delayed_response_due_ms = SystemTick_NowMs() +
|
||||
BROADCAST_RESPONSE_DELAY_MIN_MS +
|
||||
(uint32_t)((BusinessProtocol_NextRandom() &
|
||||
(BROADCAST_RESPONSE_DELAY_SLOTS - 1u)) *
|
||||
BROADCAST_RESPONSE_DELAY_STEP_MS);
|
||||
delayed_response_pending = 1u;
|
||||
}
|
||||
|
||||
/** 业务帧解析状态。 */
|
||||
typedef enum
|
||||
@@ -26,10 +79,10 @@ typedef enum
|
||||
PARSER_WAIT_LENGTH,
|
||||
/** 按 LEN 接收 DATA 区。 */
|
||||
PARSER_WAIT_DATA,
|
||||
/** 等待 CRC 低字节。 */
|
||||
PARSER_WAIT_CRC_LOW,
|
||||
/** 等待 CRC 高字节并完成校验。 */
|
||||
PARSER_WAIT_CRC_HIGH
|
||||
/** 等待 CRC 高字节。 */
|
||||
PARSER_WAIT_CRC_HIGH,
|
||||
/** 等待 CRC 低字节并完成校验。 */
|
||||
PARSER_WAIT_CRC_LOW
|
||||
} BusinessParserState;
|
||||
|
||||
/** 解析器当前状态。 */
|
||||
@@ -62,7 +115,45 @@ static void BusinessProtocol_SendByteResponse(uint16_t address,
|
||||
uint8_t command,
|
||||
uint8_t value)
|
||||
{
|
||||
(void)MeshFrame_SendBusiness(address, command, &value, 1u);
|
||||
BusinessProtocol_SendResponse(address, command, &value, 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一个8位线性反馈移位寄存器伪随机数。
|
||||
*
|
||||
* 这里只需要把多个设备的广播应答时间打散,不需要密码学随机性。
|
||||
* 使用8位状态和按位与取时间片,避免16位除法和取模代码占用Flash。
|
||||
*/
|
||||
static uint8_t BusinessProtocol_NextRandom(void)
|
||||
{
|
||||
uint8_t feedback = (uint8_t)(((response_random_state >> 7u) ^
|
||||
(response_random_state >> 5u) ^
|
||||
(response_random_state >> 4u) ^
|
||||
(response_random_state >> 3u)) & 1u);
|
||||
response_random_state = (uint8_t)((response_random_state << 1u) | feedback);
|
||||
if (response_random_state == 0u)
|
||||
{
|
||||
response_random_state = 0xA5u;
|
||||
}
|
||||
return response_random_state;
|
||||
}
|
||||
|
||||
/** 发送或排队发送业务应答;只有广播请求才进行随机延时。 */
|
||||
static void BusinessProtocol_SendResponse(uint16_t address,
|
||||
uint8_t command,
|
||||
const uint8_t *data,
|
||||
uint8_t length)
|
||||
{
|
||||
if (MeshFrame_GetLastTargetAddress() != 0xFFFFu)
|
||||
{
|
||||
(void)MeshFrame_SendBusiness(address, command, data, length);
|
||||
return;
|
||||
}
|
||||
if (length > BUSINESS_MAX_DATA_LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BusinessProtocol_QueueDelayedResponse(address, command, data, length);
|
||||
}
|
||||
|
||||
/** 初始化业务协议状态机;完整解析器在第二阶段实现。 */
|
||||
@@ -75,18 +166,21 @@ void BusinessProtocol_Init(void)
|
||||
parser_received_crc = 0u;
|
||||
last_command = 0u;
|
||||
last_length = 0u;
|
||||
delayed_response_pending = 0u;
|
||||
response_random_state = 0xA5u;
|
||||
}
|
||||
|
||||
/** 处理 UART 数据和待发送帧;当前阶段仅保留任务入口。 */
|
||||
void BusinessProtocol_Task(void)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
while (Uart1_ReadByte(&value) != 0u)
|
||||
if ((delayed_response_pending != 0u) &&
|
||||
((uint32_t)(SystemTick_NowMs() - delayed_response_due_ms) < 0x80000000ul))
|
||||
{
|
||||
/* 当前阶段仅消费 UART 字节,正式接入时由 Mesh 外层解析器调用
|
||||
* BusinessProtocol_InputByte(),避免把外层地址和帧尾误当业务数据。 */
|
||||
(void)BusinessProtocol_InputByte(value);
|
||||
(void)MeshFrame_SendBusiness(delayed_response_target,
|
||||
delayed_response_command,
|
||||
delayed_response_data,
|
||||
delayed_response_length);
|
||||
delayed_response_pending = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +188,7 @@ void BusinessProtocol_Task(void)
|
||||
* 向业务帧状态机输入一个字节。
|
||||
*
|
||||
* 帧格式为 `SRC_H SRC_L CMD LEN DATA CRC16`。CRC 计算范围为 SRC、CMD、
|
||||
* LEN 和 DATA;线上 CRC 低字节在前。CRC 错误会恢复到等待地址状态,
|
||||
* LEN 和 DATA;线上 CRC 高字节在前。CRC 错误会恢复到等待地址状态,
|
||||
* 不执行任何控制动作。
|
||||
*/
|
||||
uint8_t BusinessProtocol_InputByte(uint8_t value)
|
||||
@@ -128,7 +222,7 @@ uint8_t BusinessProtocol_InputByte(uint8_t value)
|
||||
}
|
||||
else if (parser_length == 0u)
|
||||
{
|
||||
parser_state = PARSER_WAIT_CRC_LOW;
|
||||
parser_state = PARSER_WAIT_CRC_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -144,13 +238,13 @@ uint8_t BusinessProtocol_InputByte(uint8_t value)
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSER_WAIT_CRC_LOW:
|
||||
parser_received_crc = value;
|
||||
parser_state = PARSER_WAIT_CRC_HIGH;
|
||||
case PARSER_WAIT_CRC_HIGH:
|
||||
parser_received_crc = (uint16_t)value << 8u;
|
||||
parser_state = PARSER_WAIT_CRC_LOW;
|
||||
break;
|
||||
|
||||
case PARSER_WAIT_CRC_HIGH:
|
||||
parser_received_crc |= (uint16_t)value << 8u;
|
||||
case PARSER_WAIT_CRC_LOW:
|
||||
parser_received_crc |= value;
|
||||
parser_crc_input[0] = (uint8_t)(parser_source_address >> 8u);
|
||||
parser_crc_input[1] = (uint8_t)parser_source_address;
|
||||
parser_crc_input[2] = parser_command;
|
||||
@@ -196,17 +290,6 @@ uint8_t BusinessProtocol_GetDataLength(void)
|
||||
return last_length;
|
||||
}
|
||||
|
||||
/** 读取最近一帧合法业务帧的数据区字节。 */
|
||||
uint8_t BusinessProtocol_GetDataByte(uint8_t index, uint8_t *value)
|
||||
{
|
||||
if ((value == (uint8_t *)0) || (index >= last_length))
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
*value = last_data[index];
|
||||
return 1u;
|
||||
}
|
||||
|
||||
/** 读取最近一帧合法业务帧携带的发送方 Mesh 短地址。 */
|
||||
uint16_t BusinessProtocol_GetSourceAddress(void)
|
||||
{
|
||||
@@ -264,9 +347,9 @@ void BusinessProtocol_HandleFrame(void)
|
||||
break;
|
||||
}
|
||||
current = Current_GetMilliAmpere();
|
||||
current_data[0] = (uint8_t)current;
|
||||
current_data[1] = (uint8_t)(current >> 8u);
|
||||
(void)MeshFrame_SendBusiness(source_address,
|
||||
current_data[0] = (uint8_t)(current >> 8u);
|
||||
current_data[1] = (uint8_t)current;
|
||||
BusinessProtocol_SendResponse(source_address,
|
||||
CMD_CURRENT_QUERY | CMD_RESPONSE_FLAG,
|
||||
current_data, 2u);
|
||||
break;
|
||||
@@ -279,9 +362,9 @@ void BusinessProtocol_HandleFrame(void)
|
||||
CMD_ERROR_RESPONSE, value);
|
||||
break;
|
||||
}
|
||||
current_data[0] = (uint8_t)FIRMWARE_VERSION;
|
||||
current_data[1] = (uint8_t)(FIRMWARE_VERSION >> 8u);
|
||||
(void)MeshFrame_SendBusiness(source_address,
|
||||
current_data[0] = (uint8_t)(FIRMWARE_VERSION >> 8u);
|
||||
current_data[1] = (uint8_t)FIRMWARE_VERSION;
|
||||
BusinessProtocol_SendResponse(source_address,
|
||||
CMD_FIRMWARE_VERSION_RESPONSE,
|
||||
current_data, 2u);
|
||||
break;
|
||||
@@ -308,7 +391,8 @@ void BusinessProtocol_HandleFrame(void)
|
||||
{
|
||||
uint8_t ota_status = OtaManager_HandleCommand(last_command,
|
||||
last_data,
|
||||
last_length) ? 0x00u : 0x01u;
|
||||
last_length,
|
||||
source_address) ? 0x00u : 0x01u;
|
||||
uint8_t ota_response[3u];
|
||||
uint16_t next_offset = 0u;
|
||||
uint8_t response_command = (uint8_t)(last_command | CMD_RESPONSE_FLAG);
|
||||
@@ -318,14 +402,17 @@ void BusinessProtocol_HandleFrame(void)
|
||||
ota_response[0] = ota_status;
|
||||
ota_response[1] = (uint8_t)(next_offset >> 8u);
|
||||
ota_response[2] = (uint8_t)next_offset;
|
||||
(void)MeshFrame_SendBusiness(source_address, response_command,
|
||||
BusinessProtocol_SendResponse(source_address, response_command,
|
||||
ota_response, 3u);
|
||||
}
|
||||
else
|
||||
else if (last_command != 0x0Bu)
|
||||
{
|
||||
BusinessProtocol_SendByteResponse(source_address,
|
||||
response_command, ota_status);
|
||||
}
|
||||
/* 0x0B 的完整固件校验已经改为后台分片执行,最终的 0x8B
|
||||
* 应答由 OtaManager_Task() 在校验完成后发送,避免这里提前
|
||||
* 返回“成功”而实际校验尚未完成。 */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -336,7 +423,7 @@ void BusinessProtocol_HandleFrame(void)
|
||||
BusinessProtocol_SendByteResponse(source_address, CMD_ERROR_RESPONSE, value);
|
||||
break;
|
||||
}
|
||||
threshold = (uint16_t)last_data[0] | ((uint16_t)last_data[1] << 8u);
|
||||
threshold = ((uint16_t)last_data[0] << 8u) | last_data[1];
|
||||
if ((threshold == 0u) || (threshold > 30000u))
|
||||
{
|
||||
value = 0x03u;
|
||||
@@ -349,11 +436,51 @@ void BusinessProtocol_HandleFrame(void)
|
||||
BusinessProtocol_SendByteResponse(source_address, CMD_ERROR_RESPONSE, value);
|
||||
break;
|
||||
}
|
||||
(void)MeshFrame_SendBusiness(source_address,
|
||||
BusinessProtocol_SendResponse(source_address,
|
||||
CMD_THRESHOLD_CONFIG | CMD_RESPONSE_FLAG,
|
||||
last_data, 2u);
|
||||
break;
|
||||
|
||||
case CMD_DEVICE_ONLINE:
|
||||
/* 上线通知是设备间广播事件。发送方短地址已经位于业务帧SRC
|
||||
* 字段中,因此不需要DATA,也不返回应答,避免多个设备同时
|
||||
* 上线时产生广播应答风暴。 */
|
||||
if (last_length != 0u)
|
||||
{
|
||||
value = 0x02u;
|
||||
BusinessProtocol_SendByteResponse(source_address,
|
||||
CMD_ERROR_RESPONSE, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_FIRMWARE_ANNOUNCE:
|
||||
/* DATA依次为新固件版本和固件长度,均为高字节在前。设备只
|
||||
* 在新版本高于当前版本时回复,避免全网无意义应答。 */
|
||||
if (last_length != 4u)
|
||||
{
|
||||
value = 0x02u;
|
||||
BusinessProtocol_SendByteResponse(source_address,
|
||||
CMD_ERROR_RESPONSE, value);
|
||||
break;
|
||||
}
|
||||
/* 这里直接复用最近一帧的DATA缓冲区生成应答,避免额外申请
|
||||
* 4字节栈空间。先保存主机宣布的目标版本,再覆盖为当前版本。 */
|
||||
if ((last_data[0] > (uint8_t)(FIRMWARE_VERSION >> 8u)) ||
|
||||
((last_data[0] == (uint8_t)(FIRMWARE_VERSION >> 8u)) &&
|
||||
(last_data[1] > (uint8_t)FIRMWARE_VERSION)))
|
||||
{
|
||||
last_data[2] = last_data[0];
|
||||
last_data[3] = last_data[1];
|
||||
last_data[0] = (uint8_t)(FIRMWARE_VERSION >> 8u);
|
||||
last_data[1] = (uint8_t)FIRMWARE_VERSION;
|
||||
/* 当前请求来自广播时,统一通过应答延时队列发送,
|
||||
* 防止多个设备同时回复造成Mesh拥塞。 */
|
||||
BusinessProtocol_SendResponse(source_address,
|
||||
CMD_FIRMWARE_ANNOUNCE_RESPONSE,
|
||||
last_data, 4u);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_ADDRESS_QUERY:
|
||||
if (last_length != 0u)
|
||||
{
|
||||
@@ -363,7 +490,7 @@ void BusinessProtocol_HandleFrame(void)
|
||||
}
|
||||
current_data[0] = (uint8_t)(BluetoothManager_GetShortAddress() >> 8u);
|
||||
current_data[1] = (uint8_t)BluetoothManager_GetShortAddress();
|
||||
(void)MeshFrame_SendBusiness(source_address,
|
||||
BusinessProtocol_SendResponse(source_address,
|
||||
CMD_ADDRESS_QUERY | CMD_RESPONSE_FLAG,
|
||||
current_data, 2u);
|
||||
break;
|
||||
@@ -380,7 +507,7 @@ void BusinessProtocol_HandleFrame(void)
|
||||
*
|
||||
* @param data 待计算数据指针,不能为 NULL。
|
||||
* @param length 数据长度。
|
||||
* @return CRC 结果;发送时低字节在前。
|
||||
* @return CRC 结果;发送时高字节在前。
|
||||
*/
|
||||
uint16_t BusinessProtocol_Crc16Modbus(const uint8_t *data, uint16_t length)
|
||||
{
|
||||
|
||||
@@ -175,7 +175,7 @@ void MeshFrame_Task(void)
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回最近一帧合法外层数据的源地址。 */
|
||||
/** 返回最近一帧合法外层数据携带的目标短地址。 */
|
||||
uint16_t MeshFrame_GetLastTargetAddress(void)
|
||||
{
|
||||
return last_target_address;
|
||||
@@ -215,7 +215,7 @@ uint8_t MeshFrame_SendBusiness(uint16_t target_address,
|
||||
Uart1_WriteByte((uint8_t)source_address);
|
||||
Uart1_WriteByte(command); Uart1_WriteByte(length);
|
||||
for (index = 0u; index < length; ++index) Uart1_WriteByte(data[index]);
|
||||
Uart1_WriteByte((uint8_t)crc); Uart1_WriteByte((uint8_t)(crc >> 8u));
|
||||
Uart1_WriteByte((uint8_t)(crc >> 8u)); Uart1_WriteByte((uint8_t)crc);
|
||||
Uart1_WriteByte(MESH_TAIL_0); Uart1_WriteByte(MESH_TAIL_1);
|
||||
return 1u;
|
||||
}
|
||||
|
||||
+155
-53
@@ -4,21 +4,24 @@
|
||||
*
|
||||
* 重要职责边界:
|
||||
* - 本模块属于 Application,不属于 Bootloader;
|
||||
* - 本模块接收 Mesh OTA 数据并写入外部 W25Q64;
|
||||
* - 本模块接收 Mesh OTA 数据并写入外部 W25Q80BV;
|
||||
* - 本模块不擦写 STM8 内部程序 Flash;
|
||||
* - 下载完成并完成整包 CRC16/MODBUS 校验后,才设置升级请求;
|
||||
* - 复位后由 Bootloader 读取升级请求并执行最终搬运。
|
||||
*
|
||||
* 当前代码先建立稳定的状态机和接口边界。W25Q64 的 SPI 底层驱动需要
|
||||
* 当前代码先建立稳定的状态机和接口边界。W25Q80BV 的 SPI 底层驱动需要
|
||||
* 在实际硬件确认片选、SPI模式、时钟和读写时序后接入。
|
||||
*/
|
||||
#include "ota_manager.h"
|
||||
#include "w25q64_app.h"
|
||||
#include "mesh_frame.h"
|
||||
#include "business_protocol.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
#define OTA_IMAGE_ADDRESS 0x020000ul
|
||||
#define OTA_METADATA_ADDRESS 0x030000ul
|
||||
#define OTA_IMAGE_ADDRESS 0x003000ul
|
||||
#define OTA_METADATA_ADDRESS 0x005000ul
|
||||
#define OTA_IMAGE_SECTOR_COUNT 2u
|
||||
#define OTA_IMAGE_MAX_SIZE 0x2000u
|
||||
|
||||
#define OTA_COMMAND_START 0x08u
|
||||
#define OTA_COMMAND_DATA 0x09u
|
||||
@@ -28,25 +31,32 @@
|
||||
#define OTA_STATE_IDLE 0u
|
||||
#define OTA_STATE_RECEIVING 1u
|
||||
#define OTA_STATE_READY 2u
|
||||
#define OTA_STATE_VERIFYING 3u
|
||||
|
||||
/** OTA 状态机当前状态。 */
|
||||
static uint8_t ota_state;
|
||||
/** 已经写入外部 Flash 的固件字节数。 */
|
||||
static uint16_t ota_received_size;
|
||||
/** 主机声明的固件总长度。 */
|
||||
static uint16_t ota_expected_size;
|
||||
/** 主机声明的完整固件 CRC16/MODBUS。 */
|
||||
static uint16_t ota_expected_crc16;
|
||||
/** Bootloader升级结果缓存;实际值由W25Q64驱动读取后填充。 */
|
||||
/** Bootloader升级结果缓存;实际值由W25Q80BV驱动读取后填充。 */
|
||||
static uint8_t ota_bootloader_result;
|
||||
/** 升级结果是否已经等待主程序上报。 */
|
||||
static uint8_t ota_bootloader_result_pending;
|
||||
/** 防止主循环每次重复发送同一条启动结果。 */
|
||||
static uint8_t ota_bootloader_result_reported;
|
||||
static uint16_t ota_expected_offset;
|
||||
static uint16_t ota_image_size;
|
||||
static uint16_t ota_image_version;
|
||||
static uint16_t ota_expected_crc16;
|
||||
/** 当前整包校验已经读取到的外部Flash偏移。 */
|
||||
static uint16_t ota_verify_offset;
|
||||
/** 当前整包校验过程中的连续CRC值。 */
|
||||
static uint16_t ota_verify_crc;
|
||||
/** 整包校验完成后需要回复的主机短地址。 */
|
||||
static uint16_t ota_verify_response_target;
|
||||
/** 标记校验完成后是否需要发送0x8B应答。 */
|
||||
static uint8_t ota_verify_response_pending;
|
||||
/** CMD=0x0B请求是否来自广播,用于决定最终0x8B是否随机延迟。 */
|
||||
static uint8_t ota_verify_broadcast_request;
|
||||
|
||||
/**
|
||||
* @brief 初始化 OTA 状态机。
|
||||
@@ -54,16 +64,20 @@ static uint16_t ota_expected_crc16;
|
||||
void OtaManager_Init(void)
|
||||
{
|
||||
ota_state = OTA_STATE_IDLE;
|
||||
ota_received_size = 0u;
|
||||
ota_expected_size = 0u;
|
||||
ota_bootloader_result = 0u;
|
||||
ota_bootloader_result_pending = 0u;
|
||||
ota_bootloader_result_reported = 0u;
|
||||
ota_expected_offset = 0u;
|
||||
ota_image_size = 0u;
|
||||
ota_image_version = 0u;
|
||||
ota_verify_offset = 0u;
|
||||
ota_verify_crc = 0xFFFFu;
|
||||
ota_verify_response_target = 0u;
|
||||
ota_verify_response_pending = 0u;
|
||||
ota_verify_broadcast_request = 0u;
|
||||
W25Q64App_Init();
|
||||
if (W25Q64App_ReadByte(0x030010ul, &ota_bootloader_result) != 0u &&
|
||||
if (W25Q64App_ReadByte(OTA_METADATA_ADDRESS + 0x10ul,
|
||||
&ota_bootloader_result) != 0u &&
|
||||
ota_bootloader_result != 0u)
|
||||
{
|
||||
ota_bootloader_result_pending = 1u;
|
||||
@@ -78,6 +92,116 @@ void OtaManager_Init(void)
|
||||
void OtaManager_Task(void)
|
||||
{
|
||||
uint8_t result;
|
||||
uint8_t buffer[16];
|
||||
uint16_t chunk;
|
||||
uint16_t index;
|
||||
uint8_t bit;
|
||||
uint8_t metadata[18];
|
||||
|
||||
/* 每次任务只读取并计算最多16字节,计算完成后立即返回主循环。
|
||||
* 这样主循环可以继续刷新看门狗,不会因为大固件整包校验阻塞。 */
|
||||
if (ota_state == OTA_STATE_VERIFYING)
|
||||
{
|
||||
chunk = (uint16_t)(ota_expected_size - ota_verify_offset);
|
||||
if (chunk > 16u)
|
||||
{
|
||||
chunk = 16u;
|
||||
}
|
||||
|
||||
if (W25Q64App_Read(OTA_IMAGE_ADDRESS + ota_verify_offset,
|
||||
buffer, chunk) == 0u)
|
||||
{
|
||||
/* 外部 Flash 读取失败时,必须向发起校验的主机返回失败,
|
||||
* 不能只退出状态机,否则主机将一直等待0x8B应答。 */
|
||||
result = 0x01u;
|
||||
ota_state = OTA_STATE_IDLE;
|
||||
if (ota_verify_response_pending != 0u)
|
||||
{
|
||||
if (ota_verify_broadcast_request != 0u)
|
||||
{
|
||||
BusinessProtocol_QueueDelayedResponse(ota_verify_response_target,
|
||||
0x8Bu, &result, 1u);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)MeshFrame_SendBusiness(ota_verify_response_target,
|
||||
0x8Bu, &result, 1u);
|
||||
}
|
||||
ota_verify_response_pending = 0u;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (index = 0u; index < chunk; ++index)
|
||||
{
|
||||
ota_verify_crc ^= buffer[index];
|
||||
for (bit = 0u; bit < 8u; ++bit)
|
||||
{
|
||||
if ((ota_verify_crc & 1u) != 0u)
|
||||
{
|
||||
ota_verify_crc = (uint16_t)((ota_verify_crc >> 1u) ^ 0xA001u);
|
||||
}
|
||||
else
|
||||
{
|
||||
ota_verify_crc >>= 1u;
|
||||
}
|
||||
}
|
||||
}
|
||||
ota_verify_offset = (uint16_t)(ota_verify_offset + chunk);
|
||||
|
||||
if (ota_verify_offset >= ota_expected_size)
|
||||
{
|
||||
result = (ota_verify_crc == ota_expected_crc16) ? 0x00u : 0x01u;
|
||||
if (result == 0x00u)
|
||||
{
|
||||
metadata[0] = 0x31u; metadata[1] = 0x41u;
|
||||
metadata[2] = 0x54u; metadata[3] = 0x4Fu;
|
||||
metadata[4] = (uint8_t)(ota_expected_size >> 8u);
|
||||
metadata[5] = (uint8_t)ota_expected_size;
|
||||
metadata[6] = 0u; metadata[7] = 0u;
|
||||
metadata[8] = (uint8_t)(ota_image_version >> 8u);
|
||||
metadata[9] = (uint8_t)ota_image_version;
|
||||
metadata[10] = (uint8_t)(ota_verify_crc >> 8u);
|
||||
metadata[11] = (uint8_t)ota_verify_crc;
|
||||
metadata[12] = 0u; metadata[13] = 0u;
|
||||
metadata[14] = 0xA5u; metadata[15] = 0xA5u;
|
||||
metadata[16] = 0u; metadata[17] = 0u;
|
||||
if (W25Q64App_PageProgram(OTA_METADATA_ADDRESS,
|
||||
metadata, 16u) == 0u ||
|
||||
W25Q64App_PageProgram(OTA_METADATA_ADDRESS + 16ul,
|
||||
&metadata[16], 2u) == 0u)
|
||||
{
|
||||
result = 0x01u;
|
||||
}
|
||||
}
|
||||
ota_state = OTA_STATE_IDLE;
|
||||
if (ota_verify_response_pending != 0u)
|
||||
{
|
||||
if (ota_verify_broadcast_request != 0u)
|
||||
{
|
||||
/* 广播校验请求仍使用随机延时应答,但广播场景不立即
|
||||
* 复位,避免延时队列中的0x8B尚未发出就被复位丢失。 */
|
||||
BusinessProtocol_QueueDelayedResponse(ota_verify_response_target,
|
||||
0x8Bu, &result, 1u);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)MeshFrame_SendBusiness(ota_verify_response_target,
|
||||
0x8Bu, &result, 1u);
|
||||
}
|
||||
ota_verify_response_pending = 0u;
|
||||
|
||||
/* 只有整包CRC正确且OTA元数据已经成功写入时,才在0x8B
|
||||
* 应答发送完成后复位。失败分支必须继续留在当前程序。 */
|
||||
if ((result == 0x00u) && (ota_verify_broadcast_request == 0u))
|
||||
{
|
||||
Watchdog_ResetNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ota_bootloader_result_pending != 0u &&
|
||||
ota_bootloader_result_reported == 0u)
|
||||
{
|
||||
@@ -99,7 +223,8 @@ void OtaManager_Task(void)
|
||||
*/
|
||||
uint8_t OtaManager_HandleCommand(uint8_t command,
|
||||
const uint8_t *data,
|
||||
uint8_t length)
|
||||
uint8_t length,
|
||||
uint16_t response_target)
|
||||
{
|
||||
if (command == OTA_COMMAND_START)
|
||||
{
|
||||
@@ -108,18 +233,17 @@ uint8_t OtaManager_HandleCommand(uint8_t command,
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
ota_expected_size=(uint16_t)data[0]|((uint16_t)data[1]<<8);
|
||||
ota_image_version=(uint16_t)data[2]|((uint16_t)data[3]<<8);
|
||||
if(ota_expected_size==0u)
|
||||
ota_expected_size=((uint16_t)data[0]<<8u)|data[1];
|
||||
ota_image_version=((uint16_t)data[2]<<8u)|data[3];
|
||||
if(ota_expected_size==0u || ota_expected_size > OTA_IMAGE_MAX_SIZE)
|
||||
return 0u;
|
||||
/* 先清除OTA元数据,避免上一次升级请求残留。 */
|
||||
if(W25Q64App_EraseSector(OTA_METADATA_ADDRESS)==0u)
|
||||
return 0u;
|
||||
for(sector=0u;sector<16u;sector++)
|
||||
for(sector=0u;sector<OTA_IMAGE_SECTOR_COUNT;sector++)
|
||||
if(W25Q64App_EraseSector(OTA_IMAGE_ADDRESS+((uint32_t)sector*0x1000ul))==0u)
|
||||
return 0u;
|
||||
ota_image_size=(uint16_t)ota_expected_size;
|
||||
ota_received_size=0u; ota_expected_offset=0u;
|
||||
ota_expected_offset=0u;
|
||||
ota_expected_crc16=0u;
|
||||
ota_state = OTA_STATE_RECEIVING;
|
||||
return 1u;
|
||||
@@ -141,64 +265,42 @@ uint8_t OtaManager_HandleCommand(uint8_t command,
|
||||
payload_length)==0u)
|
||||
return 0u;
|
||||
ota_expected_offset=(uint16_t)(offset+payload_length);
|
||||
ota_received_size=(uint16_t)(ota_received_size+payload_length);
|
||||
}
|
||||
return 1u;
|
||||
}
|
||||
|
||||
if (command == OTA_COMMAND_FINISH)
|
||||
{
|
||||
/* CMD=0x0A的DATA为完整固件CRC16低字节、高字节。 */
|
||||
/* CMD=0x0A的DATA为完整固件CRC16高字节、低字节。 */
|
||||
if (ota_state != OTA_STATE_RECEIVING || data == (const uint8_t *)0 ||
|
||||
length != 2u)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
ota_expected_crc16 = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
|
||||
ota_expected_crc16 = ((uint16_t)data[0] << 8u) | data[1];
|
||||
ota_state = OTA_STATE_READY;
|
||||
return 1u;
|
||||
}
|
||||
|
||||
if (command == 0x0Bu)
|
||||
{
|
||||
uint8_t buffer[16]; uint16_t offset=0u; uint16_t crc=0xFFFFu;
|
||||
uint16_t chunk;
|
||||
uint8_t metadata[18];
|
||||
if(ota_state!=OTA_STATE_READY||ota_received_size!=ota_expected_size)
|
||||
if(ota_state!=OTA_STATE_READY||ota_expected_offset!=ota_expected_size)
|
||||
return 0u;
|
||||
while(offset<ota_image_size){
|
||||
chunk=(uint16_t)(ota_image_size-offset); if(chunk>16u)chunk=16u;
|
||||
if(W25Q64App_Read(OTA_IMAGE_ADDRESS+offset,buffer,chunk)==0u)return 0u;
|
||||
{
|
||||
uint16_t index;
|
||||
for(index=0u;index<chunk;index++)
|
||||
{
|
||||
uint8_t bit; crc^=buffer[index];
|
||||
for(bit=0u;bit<8u;bit++)
|
||||
crc=(crc&1u)?(uint16_t)((crc>>1)^0xA001u):(uint16_t)(crc>>1);
|
||||
}
|
||||
}
|
||||
offset=(uint16_t)(offset+chunk);
|
||||
}
|
||||
if(crc!=ota_expected_crc16)return 0u;
|
||||
metadata[0]=0x31u; metadata[1]=0x41u; metadata[2]=0x54u; metadata[3]=0x4Fu;
|
||||
metadata[4]=(uint8_t)ota_image_size; metadata[5]=(uint8_t)(ota_image_size>>8);
|
||||
metadata[6]=0u; metadata[7]=0u;
|
||||
metadata[8]=(uint8_t)ota_image_version; metadata[9]=(uint8_t)(ota_image_version>>8);
|
||||
metadata[10]=(uint8_t)crc; metadata[11]=(uint8_t)(crc>>8);
|
||||
metadata[12]=0u; metadata[13]=0u; metadata[14]=0xA5u;
|
||||
metadata[15]=0xA5u; metadata[16]=0u; metadata[17]=0u;
|
||||
if(W25Q64App_PageProgram(OTA_METADATA_ADDRESS,metadata,16u)==0u)return 0u;
|
||||
if(W25Q64App_PageProgram(OTA_METADATA_ADDRESS+16ul,&metadata[16],2u)==0u)return 0u;
|
||||
ota_state=OTA_STATE_IDLE;
|
||||
ota_verify_offset = 0u;
|
||||
ota_verify_crc = 0xFFFFu;
|
||||
ota_verify_response_target = response_target;
|
||||
ota_verify_broadcast_request =
|
||||
(MeshFrame_GetLastTargetAddress() == 0xFFFFu) ? 1u : 0u;
|
||||
ota_verify_response_pending = 1u;
|
||||
ota_state = OTA_STATE_VERIFYING;
|
||||
return 1u;
|
||||
}
|
||||
|
||||
if (command == OTA_COMMAND_CANCEL)
|
||||
{
|
||||
ota_state = OTA_STATE_IDLE;
|
||||
ota_received_size = 0u;
|
||||
ota_expected_offset = 0u;
|
||||
return 1u;
|
||||
}
|
||||
|
||||
@@ -222,7 +324,7 @@ uint8_t OtaManager_GetExpectedOffset(uint16_t *offset)
|
||||
|
||||
uint8_t OtaManager_GetBootloaderResult(void)
|
||||
{
|
||||
/* W25Q64读取接口接入后,在此处加载result字段并置pending。 */
|
||||
/* W25Q80BV读取接口接入后,在此处加载result字段并置pending。 */
|
||||
return (ota_bootloader_result_pending != 0u) ? ota_bootloader_result : 0u;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user