demo3/tcl.c
2024-12-03 08:33:43 +08:00

304 lines
6.2 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 <stdio.h>
#include <stdlib.h>
#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 计算异或XOR校验
/// @param data
/// @param len
/// @return 校验结果
uint8_t bccCRC(uint8_t *data, uint8_t len)
{
uint8_t crc = 0;
for (int i = 0; i < len; i++)
{
crc ^= data[i];
}
return crc;
}
/// @brief 检查数据有效性
/// @param data
/// @param len
/// @return 0->有效 1->帧头无效 2->帧尾无效 3->校验位无效
int chkDataValid(uint8_t *data, uint8_t len)
{
// 按帧发送数据
// 判断帧的完整性及校验位
if (data[0] != 0x5A || data[1] != 0xA5) // 帧头校验
{
return 1;
}
if (data[len - 1] != 0xED) // 帧尾校验
{
return 2;
}
if (bccCRC(data + 2, len - 4) != data[len - 2]) // 校验位校验
{
return 3;
}
return 0;
}
/// @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 (chkDataValid(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 (chkDataValid(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();
}