demo3/tcl.c
CSSC-WORK\murmur 4fb7ee7edb 改用链表保存待发数据
完成基本逻辑
2024-12-03 08:33:43 +08:00

391 lines
9.5 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"
#include "lwrb/lwrb.h"
#include "linkedlist.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 USING_ACK 1
#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) // 客户端重试时间间隔
#define MAX_RETRY_CNT 3
#define RING_BUFFER_SIZE (1024 * 3)
#define FRAME_SIZE_MAX (200)
/// @brief 主从模式,主机拥有更高优先级
typedef enum
{
HOST_MODE = 0,
CLIENT_MODE
} devmode_t;
/// @brief 工作模式,收、发、休眠、唤醒
typedef enum
{
T_MODE = 0,
R_MODE,
SLEEP_MODE,
WORK_MODE
} devstatus_t;
typedef enum
{
ERR_OK = 0,
ERR_HEADER,
ERR_TAIL,
ERR_CRC,
ERR_TIMEOUT,
ERR_UNKNOWN,
ERR_NOK
} 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; // 重试定时器、超时定时器
static int rxNewDataFlag = 0;
static uint8_t lstLineRxData[FRAME_SIZE_MAX]; // 透传缆最后一个接收到的数据
static uint8_t lstLineRxDataLen = 0; // 透传缆最后一个接收到的数据长度
static int isTimeOut = 0;
static Node *userRxBuffList = NULL; // user端接收缓冲链表
// static err_t lstState = ERR_OK;
// 设置GPIO电平
void setGpioLevel(int gpio, int level)
{
// 设置GPIO电平
}
/// @brief 初始化工作模式仅设置对应GPIO电平
/// @param cfg
void initWorkStatus(devstatus_t 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)
{
// 发送数据前后需初始化为发送模式
initWorkStatus(T_MODE);
// 发送数据
// 发送完毕后需恢复为接收模式
msdelay(len * 10);
initWorkStatus(R_MODE);
}
// 透传缆发送逻辑
// 0. 用户串口接收待发送数据,放入缓存链表队列。
// 1. 通过透传缆串口发送数据
// 2. 发送完成后切换为接收模式
// 3. 通过透传缆串口接收回复的ACK
// 4. ACK正常则发送成功否则发送失败
// 5. 发送成功则准备发送缓存队列中下一帧数据
// 6. 发送失败则等待指定时间t后重发当前帧
/// @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());
}
void timeOutTimerCallback(MultiTimer *timer, void *userData)
{
isTimeOut = 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->校验位无效
err_t chkDataValid(uint8_t *data, uint8_t len)
{
// 按帧发送数据
// 判断帧的完整性及校验位
if (data[0] != 0x5A || data[1] != 0xA5) // 帧头校验
{
return ERR_HEADER;
}
if (data[len - 1] != 0xED) // 帧尾校验
{
return ERR_TAIL;
}
if (bccCRC(data + 2, len - 4) != data[len - 2]) // 校验位校验
{
return ERR_CRC;
}
return ERR_OK;
}
/// @brief 用户接口接收数据回调
/// @param data
/// @param len
void userRecDataCallback(uint8_t *data, uint8_t len)
{
if (chkDataValid(data, len))
{
appendNode(&userRxBuffList, data, len);
}
else
{
userTransmitData(CMD_ACK_NOK, 1);
}
}
/// @brief 透传缆接收数据回调
/// @param data
/// @param len
void lineRecCallback(uint8_t *data, uint8_t len)
{
rxNewDataFlag = 1;
memcpy(lstLineRxData, data, len);
lstLineRxDataLen = len;
}
/// @brief 阻塞方式接收ACK数据
/// @param timeOut 指定超时时间单位ms
/// @return 返回ACK状态
err_t getACK(int timeOut)
{
rxNewDataFlag = 0;
multiTimerStop(&timeoutTimer);
multiTimerStart(&timeoutTimer, timeOut, timeOutTimerCallback, NULL); // Start timer
while (1)
{
if (isTimeOut)
{
return ERR_NOK;
}
if (rxNewDataFlag)
{
rxNewDataFlag = 0;
if (lstLineRxDataLen == 1 && lstLineRxData[0] == CMD_ACK_OK)
{
return ERR_OK;
}
else
{
return ERR_NOK;
}
}
else
{
continue;
}
}
}
/// @brief
void handleTR()
{
// 初始化外设
uint16_t time2Retry = 0;
if (devMode == HOST_MODE)
{
// 间隔1s
time2Retry = 1000;
}
else
{
time2Retry = 1000 * 10;
}
// 初始化MultiTimer
multiTimerInstall(getPlatformTicks);
while (1)
{
multiTimerYield();
// 收到新数据
if (rxNewDataFlag)
{
if (lstLineRxDataLen == 1)
{
/* code */
}
else
{
if (chkDataValid(lstLineRxData, lstLineRxDataLen) == ERR_OK)
{
lineTransmitData(CMD_ACK_OK, 1);
userTransmitData(lstLineRxData, lstLineRxDataLen);
}
else
{
lineTransmitData(CMD_ACK_NOK, 1);
}
}
}
// 有数据需要发送
if (getListSize(userRxBuffList) > 0)
{
// 发送数据
uint8_t reTryCnt = 0;
err_t lstState = ERR_OK;
while (userRxBuffList != NULL) // 遍历链表
{
if (lstState != ERR_OK)
{
if (!isTimeOut)
{
// 跳过后续代码进入下次循环
continue;
}
else
{
isTimeOut = 0;
}
}
lineTransmitData(userRxBuffList->data, userRxBuffList->size);
if (USING_ACK == 1) // 使用ACK
{
if (getACK(userRxBuffList->size * 10) == ERR_OK) // ACK正常
{
lstState = ERR_OK;
userRxBuffList = userRxBuffList->next; // 正常则移动指针
deleteFirstNode(&userRxBuffList);
userTransmitData(CMD_ACK_OK, 1);
}
else
{
lstState = ERR_NOK;
reTryCnt++;
if (reTryCnt > MAX_RETRY_CNT)
{
reTryCnt = 0;
lstState = ERR_OK;
userRxBuffList = userRxBuffList->next; // 正常则移动指针
deleteFirstNode(&userRxBuffList);
userTransmitData(CMD_ACK_NOK, 1);
break;
}
multiTimerStop(&timeoutTimer);
multiTimerStart(&timeoutTimer, time2Retry, timeOutTimerCallback, NULL); // Start timer
}
}
else // 无ACK
{
lstState = ERR_OK;
userRxBuffList = userRxBuffList->next; // 移动指针
deleteFirstNode(&userRxBuffList);
}
}
}
}
}
void main()
{
handleTR();
}