commit 036a74c7ba288f1b7eabd6c8c7479ad9256ceba8 Author: CSSC-WORK\murmur Date: Thu Sep 12 16:18:07 2024 +0800 完成框架 diff --git a/tcl.c b/tcl.c new file mode 100644 index 0000000..14673f0 --- /dev/null +++ b/tcl.c @@ -0,0 +1,294 @@ +// 透传缆 + +#include +#include +#include "MultiTimer.h" + +#define CMD_TRA_MODE 0xA1 +#define CMD_REC_MODE 0xA2 +#define CMD_SLP_MODE 0xA3 +#define CMD_WKP_MODE 0xA4 +#define CMD_ACK_OK 0xAB +#define CMD_ACK_NOK 0xAF + +#define MIN_TR_PERIOD_MS 1000 * 5 // 单字节最小传输时间 +#define HOST_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000) // 主机重试时间间隔 +#define CLIENT_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000 * 10) // 客户端重试时间间隔 + +static int devMode = HOST_MODE; +static int curMode = R_MODE; +static int tarMode = R_MODE; +static int trySwt = 0; // 是否尝试切换到发送模式 +static int tarDevMode = R_MODE; // 目标端工作模式 +static MultiTimer retryTimer, timeoutTimer; // 重试定时器、超时定时器 + +/// @brief 主从模式,主机拥有更高优先级 +enum +{ + HOST_MODE = 0, + CLIENT_MODE +}; + +/// @brief 工作模式,收、发、休眠、唤醒 +enum +{ + T_MODE = 0, + R_MODE, + SLEEP_MODE, + WORK_MODE +}; + +// 设置GPIO电平 +void setGpioLevel(int gpio, int level) +{ + // 设置GPIO电平 +} + +/// @brief 初始化工作模式,仅设置对应GPIO电平 +/// @param cfg +void initWorkMode(int cfg) +{ + switch (cfg) + { + case T_MODE: + /* code */ + break; + case R_MODE: + /* code */ + break; + case SLEEP_MODE: + /* code */ + break; + case WORK_MODE: + /* code */ + break; + default: + break; + } +} + +/// @brief 通过透传缆串口发送数据 +/// @param data 待发送数据 +/// @param len 待发送数据长度 +void lineTransmitData(uint8_t *data, uint8_t len) +{ + // 发送数据前后需初始化为发送模式 + initWorkMode(T_MODE); + // 发送数据 + + // 发送完毕后需恢复为接收模式 + initWorkMode(R_MODE); +} + +/// @brief 通过用户串口发送数据 +/// @param data 待发送数据 +/// @param len 待发送数据长度 +void userTransmitData(uint8_t *data, uint8_t len) +{ +} + +/// @brief 切换为接收模式 +void switchToRecMode() +{ + lineTransmitData(CMD_REC_MODE, 1); + // 不需要ACK + curMode = R_MODE; + tarMode = R_MODE; +} + +/// @brief 切换为发送模式 +// +// 以ACK回复判断是否切换成功 +// 切换失败则定时重试 +void switchToTraMode() +{ + // tarMode = T_MODE; + + lineTransmitData(CMD_REC_MODE, 1); + + // 接收ACK + uint8_t ack[] = {}; + uint8_t len = 0; + recvData(ack, len, 2000); // 阻塞等待 + if (len == 1 && ack[0] == CMD_ACK_OK) + { + // 切换发送模式成功 + curMode = T_MODE; + tarMode = R_MODE; + // initWorkMode(T_MODE); + // return 0; + } + else + { + // 切换发送模式失败 + // 恢复为接收模式 + switchToRecMode(); + tarMode = T_MODE; // 触发定时重试 + } +} + +uint64_t getPlatformTicks(void) +{ + /* Platform-specific implementation */ +} + +// Callback functions for the timers +void retryTimerCallback(MultiTimer *timer, void *userData) +{ + if (tarDevMode == R_MODE && curMode == R_MODE && tarMode == T_MODE) // 两端为收方可发起请求 + { + trySwt = 1; + } + + printf("Timer 1 fired at %lu ms\n", getPlatformTicks()); +} + +/// @brief +/// @param data +/// @param len +/// @return 0->校验失败 1->校验成功 +int crc(uint8_t *data, uint8_t len) +{ + return 0; +} + +/// @brief 检查数据有效性 +/// @param data +/// @param len +/// @return 1->有效 0->无效 +int isDataValid(uint8_t *data, uint8_t len) +{ + // 按帧发送数据 + // 判断帧的完整性及校验位 + if (data[0] != 0x5A || data[1] != 0xA5 || data[len - 1] != 0xED) // 帧头、帧尾校验 + { + return 0; + } + + if (crc(data + 2, len - 2) != 0) // 校验位校验 + { + return 0; + } + + return 1; +} + +/// @brief 用户接口接收数据回调 +/// @param data +/// @param len +void userRecDataCallback(uint8_t *data, uint8_t len) +{ + if (len == 1) + { + switch (data[0]) + { + case CMD_REC_MODE: + switchToRecMode(); + break; + + case CMD_TRA_MODE: + if (curMode == R_MODE && tarDevMode == R_MODE) + { + switchToTraMode(); + // ok + } + break; + + case CMD_SLP_MODE: + initWorkMode(SLEEP_MODE); + break; + + case CMD_WKP_MODE: + initWorkMode(WORK_MODE); + break; + + default: + break; + } + } + else + { + if (isDataValid(data, len)) + { + lineTransmitData(data, len); + } + } +} + +/// @brief 透传缆接收数据回调 +/// @param data +/// @param len +void lineRecCallback(uint8_t *data, uint8_t len) +{ + if (len == 1) + { + switch (data[0]) + { + case CMD_REC_MODE: + lineTransmitData(CMD_ACK_OK, 1); + tarDevMode = R_MODE; + break; + + case CMD_TRA_MODE: // 对端请求切换为发送模式 + if (curMode == R_MODE) + { + lineTransmitData(CMD_ACK_OK, 1); + tarDevMode = T_MODE; + } + else + { + lineTransmitData(CMD_ACK_NOK, 1); + } + break; + + default: + lineTransmitData(CMD_ACK_NOK, 1); + break; + } + } + else + { + if (isDataValid(data, len)) + { + userTransmitData(data, len); + } + } +} + +/// @brief +void handleTR() +{ + // 初始化外设 + + uint8_t retryTime = 100; + if (devMode == HOST_MODE) + { + // 间隔0.1s + retryTime = 100; + } + else + { + retryTime = 1000; + } + + // 初始化MultiTimer + multiTimerInstall(getPlatformTicks); + // 定时器始终开启 + multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // Start timer + + while (1) + { + multiTimerYield(); + if (trySwt) + { + trySwt = 0; // clear flag + switchToTraMode(); + multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer + } + } +} + +void main() +{ + handleTR(); +} \ No newline at end of file