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 <stdlib.h>
#include "MultiTimer.h"
#include "lwrb/lwrb.h"
#define CMD_TRA_MODE 0xA1
#define CMD_REC_MODE 0xA2
@ -11,32 +12,48 @@
#define CMD_ACK_OK 0xAB
#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 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; // 重试定时器、超时定时器
#define RING_BUFFER_SIZE (1024 * 3)
#define FRAME_SIZE_MAX (200)
/// @brief 主从模式,主机拥有更高优先级
enum
typedef enum
{
HOST_MODE = 0,
CLIENT_MODE
};
} devmode_t;
/// @brief 工作模式,收、发、休眠、唤醒
enum
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_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电平
void setGpioLevel(int gpio, int level)
@ -46,7 +63,7 @@ void setGpioLevel(int gpio, int level)
/// @brief 初始化工作模式仅设置对应GPIO电平
/// @param cfg
void initWorkMode(int cfg)
void initWorkStatus(devstatus_t cfg)
{
switch (cfg)
{
@ -73,12 +90,20 @@ void initWorkMode(int cfg)
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 通过用户串口发送数据
/// @param data 待发送数据
@ -144,8 +169,8 @@ void retryTimerCallback(MultiTimer *timer, void *userData)
}
/// @brief 计算异或XOR校验
/// @param data
/// @param len
/// @param data 待校验数据
/// @param len 数据长度
/// @return 校验结果
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 len 数据长度
/// @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) // 帧头校验
{
return 1;
return ERR_HEADER;
}
if (data[len - 1] != 0xED) // 帧尾校验
{
return 2;
return ERR_TAIL;
}
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 用户接口接收数据回调
@ -218,10 +252,12 @@ void userRecDataCallback(uint8_t *data, uint8_t len)
}
else
{
if (chkDataValid(data, len))
{
lineTransmitData(data, len);
}
// 需要透传的数据
updateDataQueue(data, len);
// if (chkDataValid(data, len))
// {
// lineTransmitData(data, len);
// }
}
}
@ -258,10 +294,33 @@ void lineRecCallback(uint8_t *data, uint8_t len)
}
else
{
if (chkDataValid(data, len))
if (chkDataValid(data, len) == ERR_OK)
{
lineTransmitData(CMD_ACK_OK, 1);
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
//
lwrb_init(&traBuff, ringBuffer, RING_BUFFER_SIZE);
lwrb_init(&frameLenBuff,frameLen,sizeof(frameLen));
lwrb_set_evt_fn(&traBuff, transmitDataCallback);
while (1)
{
multiTimerYield();
@ -295,6 +360,11 @@ void handleTR()
switchToTraMode();
multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer
}
if (lwrb)
{
/* code */
}
}
}