feat(ota): 电机 OTA 支持 EtherCAT 模式(CoE 邮箱进料 + 通道独占锁)
进料口从「只有 ESP32 SPI 一条」扩成两条,中继引擎不变:主站经 CoE 0x2511 数据窗 把电机固件明文灌进 GD32 的 48KB SRAM 暂存区,再由 comm/ecat_motor_ota 泵进原有 4KB 环缓;AES 握手、CAN 单发停等、重发、0AAC 运行确认全部沿用 MotorOtaRelay。 纯网线(ESP32 WiFi 关断、/motor/ota 打不通)场合因此也能刷电机。 偏移/幂等判据仍只有一份:feedData 拆出 feedAt,两个进料口共用。 同时把审计报告 VULN-12/13/14 落地(此前只存在于文档,一行未实现):start() 第一条 语句在 PRIMASK 内原子置位 s_channel_lock_mask,EtherCAT 桥接 sendBatch/processOutput 与 SPI 0xC0/0xC7 对锁定通道回新码 0xE7=「被电机 OTA 独占」,不冒充「邮箱满」0xE4。 反向互斥一并补上:电机 OTA 活跃时 requestEnterBoot() 直接拒绝——SPI 0xB0、CoE 0x2502、 CAN 0x320 三条交接入口共用这一个判据,避免复位把刷写腰斩在 erase 之后。 完整性口径按链路分开,不互相冒充:块级 CRC32 + 整镜像 CRC32 都在从站核,且核过才 让电机进 BOOT——失败时电机仍跑旧 APP、擦除没开始,不存在「先擦再验」的变砖路径。 CRC 为 CRC-32/B(poly 0x04C11DB7,初值 0xFFFFFFFF,无反射无末尾异或),与 v2_crc32 同算法(用公开向量 123456789=0x0376E6E7 对过)。 块长取 1024 而不是 BOOT 用的 4096:SSC 的分段下载缓冲是全工程唯一的 malloc 用户, 而 APP 的 __HEAP_SIZE 只有 3KB,4096 会被从站当场回 abort 0x05040005 Out of memory (BOOT 的堆是 16KB 才撑得住 4096——块长能抄,堆抄不了)。这是跨仓常量,须与 tools/ecat 的 MFO_CHUNK_OBJ 同步。 APP 1.7.4(RAM ZI 97156)。已实测:0x2510 参数写与一块 1016B 数据写均被从站接受 (staged=1016、phase bit4);端到端电机刷写待复测(native 块长修复后未跑完整一轮)。
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include "comm/ethercat_can_bridge.h"
|
||||
#include "device/canfd.h"
|
||||
#include "device/motor_state.h"
|
||||
#include "sys/motor_ota_relay.h"
|
||||
#include "sys/systick.h"
|
||||
|
||||
#include "RTE_Components.h"
|
||||
@@ -108,6 +109,12 @@ uint8_t EthercatCanBridge::sendBatch(const uint8_t *out)
|
||||
CanFd::CanTxResult r;
|
||||
if (!CanFd::isChannelEnabled(ch)) {
|
||||
r = CanFd::CanTxResult::kErrInvalid;
|
||||
} else if (MotorOtaRelay::isChannelLocked(ch)) {
|
||||
/* 该通道正被电机 OTA 独占:PDO 运动帧一律不投递。
|
||||
* OTA 用单发模式(ARD=1),一旦挤进同一个邮箱就会 abort 掉在途的
|
||||
* 0x101 固件包,或让电机 BOOT 收到非预期长度直接回 0x05/0x06。
|
||||
* 计数与 lastTxResult 走 0xE7,主站侧能看到「被 OTA 挡了」而不是「邮箱满」。 */
|
||||
r = CanFd::CanTxResult::kErrOtaLocked;
|
||||
} else {
|
||||
r = CanFd::enqueueTx(ch, rd32le(&f[ECAT_FRM_OFF_ID]),
|
||||
&f[ECAT_FRM_HDR_SIZE], dlc);
|
||||
@@ -322,6 +329,9 @@ void EthercatCanBridge::processOutput(const uint8_t *out)
|
||||
if (dlc > 0U) {
|
||||
if (!CanFd::isChannelEnabled(ch)) {
|
||||
s_lastTxResult = (uint8_t)CanFd::CanTxResult::kErrInvalid;
|
||||
} else if (MotorOtaRelay::isChannelLocked(ch)) {
|
||||
/* 同 sendBatch:OTA 独占通道,周期运动帧不投邮箱(0xE7 上报主站)。 */
|
||||
s_lastTxResult = (uint8_t)CanFd::CanTxResult::kErrOtaLocked;
|
||||
} else {
|
||||
const CanFd::CanTxResult r =
|
||||
CanFd::enqueueTx(ch, rd32le(&out[ECAT_CAN_TX_OFF_ID]),
|
||||
|
||||
Reference in New Issue
Block a user