This commit is contained in:
CSSC-WORK\murmur 2024-09-29 09:45:34 +08:00
parent d1b240abd0
commit 05752eae3b
3 changed files with 245 additions and 26 deletions

66
MultiTimer.c Normal file
View File

@ -0,0 +1,66 @@
#include "MultiTimer.h"
#include <stdio.h>
static MultiTimer* timerList = NULL;
static PlatformTicksFunction_t platformTicksFunction = NULL;
int multiTimerInstall(PlatformTicksFunction_t ticksFunc) {
if (ticksFunc == NULL) {
return -1; // Indicate error if ticksFunc is NULL
}
platformTicksFunction = ticksFunc;
return 0;
}
static void removeTimer(MultiTimer* timer) {
MultiTimer** current = &timerList;
while (*current) {
if (*current == timer) {
*current = timer->next;
break;
}
current = &(*current)->next;
}
}
int multiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData) {
if (!timer || !callback || platformTicksFunction == NULL) {
return -1; // Return error if any parameter is invalid
}
removeTimer(timer); // Centralize removal logic
timer->deadline = platformTicksFunction() + timing;
timer->callback = callback;
timer->userData = userData;
MultiTimer** current = &timerList;
while (*current && ((*current)->deadline < timer->deadline)) {
current = &(*current)->next;
}
timer->next = *current;
*current = timer;
return 0;
}
int multiTimerStop(MultiTimer* timer) {
removeTimer(timer); // Use centralized removal function
return 0;
}
int multiTimerYield(void) {
if (platformTicksFunction == NULL) {
return -1; // Indicate error if platformTicksFunction is NULL
}
uint64_t currentTicks = platformTicksFunction();
while (timerList && (currentTicks >= timerList->deadline)) {
MultiTimer* timer = timerList;
timerList = timer->next; // Remove expired timer
if (timer->callback) {
timer->callback(timer, timer->userData); // Execute callback
}
}
return timerList ? (int)(timerList->deadline - currentTicks) : 0;
}

83
MultiTimer.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 0x1abin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t (*PlatformTicksFunction_t)(void);
typedef struct MultiTimerHandle MultiTimer;
typedef void (*MultiTimerCallback_t)(MultiTimer* timer, void* userData);
struct MultiTimerHandle {
MultiTimer* next;
uint64_t deadline;
MultiTimerCallback_t callback;
void* userData;
};
/**
* @brief Platform ticks function.
*
* @param ticksFunc ticks function.
* @return int 0 on success, -1 on error.
*/
int multiTimerInstall(PlatformTicksFunction_t ticksFunc);
/**
* @brief Start the timer work, add the handle into work list.
*
* @param timer target handle strcut.
* @param timing Set the start time.
* @param callback deadline callback.
* @param userData user data.
* @return int 0: success, -1: fail.
*/
int multiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData);
/**
* @brief Stop the timer work, remove the handle off work list.
*
* @param timer target handle strcut.
* @return int 0: success, -1: fail.
*/
int multiTimerStop(MultiTimer* timer);
/**
* @brief Check the timer expried and call callback.
*
* @return int The next timer expires.
*/
int multiTimerYield(void);
#ifdef __cplusplus
}
#endif
#endif

122
tcl.c
View File

@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "MultiTimer.h" #include "MultiTimer.h"
#include "lwrb/lwrb.h"
#define CMD_TRA_MODE 0xA1 #define CMD_TRA_MODE 0xA1
#define CMD_REC_MODE 0xA2 #define CMD_REC_MODE 0xA2
@ -11,32 +12,48 @@
#define CMD_ACK_OK 0xAB #define CMD_ACK_OK 0xAB
#define CMD_ACK_NOK 0xAF #define CMD_ACK_NOK 0xAF
#define MIN_TR_PERIOD_MS 1000 * 5 // 单字节最小传输时间 #define MIN_TR_PERIOD_MS (1000 * 5) // 单字节最小传输时间
#define HOST_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000) // 主机重试时间间隔 #define HOST_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000) // 主机重试时间间隔
#define CLIENT_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000 * 10) // 客户端重试时间间隔 #define CLIENT_RETRY_PERIOD_MS (MIN_TR_PERIOD_MS + 1000 * 10) // 客户端重试时间间隔
static int devMode = HOST_MODE; #define RING_BUFFER_SIZE (1024 * 3)
static int curMode = R_MODE; #define FRAME_SIZE_MAX (200)
static int tarMode = R_MODE;
static int trySwt = 0; // 是否尝试切换到发送模式
static int tarDevMode = R_MODE; // 目标端工作模式
static MultiTimer retryTimer, timeoutTimer; // 重试定时器、超时定时器
/// @brief 主从模式,主机拥有更高优先级 /// @brief 主从模式,主机拥有更高优先级
enum typedef enum
{ {
HOST_MODE = 0, HOST_MODE = 0,
CLIENT_MODE CLIENT_MODE
}; } devmode_t;
/// @brief 工作模式,收、发、休眠、唤醒 /// @brief 工作模式,收、发、休眠、唤醒
enum typedef enum
{ {
T_MODE = 0, T_MODE = 0,
R_MODE, R_MODE,
SLEEP_MODE, SLEEP_MODE,
WORK_MODE WORK_MODE
}; } 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];//缓存区数据帧对应长度
// 设置GPIO电平 // 设置GPIO电平
void setGpioLevel(int gpio, int level) void setGpioLevel(int gpio, int level)
@ -46,7 +63,7 @@ void setGpioLevel(int gpio, int level)
/// @brief 初始化工作模式仅设置对应GPIO电平 /// @brief 初始化工作模式仅设置对应GPIO电平
/// @param cfg /// @param cfg
void initWorkMode(int cfg) void initWorkStatus(devstatus_t cfg)
{ {
switch (cfg) switch (cfg)
{ {
@ -73,12 +90,20 @@ void initWorkMode(int cfg)
void lineTransmitData(uint8_t *data, uint8_t len) void lineTransmitData(uint8_t *data, uint8_t len)
{ {
// 发送数据前后需初始化为发送模式 // 发送数据前后需初始化为发送模式
initWorkMode(T_MODE); initWorkStatus(T_MODE);
// 发送数据 // 发送数据
// 发送完毕后需恢复为接收模式 // 发送完毕后需恢复为接收模式
initWorkMode(R_MODE); initWorkStatus(R_MODE);
} }
// 透传缆发送逻辑
// 0. 用户串口接收待发送数据,放入缓存队列。帧长度对应保存。
// 1. 通过透传缆串口发送数据
// 2. 发送完成后切换为接收模式
// 3. 通过透传缆串口接收回复的ACK
// 4. ACK正常则发送成功否则发送失败
// 5. 发送成功则准备发送缓存队列中下一帧数据
// 6. 发送失败则重发当前帧
/// @brief 通过用户串口发送数据 /// @brief 通过用户串口发送数据
/// @param data 待发送数据 /// @param data 待发送数据
@ -144,8 +169,8 @@ void retryTimerCallback(MultiTimer *timer, void *userData)
} }
/// @brief 计算异或XOR校验 /// @brief 计算异或XOR校验
/// @param data /// @param data 待校验数据
/// @param len /// @param len 数据长度
/// @return 校验结果 /// @return 校验结果
uint8_t bccCRC(uint8_t *data, uint8_t len) uint8_t bccCRC(uint8_t *data, uint8_t len)
{ {
@ -161,26 +186,35 @@ uint8_t bccCRC(uint8_t *data, uint8_t len)
/// @param data 待校验数据 /// @param data 待校验数据
/// @param len 数据长度 /// @param len 数据长度
/// @return 0->有效 1->帧头无效 2->帧尾无效 3->校验位无效 /// @return 0->有效 1->帧头无效 2->帧尾无效 3->校验位无效
int chkDataValid(uint8_t *data, uint8_t len) err_t chkDataValid(uint8_t *data, uint8_t len)
{ {
// 按帧发送数据 // 按帧发送数据
// 判断帧的完整性及校验位 // 判断帧的完整性及校验位
if (data[0] != 0x5A || data[1] != 0xA5) // 帧头校验 if (data[0] != 0x5A || data[1] != 0xA5) // 帧头校验
{ {
return 1; return ERR_HEADER;
} }
if (data[len - 1] != 0xED) // 帧尾校验 if (data[len - 1] != 0xED) // 帧尾校验
{ {
return 2; return ERR_TAIL;
} }
if (bccCRC(data + 2, len - 4) != data[len - 2]) // 校验位校验 if (bccCRC(data + 2, len - 4) != data[len - 2]) // 校验位校验
{ {
return 3; return ERR_CRC;
} }
return 0; return ERR_OK;
}
// 创建长度为3k的队列
// 更新缓存队列
void updateDataQueue(uint8_t *data, uint8_t len)
{
lwrb_write(&traBuff, data, len);
lwrb_write(&frameLenBuff, len, 1);
} }
/// @brief 用户接口接收数据回调 /// @brief 用户接口接收数据回调
@ -218,10 +252,12 @@ void userRecDataCallback(uint8_t *data, uint8_t len)
} }
else else
{ {
if (chkDataValid(data, len)) // 需要透传的数据
{ updateDataQueue(data, len);
lineTransmitData(data, len); // if (chkDataValid(data, len))
} // {
// lineTransmitData(data, len);
// }
} }
} }
@ -258,10 +294,33 @@ void lineRecCallback(uint8_t *data, uint8_t len)
} }
else else
{ {
if (chkDataValid(data, len)) if (chkDataValid(data, len) == ERR_OK)
{ {
lineTransmitData(CMD_ACK_OK, 1);
userTransmitData(data, len); userTransmitData(data, len);
} }
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;
} }
} }
@ -286,6 +345,12 @@ void handleTR()
// 定时器始终开启 // 定时器始终开启
multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // Start timer 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) while (1)
{ {
multiTimerYield(); multiTimerYield();
@ -295,6 +360,11 @@ void handleTR()
switchToTraMode(); switchToTraMode();
multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer
} }
if (lwrb)
{
/* code */
}
} }
} }