294 lines
6.0 KiB
C
294 lines
6.0 KiB
C
|
// 透传缆
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include "MultiTimer.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 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; // 重试定时器、超时定时器
|
|||
|
|
|||
|
/// @brief 主从模式,主机拥有更高优先级
|
|||
|
enum
|
|||
|
{
|
|||
|
HOST_MODE = 0,
|
|||
|
CLIENT_MODE
|
|||
|
};
|
|||
|
|
|||
|
/// @brief 工作模式,收、发、休眠、唤醒
|
|||
|
enum
|
|||
|
{
|
|||
|
T_MODE = 0,
|
|||
|
R_MODE,
|
|||
|
SLEEP_MODE,
|
|||
|
WORK_MODE
|
|||
|
};
|
|||
|
|
|||
|
// 设置GPIO电平
|
|||
|
void setGpioLevel(int gpio, int level)
|
|||
|
{
|
|||
|
// 设置GPIO电平
|
|||
|
}
|
|||
|
|
|||
|
/// @brief 初始化工作模式,仅设置对应GPIO电平
|
|||
|
/// @param cfg
|
|||
|
void initWorkMode(int 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)
|
|||
|
{
|
|||
|
// 发送数据前后需初始化为发送模式
|
|||
|
initWorkMode(T_MODE);
|
|||
|
// 发送数据
|
|||
|
|
|||
|
// 发送完毕后需恢复为接收模式
|
|||
|
initWorkMode(R_MODE);
|
|||
|
}
|
|||
|
|
|||
|
/// @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());
|
|||
|
}
|
|||
|
|
|||
|
/// @brief
|
|||
|
/// @param data
|
|||
|
/// @param len
|
|||
|
/// @return 0->校验失败 1->校验成功
|
|||
|
int crc(uint8_t *data, uint8_t len)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/// @brief 检查数据有效性
|
|||
|
/// @param data
|
|||
|
/// @param len
|
|||
|
/// @return 1->有效 0->无效
|
|||
|
int isDataValid(uint8_t *data, uint8_t len)
|
|||
|
{
|
|||
|
// 按帧发送数据
|
|||
|
// 判断帧的完整性及校验位
|
|||
|
if (data[0] != 0x5A || data[1] != 0xA5 || data[len - 1] != 0xED) // 帧头、帧尾校验
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
if (crc(data + 2, len - 2) != 0) // 校验位校验
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
/// @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
|
|||
|
{
|
|||
|
if (isDataValid(data, len))
|
|||
|
{
|
|||
|
lineTransmitData(data, len);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// @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
|
|||
|
{
|
|||
|
if (isDataValid(data, len))
|
|||
|
{
|
|||
|
userTransmitData(data, len);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// @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
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
multiTimerYield();
|
|||
|
if (trySwt)
|
|||
|
{
|
|||
|
trySwt = 0; // clear flag
|
|||
|
switchToTraMode();
|
|||
|
multiTimerStart(&retryTimer, retryTime, retryTimerCallback, NULL); // always restart timer
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void main()
|
|||
|
{
|
|||
|
handleTR();
|
|||
|
}
|