2026-09-04 21:08:56 +08:00
|
|
|
|
/* ext_relay.c - 485 <20><>չ<EFBFBD>̵<EFBFBD><CCB5><EFBFBD><EFBFBD><EFBFBD>(4 ·<><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֧<EFBFBD><D6A7>
|
|
|
|
|
|
*
|
|
|
|
|
|
* Ӳ<EFBFBD><EFBFBD>: <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>سӹ<EFBFBD><EFBFBD><EFBFBD> USART2 RS485 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>(9600-8N1, DMA+IDLE <EFBFBD><EFBFBD>֡)
|
|
|
|
|
|
* Э<EFBFBD><EFBFBD>: Modbus RTU, <EFBFBD>ӻ<EFBFBD><EFBFBD><EFBFBD>ַ 0x10, <EFBFBD><EFBFBD><EFBFBD><EFBFBD> Docs/RS485<EFBFBD><EFBFBD>չ<EFBFBD>̵<EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>.md
|
|
|
|
|
|
* FC05 д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȧ(<EFBFBD><EFBFBD>Ȧ0~3=<EFBFBD>̵<EFBFBD><EFBFBD><EFBFBD>1~4, 0xFF00<EFBFBD><EFBFBD><EFBFBD><EFBFBD>/0x0000<EFBFBD>Ͽ<EFBFBD>), <EFBFBD>ӻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* FC03 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ּĴ<EFBFBD><EFBFBD><EFBFBD> 0x0000 <EFBFBD><EFBFBD> 4 <EFBFBD><EFBFBD>: <EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬/<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬/<EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD>־/<EFBFBD>̼<EFBFBD><EFBFBD>汾
|
2026-09-08 14:46:23 +08:00
|
|
|
|
* ʱ<EFBFBD><EFBFBD>: <EFBFBD><EFBFBD><EFBFBD>߾<EFBFBD>Ĭ >=50ms <EFBFBD>ŷ<EFBFBD>֡(<EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> rs485_bus ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>); Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ 300ms <EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1 <EFBFBD><EFBFBD>
|
|
|
|
|
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: ƽʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѯ), ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>շ<EFBFBD>:
|
|
|
|
|
|
* 1) <EFBFBD>ϵ<EFBFBD> 3s <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̽<EFBFBD><EFBFBD>(ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>״̬<EFBFBD>ָ<EFBFBD>)
|
|
|
|
|
|
* 2) ƽ̨/<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: FC03 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ̬(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>) -> FC05 -> 150ms -> FC03 У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* 3) <EFBFBD>ϵ<EFBFBD><EFBFBD>ָ<EFBFBD>: <EFBFBD><EFBFBD><EFBFBD><EFBFBD>-><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ȶ<EFBFBD> EEPROM <EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>һ<EFBFBD>µĻ<EFBFBD>·<EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD> FC05
|
2026-09-04 21:08:56 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "ext_relay.h"
|
|
|
|
|
|
#include "relay.h"
|
2026-09-04 21:23:05 +08:00
|
|
|
|
#include "24c02.h"
|
2026-09-04 21:08:56 +08:00
|
|
|
|
#include "uart.h"
|
|
|
|
|
|
#include "log.h"
|
|
|
|
|
|
#include "network.h"
|
|
|
|
|
|
#include "FreeRTOS.h"
|
|
|
|
|
|
#include "task.h"
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
#define EXT_RESP_TIMEOUT_MS 300u /* Ӧ<><D3A6><EFBFBD><EFBFBD>ʱ */
|
|
|
|
|
|
#define EXT_FB_SETTLE_MS 150u /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժ<EFBFBD><D4BA>ȴ<EFBFBD><C8B4><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6>ٶ<EFBFBD><D9B6><EFBFBD><EFBFBD><EFBFBD> */
|
2026-09-08 14:46:23 +08:00
|
|
|
|
|
|
|
|
|
|
/* ֡<>¼<EFBFBD>(on_frame <20><>λ, process <20><><EFBFBD><EFBFBD>; ͬ<><CDAC> app_task <20><><EFBFBD>߳<EFBFBD>) */
|
|
|
|
|
|
static uint8_t rx_echo_ok = 0;
|
|
|
|
|
|
static uint8_t rx_state_ok = 0;
|
|
|
|
|
|
static uint8_t rx_exc = 0;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
|
|
|
|
|
|
/* Modbus CRC16(<28><><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ) */
|
|
|
|
|
|
static uint16_t ext_crc16(const uint8_t *data, uint16_t len)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t crc = 0xFFFF;
|
|
|
|
|
|
for (uint16_t i = 0; i < len; i++) {
|
|
|
|
|
|
crc ^= data[i];
|
|
|
|
|
|
for (uint8_t j = 0; j < 8; j++) {
|
|
|
|
|
|
crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return crc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20><><EFBFBD>߷<EFBFBD><DFB7><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>־ + <20><> 50ms <20><>Ĭ + <20><><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD> + <20><><EFBFBD><EFBFBD> + ˢ<><CBA2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
static void ext_tx(const uint8_t *frame, uint16_t len)
|
|
|
|
|
|
{
|
2026-09-08 14:46:23 +08:00
|
|
|
|
rx_echo_ok = 0;
|
2026-09-08 12:53:24 +08:00
|
|
|
|
rx_state_ok = 0;
|
|
|
|
|
|
rx_exc = 0;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
uint32_t dt = HAL_GetTick() - rs485_bus_last_tick();
|
|
|
|
|
|
if (dt < 50u) vTaskDelay(50u - dt);
|
|
|
|
|
|
USART2_FlushRxBuf();
|
|
|
|
|
|
HAL_UART_Transmit(&huart2, (uint8_t *)frame, len, 100);
|
|
|
|
|
|
rs485_bus_touch();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ext_send_fc05(uint8_t ch, uint8_t on)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t f[8];
|
|
|
|
|
|
f[0] = EXT_RELAY_ADDR;
|
|
|
|
|
|
f[1] = 0x05;
|
|
|
|
|
|
f[2] = 0x00;
|
|
|
|
|
|
f[3] = (uint8_t)(ch - 1); /* <20><>Ȧ<EFBFBD><C8A6>ַ 0~3 */
|
|
|
|
|
|
f[4] = on ? 0xFF : 0x00;
|
|
|
|
|
|
f[5] = 0x00;
|
|
|
|
|
|
uint16_t c = ext_crc16(f, 6);
|
|
|
|
|
|
f[6] = (uint8_t)(c & 0xFF);
|
|
|
|
|
|
f[7] = (uint8_t)(c >> 8);
|
|
|
|
|
|
ext_tx(f, 8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ext_send_fc03(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t f[8];
|
|
|
|
|
|
f[0] = EXT_RELAY_ADDR;
|
|
|
|
|
|
f[1] = 0x03;
|
|
|
|
|
|
f[2] = 0x00; f[3] = 0x00; /* <20><>ʼ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD> 0x0000 */
|
|
|
|
|
|
f[4] = 0x00; f[5] = 0x04; /* <20><> 4 <20><> */
|
|
|
|
|
|
uint16_t c = ext_crc16(f, 6);
|
|
|
|
|
|
f[6] = (uint8_t)(c & 0xFF);
|
|
|
|
|
|
f[7] = (uint8_t)(c >> 8);
|
|
|
|
|
|
ext_tx(f, 8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* <20><>չ<EFBFBD><D5B9>״̬(<28><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> FC03 Ӧ<><D3A6>) */
|
|
|
|
|
|
static uint8_t s_online = 0;
|
|
|
|
|
|
static uint8_t s_state = 0; /* REG0 <20><><EFBFBD><EFBFBD>״̬ bit0~3 */
|
|
|
|
|
|
static uint8_t s_fb = 0; /* REG1 <20><><EFBFBD><EFBFBD>״̬ */
|
|
|
|
|
|
static uint8_t s_fault = 0; /* REG2 <20><><EFBFBD>ϱ<EFBFBD>־ */
|
|
|
|
|
|
static uint16_t s_ver = 0; /* REG3 <20>ӻ<EFBFBD><D3BB>汾 */
|
2026-09-08 12:53:24 +08:00
|
|
|
|
static uint8_t s_fault_logged = 0; /* <20>Ѵ<EFBFBD>ӡ<EFBFBD>Ĺ<EFBFBD><C4B9><EFBFBD>λ(<28>仯<EFBFBD><E4BBAF><EFBFBD>ش<EFBFBD>) */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define ST_IDLE 0 /* <20><><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define ST_READ 1 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20>ϵ<EFBFBD>̽<EFBFBD><CCBD> / <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>ȡ */
|
|
|
|
|
|
#define ST_ECHO 2 /* <20><> FC05 <20><><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define ST_SETTLE 3 /* <20><><EFBFBD><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6><EFBFBD>ʱ */
|
|
|
|
|
|
#define ST_CONFIRM 4 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3> */
|
|
|
|
|
|
|
|
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define TXN_NONE 0 /* <20>ϵ<EFBFBD>̽<EFBFBD><CCBD> */
|
|
|
|
|
|
#define TXN_CMD 1 /* ƽ̨/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define TXN_RESTORE 2 /* <20>ϵ<EFBFBD><CFB5>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t cmd_stage = ST_IDLE;
|
|
|
|
|
|
static uint8_t cmd_txn = TXN_NONE;
|
|
|
|
|
|
static uint8_t cmd_pending = 0; /* <20><><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
static uint8_t cmd_ch = 0, cmd_on = 0, cmd_retry = 0;
|
|
|
|
|
|
static uint32_t cmd_tick = 0;
|
|
|
|
|
|
static char cmd_id[20] = {0};
|
2026-09-08 14:46:23 +08:00
|
|
|
|
static uint8_t cmd_state_before = 0; /* <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>λ(FC03 Ԥ<><D4A4>ֵ) */
|
|
|
|
|
|
static uint8_t cmd_fb_before = 0; /* <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>λ(FC03 Ԥ<><D4A4>ֵ) */
|
|
|
|
|
|
static uint8_t boot_probe_done = 0; /* <20>ϵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>̽<EFBFBD><CCBD><EFBFBD>ѷ<EFBFBD> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
|
2026-09-04 21:23:05 +08:00
|
|
|
|
#define EXT_STATE_EEPROM_IDX 5 /* MqttInfoStr.Relay_State[5] ԭ<><D4AD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>: <20><>չ<EFBFBD><D5B9>״̬λ<CCAC><CEBB><EFBFBD><EFBFBD> */
|
|
|
|
|
|
|
|
|
|
|
|
/* <20>ϵ<EFBFBD><CFB5>ָ<EFBFBD>״̬ */
|
|
|
|
|
|
static uint8_t restore_diff = 0; /* <20><><EFBFBD>ָ<EFBFBD>λ(ʵ<><CAB5>!=<3D><><EFBFBD><EFBFBD>) */
|
|
|
|
|
|
static uint8_t restore_target = 0; /* <20>ָ<EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(EEPROM <20><><EFBFBD><EFBFBD>) */
|
|
|
|
|
|
static uint32_t restore_next_tick = 0; /* <20>ָ<EFBFBD>ʧ<EFBFBD>ܺ<EFBFBD><DCBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˱<EFBFBD> */
|
|
|
|
|
|
|
|
|
|
|
|
/* EEPROM <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><D5B9>״̬(0xFF=<3D>հ<EFBFBD><D5B0><EFBFBD>Ϊȫ<CEAA><C8AB>) */
|
|
|
|
|
|
static uint8_t ext_saved_mask(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t v = MqttInfoStr.Relay_State[EXT_STATE_EEPROM_IDX];
|
|
|
|
|
|
if (v == 0xFF) return 0;
|
|
|
|
|
|
return (uint8_t)(v & 0x0F);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* <20><> FC03 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬ˢ<CCAC><CBA2> EEPROM(<28>仯<EFBFBD><E4BBAF>д) */
|
|
|
|
|
|
static void ext_save_state(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t nv = (uint8_t)(s_state & 0x0F);
|
|
|
|
|
|
if (MqttInfoStr.Relay_State[EXT_STATE_EEPROM_IDX] != nv) {
|
|
|
|
|
|
MqttInfoStr.Relay_State[EXT_STATE_EEPROM_IDX] = nv;
|
|
|
|
|
|
eepromWriteData(102, &MqttInfoStr.Relay_State[0], 7);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-04 21:08:56 +08:00
|
|
|
|
uint8_t ext_relay_online(void) { return s_online; }
|
|
|
|
|
|
uint8_t ext_relay_state_mask(void) { return s_state; }
|
|
|
|
|
|
uint8_t ext_relay_fault_mask(void) { return s_fault; }
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* һ<><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>: fresh_state=1 <20><>ʾ<EFBFBD><CABE><EFBFBD>յ<EFBFBD> FC03(״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>) */
|
2026-09-04 21:23:05 +08:00
|
|
|
|
static void ext_note_success(int fresh_state)
|
2026-09-04 21:08:56 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!s_online) {
|
|
|
|
|
|
s_online = 1;
|
|
|
|
|
|
log_info("> EXT: <20><>չ<EFBFBD>̵<EFBFBD><CCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28>ӻ<EFBFBD><D3BB>汾 V%u.%02X)", s_ver >> 8, s_ver & 0xFF);
|
|
|
|
|
|
relayStatueUpdata(); /* <20><><EFBFBD>ߺ<EFBFBD><DFBA><EFBFBD>һ<EFBFBD><D2BB>ȫ״̬, ƽ̨ˢ<CCA8><CBA2> sw5~sw8 */
|
2026-09-04 21:23:05 +08:00
|
|
|
|
/* <20>ϵ<EFBFBD><CFB5>ָ<EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬ʱ, <20>ȶ<EFBFBD> EEPROM <20><><EFBFBD><EFBFBD>, <20><>һ<EFBFBD>µĻ<C2B5>·<EFBFBD><C2B7><EFBFBD><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD> */
|
|
|
|
|
|
if (fresh_state) {
|
|
|
|
|
|
uint8_t saved = ext_saved_mask();
|
|
|
|
|
|
uint8_t diff = (uint8_t)((s_state ^ saved) & 0x0F);
|
|
|
|
|
|
if (diff) {
|
|
|
|
|
|
restore_diff = diff;
|
|
|
|
|
|
restore_target = saved;
|
|
|
|
|
|
log_warn("> EXT: <20><>չ<EFBFBD><D5B9>״̬<D7B4><CCAC><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD>䲻<EFBFBD><E4B2BB>(ʵ<><CAB5>=%02X <20><><EFBFBD><EFBFBD>=%02X), <20><>·<EFBFBD>ָ<EFBFBD>", s_state, saved);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ext_note_fail(void)
|
|
|
|
|
|
{
|
2026-09-08 14:46:23 +08:00
|
|
|
|
if (s_online) {
|
2026-09-04 21:08:56 +08:00
|
|
|
|
s_online = 0;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
log_warn("> EXT: <20><>չ<EFBFBD>̵<EFBFBD><CCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>)");
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ext_respond(int ok, const char *msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cmd_id[0]) {
|
2026-09-14 10:23:05 +08:00
|
|
|
|
NET_publish_response_wait(cmd_id, ok, msg); /* <20><>ģ<EFBFBD><C4A3> OK+<2B><><EFBFBD><EFBFBD>, <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>ʧ */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
cmd_id[0] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ext_relay_cmd(uint8_t ch, uint8_t on, const char *id)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ch < 1 || ch > EXT_RELAY_CH) return;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD>ճ<EFBFBD><D5B3><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FC03 ̽<><CCBD>, <20><>ͨ<EFBFBD><CDA8>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(ƽʱ<C6BD><CAB1><EFBFBD><EFBFBD>ѯ) */
|
|
|
|
|
|
if (cmd_pending || cmd_stage != ST_IDLE) {
|
2026-09-04 21:08:56 +08:00
|
|
|
|
log_warn("> EXT: <20><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>, <20>ܾ<EFBFBD> SW%d <20><><EFBFBD><EFBFBD>", ch + 4);
|
2026-09-13 21:35:11 +08:00
|
|
|
|
if (id) NET_publish_response(id, 0, "\xE6\x89\xA9\xE5\xB1\x95\xE6\x9D\xBF\xE5\xBF\x99\xE8\xAF\xB7\xE9\x87\x8D\xE8\xAF\x95");
|
2026-09-04 21:08:56 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
cmd_ch = ch;
|
|
|
|
|
|
cmd_on = on ? 1 : 0;
|
|
|
|
|
|
if (id) {
|
|
|
|
|
|
strncpy(cmd_id, id, sizeof(cmd_id) - 1);
|
|
|
|
|
|
cmd_id[sizeof(cmd_id) - 1] = 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cmd_id[0] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
cmd_pending = 1;
|
|
|
|
|
|
log_info("> EXT: SW%d %s (<28>·<EFBFBD><C2B7><EFBFBD>չ<EFBFBD><D5B9>)", ch + 4, on ? "<EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 485 ֡<><D6A1><EFBFBD><EFBFBD>: feed_scale <20><>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>վ<EFBFBD><D5BE> 0x10 <20>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
void ext_relay_on_frame(const uint8_t *b, uint16_t len)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (len < 5) return;
|
|
|
|
|
|
uint16_t c = ext_crc16(b, (uint16_t)(len - 2));
|
|
|
|
|
|
uint16_t r = (uint16_t)(((uint16_t)b[len - 1] << 8) | b[len - 2]);
|
|
|
|
|
|
if (c != r) {
|
|
|
|
|
|
log_warn("> EXT: ֡ CRC <20><><EFBFBD><EFBFBD> (len=%u)", (unsigned)len);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (b[1] & 0x80) { /* Modbus <20>쳣Ӧ<ECB3A3><D3A6> */
|
|
|
|
|
|
log_warn("> EXT: <20>쳣Ӧ<ECB3A3><D3A6> FC=%02X <20><>=%02X", b[1] & 0x7F, b[2]);
|
|
|
|
|
|
rx_exc = 1;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (b[1] == 0x05 && len == 8) {
|
|
|
|
|
|
/* <20><><EFBFBD><EFBFBD>У<EFBFBD><D0A3>: <20><>Ȧ<EFBFBD><C8A6>ַ<EFBFBD><D6B7>ͨ<EFBFBD><CDA8>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> */
|
|
|
|
|
|
if (b[2] == 0x00 && b[3] == (uint8_t)(cmd_ch - 1) &&
|
|
|
|
|
|
((b[4] == 0xFF && cmd_on) || (b[4] == 0x00 && !cmd_on)) && b[5] == 0x00) {
|
|
|
|
|
|
rx_echo_ok = 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log_warn("> EXT: FC05 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (b[1] == 0x03 && len == 13 && b[2] == 0x08) {
|
|
|
|
|
|
/* 4 <20><><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD>ֻ<EFBFBD>õ<EFBFBD><C3B5>ֽ<EFBFBD> */
|
|
|
|
|
|
s_state = b[4] & 0x0F;
|
|
|
|
|
|
s_fb = b[6] & 0x0F;
|
|
|
|
|
|
s_fault = b[8] & 0x0F;
|
|
|
|
|
|
s_ver = (uint16_t)(((uint16_t)b[9] << 8) | b[10]);
|
|
|
|
|
|
rx_state_ok = 1;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
log_warn("> EXT: δʶ<CEB4><CAB6>֡ FC=%02X len=%u", b[1], (unsigned)len);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7><EFBFBD><EFBFBD>β */
|
|
|
|
|
|
static void ext_txn_failed(const char *respond_msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cmd_txn == TXN_CMD) {
|
|
|
|
|
|
log_warn("> EXT: SW%d <20><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>(%s)", cmd_ch + 4, respond_msg);
|
|
|
|
|
|
ext_respond(0, respond_msg);
|
|
|
|
|
|
} else if (cmd_txn == TXN_RESTORE) {
|
|
|
|
|
|
restore_next_tick = HAL_GetTick() + 2000; /* <20>˱ܺ<CBB1><DCBA><EFBFBD><EFBFBD><EFBFBD>, λ<><CEBB><EFBFBD><EFBFBD> */
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log_warn("> EXT: <20>ϵ<EFBFBD>̽<EFBFBD><CCBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>(δ<><CEB4><EFBFBD><EFBFBD>չ<EFBFBD><D5B9>?)");
|
|
|
|
|
|
}
|
|
|
|
|
|
ext_note_fail();
|
|
|
|
|
|
cmd_txn = TXN_NONE;
|
|
|
|
|
|
cmd_stage = ST_IDLE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ/<2F>쳣ͳһ<CDB3><D2BB><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD> 1 <20><>, <20><>ʧ<EFBFBD><CAA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β */
|
|
|
|
|
|
static void ext_txn_retry_or_fail(uint8_t resend_fc05, const char *respond_msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cmd_retry < 1) {
|
|
|
|
|
|
cmd_retry++;
|
|
|
|
|
|
if (resend_fc05) ext_send_fc05(cmd_ch, cmd_on);
|
|
|
|
|
|
else ext_send_fc03();
|
|
|
|
|
|
cmd_tick = HAL_GetTick();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
ext_txn_failed(respond_msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-04 21:08:56 +08:00
|
|
|
|
void ext_relay_process(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t now = HAL_GetTick();
|
|
|
|
|
|
if (now < 3000u) return; /* <20>ϵ<EFBFBD><CFB5>ȶ<EFBFBD><C8B6><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD>״β<D7B4>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD> */
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20>ϵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>̽<EFBFBD><CCBD>: ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + <20><><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5>ָ<EFBFBD><D6B8>ȶ<EFBFBD> */
|
|
|
|
|
|
if (!boot_probe_done && cmd_stage == ST_IDLE && !cmd_pending) {
|
|
|
|
|
|
boot_probe_done = 1;
|
|
|
|
|
|
cmd_txn = TXN_NONE;
|
|
|
|
|
|
cmd_retry = 0;
|
|
|
|
|
|
cmd_stage = ST_READ;
|
|
|
|
|
|
ext_send_fc03();
|
|
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>: <20><> FC03 Ԥ<><D4A4>(<28>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ״̬) */
|
|
|
|
|
|
if (cmd_pending && cmd_stage == ST_IDLE) {
|
2026-09-04 21:08:56 +08:00
|
|
|
|
cmd_pending = 0;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_txn = TXN_CMD;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
cmd_retry = 0;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_stage = ST_READ;
|
|
|
|
|
|
ext_send_fc03();
|
2026-09-04 21:08:56 +08:00
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
if (cmd_stage == ST_READ) {
|
|
|
|
|
|
if (rx_state_ok) {
|
|
|
|
|
|
rx_state_ok = 0;
|
|
|
|
|
|
ext_note_success(1);
|
|
|
|
|
|
if (s_fault != s_fault_logged) { /* <20><><EFBFBD><EFBFBD>λ<EFBFBD>仯<EFBFBD>Ŵ<EFBFBD>ӡ */
|
|
|
|
|
|
s_fault_logged = s_fault;
|
|
|
|
|
|
if (s_fault) {
|
|
|
|
|
|
log_warn("> EXT: <20><><EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><ECB3A3>־=%02X (<28><><EFBFBD><EFBFBD>=%02X <20><><EFBFBD><EFBFBD>=%02X)", s_fault, s_state, s_fb);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (cmd_txn == TXN_CMD) {
|
|
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ״̬(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>: У<>鷴<EFBFBD><E9B7B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>гɹ<D0B3>) */
|
|
|
|
|
|
cmd_state_before = (uint8_t)((s_state >> (cmd_ch - 1)) & 1u);
|
|
|
|
|
|
cmd_fb_before = (uint8_t)((s_fb >> (cmd_ch - 1)) & 1u);
|
|
|
|
|
|
cmd_retry = 0;
|
|
|
|
|
|
cmd_stage = ST_ECHO;
|
|
|
|
|
|
ext_send_fc05(cmd_ch, cmd_on);
|
|
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cmd_txn = TXN_NONE;
|
|
|
|
|
|
cmd_stage = ST_IDLE; /* <20>ϵ<EFBFBD>̽<EFBFBD><CCBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
|
|
|
|
|
rx_exc = 0;
|
|
|
|
|
|
if (cmd_txn == TXN_CMD) {
|
2026-09-13 21:35:11 +08:00
|
|
|
|
ext_txn_retry_or_fail(0, "\xE6\x89\xA9\xE5\xB1\x95\xE6\x9D\xBF\xE4\xB8\x8D\xE5\x9C\xA8\xE7\xBA\xBF");
|
2026-09-08 14:46:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
ext_txn_retry_or_fail(0, "");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cmd_stage == ST_ECHO) { /* <20><> FC05 <20><><EFBFBD><EFBFBD> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
if (rx_echo_ok) {
|
|
|
|
|
|
rx_echo_ok = 0;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
ext_note_success(0);
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_stage = ST_SETTLE;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
|
|
|
|
|
rx_exc = 0;
|
2026-09-13 21:35:11 +08:00
|
|
|
|
ext_txn_retry_or_fail(1, "\xE6\x89\xA9\xE5\xB1\x95\xE6\x9D\xBF\xE6\x97\xA0\xE5\xBA\x94\xE7\xAD\x94");
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
if (cmd_stage == ST_SETTLE) { /* <20><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6><EFBFBD>ʱ */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
if ((now - cmd_tick) >= EXT_FB_SETTLE_MS) {
|
|
|
|
|
|
cmd_retry = 0;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_stage = ST_CONFIRM;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
ext_send_fc03();
|
|
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
if (cmd_stage == ST_CONFIRM) { /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
if (rx_state_ok) {
|
|
|
|
|
|
rx_state_ok = 0;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
ext_note_success(1);
|
2026-09-08 14:46:23 +08:00
|
|
|
|
if (cmd_txn == TXN_RESTORE) {
|
|
|
|
|
|
cmd_txn = TXN_NONE;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
restore_diff &= (uint8_t)~(1u << (cmd_ch - 1));
|
|
|
|
|
|
if (!restore_diff) {
|
|
|
|
|
|
log_info("> EXT: <20>ϵ<EFBFBD>״̬<D7B4>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD>=%02X)", s_state);
|
|
|
|
|
|
ext_save_state();
|
|
|
|
|
|
relayStatueUpdata();
|
|
|
|
|
|
}
|
2026-09-04 21:08:56 +08:00
|
|
|
|
} else {
|
2026-09-08 12:59:18 +08:00
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ؼ̵<D8BC><CCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD>λ=Ŀ<><C4BF> <20><> <20><><EFBFBD><EFBFBD>λ=Ŀ<><C4BF> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* (<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ!=Ŀ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=Ŀ<EFBFBD><EFBFBD>); <EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><EFBFBD>̬<EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<EFBFBD><EFBFBD><EFBFBD>Է<EFBFBD>)ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -> <EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> OK */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
uint8_t bit = (uint8_t)(1u << (cmd_ch - 1));
|
2026-09-08 12:59:18 +08:00
|
|
|
|
int state_ok = (((s_state & bit) != 0) == cmd_on);
|
|
|
|
|
|
int fb_ok = (((s_fb & bit) != 0) == cmd_on);
|
|
|
|
|
|
int fb_trans = (cmd_fb_before != cmd_on);
|
|
|
|
|
|
int was_already = (cmd_state_before == cmd_on);
|
|
|
|
|
|
int ok = state_ok && fb_ok && (fb_trans || was_already);
|
2026-09-04 21:08:56 +08:00
|
|
|
|
if (ok) {
|
|
|
|
|
|
log_info("> EXT: SW%d %s<>ɹ<EFBFBD> (<28><><EFBFBD><EFBFBD>=%02X)", cmd_ch + 4, cmd_on ? "<EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>", s_fb);
|
|
|
|
|
|
ext_respond(1, "OK");
|
|
|
|
|
|
} else {
|
2026-09-08 12:59:18 +08:00
|
|
|
|
log_warn("> EXT: SW%d %sδ<73><CEB4>Ч (<28><><EFBFBD><EFBFBD>=%02X <20><><EFBFBD><EFBFBD>=%02X <20><><EFBFBD><EFBFBD>=%02X, <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>=%d <20><><EFBFBD><EFBFBD>=%d)",
|
|
|
|
|
|
cmd_ch + 4, cmd_on ? "<EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>", s_state, s_fb, s_fault,
|
|
|
|
|
|
cmd_state_before, cmd_fb_before);
|
2026-09-13 21:29:55 +08:00
|
|
|
|
ext_respond(0, "\xE8\xB4\x9F\xE8\xBD\xBD\xE6\x96\xAD\xE5\xBC\x80\xE6\x88\x96\xE7\xBB\xA7\xE7\x94\xB5\xE5\x99\xA8\xE6\x8D\x9F\xE5\x9D\x8F"); /* <20><><EFBFBD>ضϿ<D8B6><CFBF><EFBFBD><EFBFBD>̵<EFBFBD><CCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(UTF-8 <20>ֽ<EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ<EFBFBD>һ<EFBFBD><D2BB>) */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_txn = TXN_NONE;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
ext_save_state(); /* <20>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD>: <20><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD> */
|
2026-09-04 21:08:56 +08:00
|
|
|
|
relayStatueUpdata(); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA>ϱ<EFBFBD>ȫ״̬ */
|
|
|
|
|
|
}
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_stage = ST_IDLE;
|
2026-09-04 21:08:56 +08:00
|
|
|
|
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
|
|
|
|
|
rx_exc = 0;
|
2026-09-13 21:35:11 +08:00
|
|
|
|
ext_txn_retry_or_fail(0, "\xE6\x89\xA9\xE5\xB1\x95\xE6\x9D\xBF\xE6\x97\xA0\xE5\xBA\x94\xE7\xAD\x94");
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-08 14:46:23 +08:00
|
|
|
|
/* <20>ϵ<EFBFBD><CFB5>ָ<EFBFBD>: <20><>·<EFBFBD><C2B7><EFBFBD><EFBFBD> FC05 ʹ<><CAB9>չ<EFBFBD><D5B9><EFBFBD>ص<EFBFBD> EEPROM <20><><EFBFBD><EFBFBD>״̬(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ) */
|
|
|
|
|
|
if (restore_diff && now >= restore_next_tick && cmd_stage == ST_IDLE && !cmd_pending) {
|
2026-09-04 21:23:05 +08:00
|
|
|
|
uint8_t bit = (uint8_t)(restore_diff & (uint8_t)(-(int)restore_diff)); /* <20><><EFBFBD>ʹ<EFBFBD><CDB4>ָ<EFBFBD>λ */
|
|
|
|
|
|
uint8_t ch = 1;
|
|
|
|
|
|
while (!(bit & 1)) { bit >>= 1; ch++; }
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_txn = TXN_RESTORE;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
cmd_ch = ch;
|
|
|
|
|
|
cmd_on = (uint8_t)((restore_target >> (ch - 1)) & 1u);
|
|
|
|
|
|
cmd_retry = 0;
|
2026-09-08 14:46:23 +08:00
|
|
|
|
cmd_stage = ST_ECHO;
|
2026-09-04 21:23:05 +08:00
|
|
|
|
ext_send_fc05(cmd_ch, cmd_on);
|
|
|
|
|
|
cmd_tick = now;
|
|
|
|
|
|
log_info("> EXT: <20>ָ<EFBFBD> SW%d -> %s", ch + 4, cmd_on ? "<EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-09-04 21:08:56 +08:00
|
|
|
|
}
|