diff --git a/linkedlist.c b/linkedlist.c new file mode 100644 index 0000000..855795c --- /dev/null +++ b/linkedlist.c @@ -0,0 +1,99 @@ +// linkedlist.c + +#include +#include +#include "linkedlist.h" + +// 创建新节点并为其分配不定长数组 +Node* createNode(int* arr, int size) { + Node* newNode = (Node*)malloc(sizeof(Node)); + if (!newNode) { + printf("内存分配失败\n"); + exit(1); + } + + newNode->data = (int*)malloc(size * sizeof(int)); // 分配数组内存 + if (!newNode->data) { + printf("数组内存分配失败\n"); + free(newNode); // 释放节点内存 + exit(1); + } + + for (int i = 0; i < size; i++) { + newNode->data[i] = arr[i]; + } + + newNode->size = size; + newNode->next = NULL; + return newNode; +} + +// 向链表末尾添加节点 +void appendNode(Node** head, int* arr, int size) { + Node* newNode = createNode(arr, size); + + if (*head == NULL) { + *head = newNode; + return; + } + + Node* temp = *head; + while (temp->next != NULL) { + temp = temp->next; + } + + temp->next = newNode; +} + +// 删除链表的第一个节点 +void deleteFirstNode(Node** head) { + if (*head == NULL) { + printf("链表为空,无法删除第一个节点。\n"); + return; + } + + Node* temp = *head; + *head = (*head)->next; + + free(temp->data); // 释放数组 + free(temp); // 释放节点 + + printf("第一个节点已删除。\n"); +} + +// 打印链表 +void printList(Node* head) { + Node* temp = head; + while (temp != NULL) { + printf("节点数组: "); + for (int i = 0; i < temp->size; i++) { + printf("%d ", temp->data[i]); + } + printf("\n"); + temp = temp->next; + } +} + +// 释放链表占用的内存 +void freeList(Node* head) { + Node* temp; + while (head != NULL) { + temp = head; + head = head->next; + free(temp->data); // 释放节点中的数组 + free(temp); // 释放节点本身 + } +} + +// 获取链表中节点的数量 +int getListSize(Node* head) { + int count = 0; + Node* temp = head; + + while (temp != NULL) { + count++; + temp = temp->next; + } + + return count; +} \ No newline at end of file diff --git a/linkedlist.h b/linkedlist.h new file mode 100644 index 0000000..1715805 --- /dev/null +++ b/linkedlist.h @@ -0,0 +1,20 @@ +// linkedlist.h + +#ifndef LINKEDLIST_H +#define LINKEDLIST_H + +// 定义链表节点的结构体,并使用 typedef 进行简化 +typedef struct Node { + int* data; // 指向不定长数组的指针 + int size; // 数组的大小 + struct Node* next; // 指向下一个节点的指针 +} Node; + +// 函数声明 +Node* createNode(int* arr, int size); // 创建新节点 +void appendNode(Node** head, int* arr, int size); // 添加节点到链表末尾 +void deleteFirstNode(Node** head); // 删除链表的第一个节点 +void printList(Node* head); // 打印链表 +void freeList(Node* head); // 释放链表内存 +int getListSize(Node* head); // 获取链表中的节点数量 +#endif // LINKEDLIST_H diff --git a/tcl.c b/tcl.c index d78536b..76fe0a5 100644 --- a/tcl.c +++ b/tcl.c @@ -4,6 +4,7 @@ #include #include "MultiTimer.h" #include "lwrb/lwrb.h" +#include "linkedlist.h" #define CMD_TRA_MODE 0xA1 #define CMD_REC_MODE 0xA2 @@ -12,10 +13,12 @@ #define CMD_ACK_OK 0xAB #define CMD_ACK_NOK 0xAF -#define MIN_TR_PERIOD_MS (1000 * 5) // 单字节最小传输时间 +#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) @@ -40,7 +43,10 @@ typedef enum ERR_OK = 0, ERR_HEADER, ERR_TAIL, - ERR_CRC + ERR_CRC, + ERR_TIMEOUT, + ERR_UNKNOWN, + ERR_NOK } err_t; static devmode_t devMode = HOST_MODE; @@ -49,11 +55,12 @@ 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];//缓存区数据帧对应长度 - +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) @@ -94,16 +101,17 @@ void lineTransmitData(uint8_t *data, uint8_t len) // 发送数据 // 发送完毕后需恢复为接收模式 + msdelay(len * 10); initWorkStatus(R_MODE); } // 透传缆发送逻辑 -// 0. 用户串口接收待发送数据,放入缓存队列。帧长度对应保存。 +// 0. 用户串口接收待发送数据,放入缓存链表队列。 // 1. 通过透传缆串口发送数据 // 2. 发送完成后切换为接收模式 // 3. 通过透传缆串口接收回复的ACK // 4. ACK正常则发送成功,否则发送失败 // 5. 发送成功则准备发送缓存队列中下一帧数据 -// 6. 发送失败则重发当前帧 +// 6. 发送失败则等待指定时间t后重发当前帧 /// @brief 通过用户串口发送数据 /// @param data 待发送数据 @@ -168,6 +176,13 @@ void retryTimerCallback(MultiTimer *timer, void *userData) 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 数据长度 @@ -208,56 +223,18 @@ err_t chkDataValid(uint8_t *data, uint8_t len) return ERR_OK; } -// 创建长度为3k的队列 - -// 更新缓存队列 -void updateDataQueue(uint8_t *data, uint8_t len) -{ - lwrb_write(&traBuff, data, len); - lwrb_write(&frameLenBuff, len, 1); -} - /// @brief 用户接口接收数据回调 /// @param data /// @param len void userRecDataCallback(uint8_t *data, uint8_t len) { - if (len == 1) + if (chkDataValid(data, len)) { - 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; - } + appendNode(&userRxBuffList, data, len); } else { - // 需要透传的数据 - updateDataQueue(data, len); - // if (chkDataValid(data, len)) - // { - // lineTransmitData(data, len); - // } + userTransmitData(CMD_ACK_NOK, 1); } } @@ -266,105 +243,145 @@ void userRecDataCallback(uint8_t *data, uint8_t len) /// @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; + rxNewDataFlag = 1; + memcpy(lstLineRxData, data, len); + lstLineRxDataLen = len; +} - case CMD_TRA_MODE: // 对端请求切换为发送模式 - if (curMode == R_MODE) +/// @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) { - lineTransmitData(CMD_ACK_OK, 1); - tarDevMode = T_MODE; + return ERR_OK; } else { - lineTransmitData(CMD_ACK_NOK, 1); + return ERR_NOK; } - break; - - default: - lineTransmitData(CMD_ACK_NOK, 1); - break; - } - } - else - { - if (chkDataValid(data, len) == ERR_OK) - { - lineTransmitData(CMD_ACK_OK, 1); - userTransmitData(data, len); } else { - lineTransmitData(CMD_ACK_NOK, 1); + continue; } } } -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; - } -} - /// @brief void handleTR() { // 初始化外设 - uint8_t retryTime = 100; + uint16_t time2Retry = 0; if (devMode == HOST_MODE) { - // 间隔0.1s - retryTime = 100; + // 间隔1s + time2Retry = 1000; } else { - retryTime = 1000; + time2Retry = 1000 * 10; } // 初始化MultiTimer multiTimerInstall(getPlatformTicks); - // 定时器始终开启 - multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // Start timer - - // - - lwrb_init(&traBuff, ringBuffer, RING_BUFFER_SIZE); - lwrb_init(&frameLenBuff,frameLen,sizeof(frameLen)); - lwrb_set_evt_fn(&traBuff, transmitDataCallback); while (1) { multiTimerYield(); - if (trySwt) + + // 收到新数据 + if (rxNewDataFlag) { - trySwt = 0; // clear flag - switchToTraMode(); - multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer + 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 (lwrb) + + // 有数据需要发送 + if (getListSize(userRxBuffList) > 0) { - /* code */ + // 发送数据 + 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); + } + } } - } }