Integrate CAN-aware CMS risk pipeline and relocatable Orin runtime
This commit is contained in:
+338
@@ -0,0 +1,338 @@
|
||||
// can_comm.cpp - USBCANFD CAN/CANFD 收发封装实现
|
||||
//
|
||||
// 代码迁移自 vision-anti-pinch_bak/main.cpp 的 CAN 模块部分。
|
||||
|
||||
#include "can_comm.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "zcan.h"
|
||||
|
||||
/* =====================================================================
|
||||
* 类型/宏/全局变量
|
||||
* ===================================================================== */
|
||||
|
||||
typedef uint32_t UINT;
|
||||
typedef uint32_t U32;
|
||||
#define msleep(ms) usleep((ms) * 1000)
|
||||
|
||||
#define USBCANFD 33
|
||||
#define MAX_CHANNELS 2 // 最大通道数量
|
||||
#define RX_WAIT_TIME 100
|
||||
#define RX_BUFF_SIZE 1000
|
||||
|
||||
// 接收线程上下文
|
||||
typedef struct
|
||||
{
|
||||
int dev_type; // 设备类型
|
||||
int dev_idx; // 设备索引
|
||||
int chn_idx; // 通道号
|
||||
int total; // 接收总数
|
||||
int stop; // 线程结束标志
|
||||
} THREAD_CTX;
|
||||
|
||||
/* CAN 运行标志, 由信号处理函数(Ctrl+C)或外部置位 */
|
||||
static volatile bool g_can_running = true;
|
||||
|
||||
static int g_receive_count = 0;
|
||||
|
||||
/* ===== 仅供 can_start/can_stop 共享的文件内静态变量 ===== */
|
||||
static int s_DevType = USBCANFD;
|
||||
static int s_DevIdx = 0;
|
||||
static THREAD_CTX s_rx_ctx[MAX_CHANNELS];
|
||||
static pthread_t s_rx_threads[MAX_CHANNELS];
|
||||
static bool s_can_opened = false;
|
||||
|
||||
namespace CanComm {
|
||||
|
||||
bool is_open() { return s_can_opened; }
|
||||
|
||||
int receive_count() { return g_receive_count; }
|
||||
|
||||
/* ===== 报文解析回调 (由 main.cpp 通过 set_msg_callback 注册) ===== */
|
||||
static MsgCallback s_msg_cb = nullptr;
|
||||
|
||||
void set_msg_callback(MsgCallback cb) { s_msg_cb = cb; }
|
||||
|
||||
} // namespace CanComm
|
||||
|
||||
/* =====================================================================
|
||||
* 帧构建与收发
|
||||
* ===================================================================== */
|
||||
|
||||
namespace CanComm {
|
||||
|
||||
// 构建 CAN 帧
|
||||
static void construct_can_frame(ZCAN_20_MSG *can_msg, UINT id, int chn_idx, int pad)
|
||||
{
|
||||
memset(can_msg, 0, sizeof(ZCAN_20_MSG));
|
||||
can_msg->hdr.inf.txm = 0; // 0-正常发送
|
||||
can_msg->hdr.inf.fmt = 0; // 0-CAN
|
||||
can_msg->hdr.inf.sdf = 0; // 0-数据帧, 1-远程帧
|
||||
can_msg->hdr.inf.sef = 0; // 0-标准帧, 1-扩展帧
|
||||
|
||||
can_msg->hdr.id = id; // ID
|
||||
can_msg->hdr.chn = chn_idx; // 通道
|
||||
can_msg->hdr.len = 8; // 数据长度
|
||||
|
||||
if (pad > 0)
|
||||
{
|
||||
can_msg->hdr.pad = pad; // 发送后延迟 pad ms
|
||||
can_msg->hdr.inf.qsend = 1; // 队列发送帧,仅判断首帧
|
||||
can_msg->hdr.inf.qsend_100us = 0; // 队列发送单位,0-ms,1-100us
|
||||
}
|
||||
|
||||
for (int i = 0; i < can_msg->hdr.len; i++)
|
||||
can_msg->dat[i] = i;
|
||||
}
|
||||
|
||||
// 构建 CANFD 帧
|
||||
static void construct_canfd_frame(ZCAN_FD_MSG *canfd_msg, UINT id, int chn_idx, int pad)
|
||||
{
|
||||
memset(canfd_msg, 0, sizeof(ZCAN_FD_MSG));
|
||||
canfd_msg->hdr.inf.txm = 0; // 0-正常发送
|
||||
canfd_msg->hdr.inf.fmt = 1; // 0-CAN, 1-CANFD
|
||||
canfd_msg->hdr.inf.sdf = 0; // 0-数据帧 CANFD只有数据帧!
|
||||
canfd_msg->hdr.inf.sef = 1; // 0-标准帧, 1-扩展帧
|
||||
canfd_msg->hdr.inf.brs = 1; // canfd 加速
|
||||
|
||||
canfd_msg->hdr.id = id; // ID
|
||||
canfd_msg->hdr.chn = chn_idx; // 通道
|
||||
canfd_msg->hdr.len = 64; // 数据长度
|
||||
|
||||
if (pad > 0)
|
||||
{
|
||||
canfd_msg->hdr.pad = 100; // 发送后延迟100ms
|
||||
canfd_msg->hdr.inf.qsend = 1; // 队列发送帧,仅判断首帧
|
||||
canfd_msg->hdr.inf.qsend_100us = 0; // 队列发送单位,0-ms,1-100us
|
||||
}
|
||||
|
||||
for (int i = 0; i < canfd_msg->hdr.len; i++)
|
||||
canfd_msg->dat[i] = i;
|
||||
}
|
||||
|
||||
// 分发报文到 main.cpp 注册的解析回调
|
||||
static inline void dispatch_msg(uint32_t ts, uint32_t msg_id, const uint8_t *data, uint32_t len)
|
||||
{
|
||||
if (s_msg_cb)
|
||||
s_msg_cb(ts, msg_id, data, len);
|
||||
}
|
||||
|
||||
// 接收线程
|
||||
static void *rx_thread(void *data)
|
||||
{
|
||||
THREAD_CTX *ctx = (THREAD_CTX *)data;
|
||||
int DevType = ctx->dev_type;
|
||||
int DevIdx = ctx->dev_idx;
|
||||
int chn_idx = ctx->chn_idx;
|
||||
|
||||
ZCAN_20_MSG can_data[RX_BUFF_SIZE];
|
||||
ZCAN_FD_MSG canfd_data[RX_BUFF_SIZE];
|
||||
|
||||
while (!ctx->stop)
|
||||
{
|
||||
memset(can_data, 0, sizeof(can_data));
|
||||
memset(canfd_data, 0, sizeof(canfd_data));
|
||||
|
||||
int rcount = VCI_Receive(DevType, DevIdx, chn_idx, can_data, RX_BUFF_SIZE, RX_WAIT_TIME); // CAN
|
||||
for (int i = 0; i < rcount; ++i)
|
||||
{
|
||||
if (can_data[i].hdr.inf.sdf == 0)
|
||||
{ // 数据帧
|
||||
dispatch_msg(can_data->hdr.ts, can_data[i].hdr.id, can_data[i].dat, can_data[i].hdr.len);
|
||||
}
|
||||
}
|
||||
ctx->total += rcount;
|
||||
|
||||
rcount = VCI_ReceiveFD(DevType, DevIdx, chn_idx, canfd_data, RX_BUFF_SIZE, RX_WAIT_TIME); // CANFD
|
||||
for (int i = 0; i < rcount; ++i)
|
||||
{
|
||||
dispatch_msg(canfd_data->hdr.ts, canfd_data[i].hdr.id, canfd_data[i].dat, canfd_data[i].hdr.len);
|
||||
}
|
||||
ctx->total += rcount;
|
||||
msleep(10);
|
||||
}
|
||||
g_receive_count = ctx->total;
|
||||
printf("chn: %d receive %d\n", chn_idx, ctx->total);
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
// 合并接收线程
|
||||
static void *rx_merge_thread(void *data)
|
||||
{
|
||||
THREAD_CTX *ctx = (THREAD_CTX *)data;
|
||||
int DevType = ctx->dev_type;
|
||||
int DevIdx = ctx->dev_idx;
|
||||
|
||||
ZCANDataObj obj_data[RX_BUFF_SIZE];
|
||||
|
||||
while (!ctx->stop)
|
||||
{
|
||||
memset(obj_data, 0, sizeof(obj_data));
|
||||
int rcount = VCI_ReceiveData(DevType, DevIdx, 0, obj_data, RX_BUFF_SIZE, RX_WAIT_TIME); // 第三个参数固定为0就好
|
||||
for (int i = 0; i < rcount; ++i)
|
||||
{
|
||||
if (obj_data[i].dataType == ZCAN_DT_ZCAN_CAN_DATA)
|
||||
{ // CAN
|
||||
ZCAN_20_MSG *can_data = &obj_data[i].data.zcanCANData;
|
||||
if (can_data->hdr.inf.sdf == 0)
|
||||
{ // 数据帧
|
||||
dispatch_msg(can_data->hdr.ts, can_data->hdr.id, can_data->dat, can_data->hdr.len);
|
||||
}
|
||||
}
|
||||
else if (obj_data[i].dataType == ZCAN_DT_ZCAN_CANFD_DATA)
|
||||
{ // CANFD
|
||||
ZCAN_FD_MSG *canfd_data = &obj_data[i].data.zcanCANFDData;
|
||||
dispatch_msg(canfd_data->hdr.ts, canfd_data->hdr.id, canfd_data->dat, canfd_data->hdr.len);
|
||||
}
|
||||
}
|
||||
ctx->total += rcount;
|
||||
msleep(10);
|
||||
}
|
||||
g_receive_count = ctx->total;
|
||||
printf("merge receive %d\n", ctx->total);
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 初始化并启动 CAN 收发。
|
||||
* 返回 true 成功; false 失败(主流程可继续仅取图)。
|
||||
*/
|
||||
bool can_start()
|
||||
{
|
||||
g_can_running = true;
|
||||
int IsMerge = 1; // 是否合并接收
|
||||
|
||||
// 打开设备
|
||||
if (!VCI_OpenDevice(s_DevType, s_DevIdx, 0))
|
||||
{
|
||||
printf("Open device fail\n");
|
||||
return false;
|
||||
}
|
||||
s_can_opened = true;
|
||||
printf("Open device success\n");
|
||||
|
||||
// 初始化,启动通道
|
||||
for (int i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
ZCAN_INIT init; // 波特率结构体,数据根据zcanpro的波特率计算器得出
|
||||
init.clk = 60000000; // clock: 60M(V1.01) 80M(V1.03即以上)
|
||||
init.mode = 0; // 0-正常
|
||||
|
||||
init.aset.tseg1 = 14; // 仲裁域 500kbps
|
||||
init.aset.tseg2 = 3;
|
||||
init.aset.sjw = 2;
|
||||
init.aset.smp = 0;
|
||||
init.aset.brp = 5;
|
||||
|
||||
init.dset.tseg1 = 10; // 数据域 2000kbps
|
||||
init.dset.tseg2 = 2;
|
||||
init.dset.sjw = 2;
|
||||
init.dset.smp = 0;
|
||||
init.dset.brp = 1;
|
||||
|
||||
if (!VCI_InitCAN(s_DevType, s_DevIdx, i, &init)) // 初始化通道
|
||||
{
|
||||
printf("InitCAN(%d) fail\n", i);
|
||||
return false;
|
||||
}
|
||||
printf("InitCAN(%d) success\n", i);
|
||||
|
||||
U32 on = 1;
|
||||
if (!VCI_SetReference(s_DevType, s_DevIdx, i, CMD_CAN_TRES, &on)) // 终端电阻
|
||||
{
|
||||
printf("CMD_CAN_TRES fail\n");
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (!VCI_SetReference(s_DevType, s_DevIdx, i, ZCAN_CMD_SET_CHNL_RECV_MERGE, &IsMerge)) // 合并接收
|
||||
{
|
||||
printf("ZCAN_CMD_SET_CHNL_RECV_MERGE fail\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!VCI_StartCAN(s_DevType, s_DevIdx, i)) // 启动通道
|
||||
{
|
||||
printf("StartCAN(%d) fail\n", i);
|
||||
return false;
|
||||
}
|
||||
printf("StartCAN(%d) success\n", i);
|
||||
|
||||
s_rx_ctx[i].dev_type = s_DevType;
|
||||
s_rx_ctx[i].dev_idx = s_DevIdx;
|
||||
s_rx_ctx[i].chn_idx = i;
|
||||
s_rx_ctx[i].total = 0;
|
||||
s_rx_ctx[i].stop = 0;
|
||||
|
||||
if (IsMerge && i == 0)
|
||||
{
|
||||
pthread_create(&s_rx_threads[i], NULL, rx_merge_thread, &s_rx_ctx[i]); // 合并接收线程
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_create(&s_rx_threads[i], NULL, rx_thread, &s_rx_ctx[i]); // 创建接收线程
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 停止 CAN 接收并关闭设备。
|
||||
*/
|
||||
void can_stop()
|
||||
{
|
||||
if (!s_can_opened)
|
||||
return;
|
||||
|
||||
g_can_running = false;
|
||||
|
||||
for (int i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
s_rx_ctx[i].stop = 1;
|
||||
pthread_join(s_rx_threads[i], NULL); // 等待接收线程退出
|
||||
|
||||
if (!VCI_ResetCAN(s_DevType, s_DevIdx, i)) // 复位通道
|
||||
printf("ResetCAN(%d) fail\n", i);
|
||||
else
|
||||
printf("ResetCAN(%d) success!\n", i);
|
||||
}
|
||||
|
||||
if (!VCI_CloseDevice(s_DevType, s_DevIdx))
|
||||
printf("CloseDevice fail\n");
|
||||
else
|
||||
printf("CloseDevice success\n");
|
||||
|
||||
s_can_opened = false;
|
||||
}
|
||||
|
||||
uint32_t can_send(int chn_idx, uint32_t id, const uint8_t data[8])
|
||||
{
|
||||
if (!s_can_opened)
|
||||
return 0;
|
||||
|
||||
ZCAN_20_MSG msg;
|
||||
construct_can_frame(&msg, id, chn_idx, 0);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
msg.dat[i] = data[i];
|
||||
|
||||
return VCI_Transmit(s_DevType, s_DevIdx, chn_idx, &msg, 1);
|
||||
}
|
||||
|
||||
uint32_t canfd_send(int chn_idx, uint32_t id, const uint8_t data[64])
|
||||
{
|
||||
if (!s_can_opened)
|
||||
return 0;
|
||||
|
||||
ZCAN_FD_MSG msg;
|
||||
construct_canfd_frame(&msg, id, chn_idx, 0);
|
||||
for (int i = 0; i < 64; ++i)
|
||||
msg.dat[i] = data[i];
|
||||
|
||||
return VCI_TransmitFD(s_DevType, s_DevIdx, chn_idx, &msg, 1);
|
||||
}
|
||||
|
||||
} // namespace CanComm
|
||||
Reference in New Issue
Block a user