demo3/tcl.c

374 lines
8.2 KiB
C
Raw Normal View History

2024-09-12 08:18:07 +00:00
// 透传缆
#include <stdio.h>
#include <stdlib.h>
#include "MultiTimer.h"
2024-09-29 01:45:34 +00:00
#include "lwrb/lwrb.h"
2024-09-12 08:18:07 +00:00
#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
2024-09-29 01:45:34 +00:00
#define MIN_TR_PERIOD_MS (1000 * 5) // 单字节最小传输时间
2024-09-12 08:18:07 +00:00
#define HOST_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000) // 主机重试时间间隔
#define CLIENT_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000 * 10) // 客户端重试时间间隔
2024-09-29 01:45:34 +00:00
#define RING_BUFFER_SIZE (1024 * 3)
#define FRAME_SIZE_MAX (200)
2024-09-12 08:18:07 +00:00
/// @brief 主从模式,主机拥有更高优先级
2024-09-29 01:45:34 +00:00
typedef enum
2024-09-12 08:18:07 +00:00
{
HOST_MODE = 0,
CLIENT_MODE
2024-09-29 01:45:34 +00:00
} devmode_t;
2024-09-12 08:18:07 +00:00
/// @brief 工作模式,收、发、休眠、唤醒
2024-09-29 01:45:34 +00:00
typedef enum
2024-09-12 08:18:07 +00:00
{
T_MODE = 0,
R_MODE,
SLEEP_MODE,
WORK_MODE
2024-09-29 01:45:34 +00:00
} devstatus_t;
typedef enum
{
ERR_OK = 0,
ERR_HEADER,
ERR_TAIL,
ERR_CRC
} err_t;
static devmode_t devMode = HOST_MODE;
static devstatus_t curMode = R_MODE;
static devstatus_t tarMode = R_MODE;
volatile int trySwt = 0; // 是否尝试切换到发送模式
static devstatus_t tarDevMode = R_MODE; // 目标端工作模式
static MultiTimer retryTimer, timeoutTimer; // 重试定时器、超时定时器
lwrb_t traBuff,frameLenBuff;// 环形缓冲区
uint8_t ringBuffer[RING_BUFFER_SIZE];
uint8_t buffer[FRAME_SIZE_MAX];// 单次待发数据缓冲区
uint8_t frameLen[15];//缓存区数据帧对应长度
2024-09-12 08:18:07 +00:00
// 设置GPIO电平
void setGpioLevel(int gpio, int level)
{
// 设置GPIO电平
}
/// @brief 初始化工作模式仅设置对应GPIO电平
/// @param cfg
2024-09-29 01:45:34 +00:00
void initWorkStatus(devstatus_t cfg)
2024-09-12 08:18:07 +00:00
{
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)
{
// 发送数据前后需初始化为发送模式
2024-09-29 01:45:34 +00:00
initWorkStatus(T_MODE);
2024-09-12 08:18:07 +00:00
// 发送数据
// 发送完毕后需恢复为接收模式
2024-09-29 01:45:34 +00:00
initWorkStatus(R_MODE);
2024-09-12 08:18:07 +00:00
}
2024-09-29 01:45:34 +00:00
// 透传缆发送逻辑
// 0. 用户串口接收待发送数据,放入缓存队列。帧长度对应保存。
// 1. 通过透传缆串口发送数据
// 2. 发送完成后切换为接收模式
// 3. 通过透传缆串口接收回复的ACK
// 4. ACK正常则发送成功否则发送失败
// 5. 发送成功则准备发送缓存队列中下一帧数据
// 6. 发送失败则重发当前帧
2024-09-12 08:18:07 +00:00
/// @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());
}
2024-09-12 08:44:24 +00:00
/// @brief 计算异或XOR校验
2024-09-29 01:45:34 +00:00
/// @param data 待校验数据
/// @param len 数据长度
2024-09-12 08:44:24 +00:00
/// @return 校验结果
uint8_t bccCRC(uint8_t *data, uint8_t len)
2024-09-12 08:18:07 +00:00
{
2024-09-12 08:44:24 +00:00
uint8_t crc = 0;
for (int i = 0; i < len; i++)
{
crc ^= data[i];
}
return crc;
2024-09-12 08:18:07 +00:00
}
/// @brief 检查数据有效性
2024-09-12 08:48:51 +00:00
/// @param data 待校验数据
/// @param len 数据长度
2024-09-12 08:44:24 +00:00
/// @return 0->有效 1->帧头无效 2->帧尾无效 3->校验位无效
2024-09-29 01:45:34 +00:00
err_t chkDataValid(uint8_t *data, uint8_t len)
2024-09-12 08:18:07 +00:00
{
// 按帧发送数据
// 判断帧的完整性及校验位
2024-09-12 08:44:24 +00:00
if (data[0] != 0x5A || data[1] != 0xA5) // 帧头校验
2024-09-12 08:18:07 +00:00
{
2024-09-29 01:45:34 +00:00
return ERR_HEADER;
2024-09-12 08:18:07 +00:00
}
2024-09-12 08:44:24 +00:00
if (data[len - 1] != 0xED) // 帧尾校验
2024-09-12 08:18:07 +00:00
{
2024-09-29 01:45:34 +00:00
return ERR_TAIL;
2024-09-12 08:18:07 +00:00
}
2024-09-12 08:44:24 +00:00
if (bccCRC(data + 2, len - 4) != data[len - 2]) // 校验位校验
{
2024-09-29 01:45:34 +00:00
return ERR_CRC;
2024-09-12 08:44:24 +00:00
}
2024-09-29 01:45:34 +00:00
return ERR_OK;
}
// 创建长度为3k的队列
// 更新缓存队列
void updateDataQueue(uint8_t *data, uint8_t len)
{
lwrb_write(&traBuff, data, len);
lwrb_write(&frameLenBuff, len, 1);
2024-09-12 08:18:07 +00:00
}
/// @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
{
2024-09-29 01:45:34 +00:00
// 需要透传的数据
updateDataQueue(data, len);
// if (chkDataValid(data, len))
// {
// lineTransmitData(data, len);
// }
2024-09-12 08:18:07 +00:00
}
}
/// @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
{
2024-09-29 01:45:34 +00:00
if (chkDataValid(data, len) == ERR_OK)
2024-09-12 08:18:07 +00:00
{
2024-09-29 01:45:34 +00:00
lineTransmitData(CMD_ACK_OK, 1);
2024-09-12 08:18:07 +00:00
userTransmitData(data, len);
}
2024-09-29 01:45:34 +00:00
else
{
lineTransmitData(CMD_ACK_NOK, 1);
}
}
}
void transmitDataCallback(lwrb_t *buff, lwrb_evt_type_t type, size_t len)
{
switch (type)
{
case LWRB_EVT_RESET:
printf("[EVT] Buffer reset event!\r\n");
break;
case LWRB_EVT_READ:
printf("[EVT] Buffer read event: %d byte(s)!\r\n", (int)len);
break;
case LWRB_EVT_WRITE:
printf("[EVT] Buffer write event: %d byte(s)!\r\n", (int)len);
break;
default:
break;
2024-09-12 08:18:07 +00:00
}
}
/// @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
2024-09-29 01:45:34 +00:00
//
lwrb_init(&traBuff, ringBuffer, RING_BUFFER_SIZE);
lwrb_init(&frameLenBuff,frameLen,sizeof(frameLen));
lwrb_set_evt_fn(&traBuff, transmitDataCallback);
2024-09-12 08:18:07 +00:00
while (1)
{
multiTimerYield();
if (trySwt)
{
trySwt = 0; // clear flag
switchToTraMode();
multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer
}
2024-09-29 01:45:34 +00:00
if (lwrb)
{
/* code */
}
2024-09-12 08:18:07 +00:00
}
}
void main()
{
handleTR();
}