src.dualinventive.com/dinet/sec-multi-proxy/libdi/tests/fixtures/CANTest.hpp

266 lines
6.7 KiB
C++

#include <functional>
#include <di/can.h>
#include <di/can/cfg.h>
#include <di/time.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <gtest/gtest.h>
#define DI_CAN_CFG_FRAME_SIZE 32U
#define DI_CAN_CFG_MSG_SIZE 16U
#define DI_CAN_CFG_MSG_DATA_SIZE 4096U
static std::function<di_errno_t(struct di_can_frame_rx *)> CANTestRecvCb;
static std::function<di_errno_t(const struct di_can_frame_tx *)> CANTestSendCb;
static di_errno_t CANTestSendCallback(const struct di_can_frame_tx *frame) {
if (CANTestSendCb)
return CANTestSendCb(frame);
return DNE_OPNOTSUPP;
}
static di_errno_t CANTestRecvCallback(struct di_can_frame_rx *frame) {
if (CANTestRecvCb)
return CANTestRecvCb(frame);
return DNE_OPNOTSUPP;
}
class DI_CAN : public ::testing::Test {
public:
void SetNodeid(uint32_t nodeid) {
_ctx.nodeid = nodeid;
_ctx.net.self.nodeid = nodeid;
}
void EnableLoopbackSend(bool enable) {
_loopback_enabled = enable;
}
void EnableSocketCANSend(bool enable) {
__socketcan_enabled = enable;
if (__socketcan_fd)
__SocketCAN_Close();
__socketcan_fd = __SocketCAN_Open();
}
void PrintMsg(const struct di_can_msg *msg) {
printf("=== di_can_msg %p ===\n", msg);
printf(" - canid: 0x%08x\n", msg->canid);
printf(" - src_id: 0x%08x\n", msg->src_id);
printf(" - dst_id: 0x%08x\n", msg->dst_id);
printf(" - transaction: %u\n", DI_CAN_GET_TRANSACTION(msg->canid));
printf(" - type: ");
switch (DI_CAN_GET_MSGTYPE(msg->canid)) {
case DI_CAN_MSGTYPE_RAW:
printf("raw\n");
break;
case DI_CAN_MSGTYPE_RPC:
printf("rpc\n");
break;
case DI_CAN_MSGTYPE_NET:
printf("net\n");
break;
case DI_CAN_MSGTYPE_LOG:
printf("log\n");
break;
default:
printf("unknown\n");
break;
}
printf(" - size: %zu\n", msg->size);
}
// Get the current message timeout
di_time_t getCurrentMsgTimeout(void) {
return di_time_get_uptime() + _ctx.msg.timeout;
}
void PrintNetNodes(void) {
printf("=== CANTest Network Nodes ===\n");
printf("self 0x%08x type: %d, role: %d\n", _ctx.net.self.nodeid, _ctx.net.self.type, _ctx.net.self.role);
for (size_t n = 0; n < DI_ARRAY_SIZE(_ctx.net.nodes.list); n++) {
printf("node[%zu] 0x%08x type: 0x%02x, role: 0x%02x\n",
n,
_ctx.net.nodes.list[n].nodeid,
_ctx.net.nodes.list[n].type,
_ctx.net.nodes.list[n].role);
}
}
protected:
virtual void SetUp() {
di_can_init(&_ctx);
_frame_rx_pool = new di_can_frame_rx[DI_CAN_CFG_FRAME_SIZE];
_msg_buffer_data = new uint8_t[DI_CAN_CFG_MSG_SIZE * DI_CAN_CFG_MSG_DATA_SIZE];
_msg_buffer_pool = new di_buffer[DI_CAN_CFG_MSG_SIZE];
_msg_pool = new di_can_msg[DI_CAN_CFG_MSG_SIZE];
di_can_frame_init(&_ctx, _frame_rx_pool, DI_CAN_CFG_FRAME_SIZE);
di_buffer_init_array(_msg_buffer_pool, _msg_buffer_data, DI_CAN_CFG_MSG_SIZE, DI_CAN_CFG_MSG_DATA_SIZE);
di_can_msg_init_array(&_ctx, _msg_pool, DI_CAN_CFG_MSG_SIZE, _msg_buffer_pool, DI_CAN_CFG_MSG_SIZE);
di_can_msg_init(&_ctx, _msg_pool, DI_CAN_CFG_MSG_SIZE);
di_can_net_init(&_ctx);
di_can_msg_recv_set_blocking(&_ctx, false);
di_can_msg_recv_set_timeout(&_ctx, 0);
di_can_callback_set_send(&_ctx, CANTestSendCallback);
CANTestSendCb = std::bind(&DI_CAN::__CanSend, this, std::placeholders::_1);
di_can_callback_set_recv(&_ctx, CANTestRecvCallback);
CANTestRecvCb = std::bind(&DI_CAN::__CanRecv, this, std::placeholders::_1);
_loopback_enabled = true;
__socketcan_enabled = false;
__socketcan_fd = -1;
EnableSocketCANSend(true);
SetNodeid(0xb034b065);
}
virtual void TearDown() {
delete[] _frame_rx_pool;
delete[] _msg_buffer_data;
delete[] _msg_buffer_pool;
delete[] _msg_pool;
if (__socketcan_enabled)
__SocketCAN_Close();
}
private:
di_errno_t __CanSend(const struct di_can_frame_tx *frame) {
__CanSendDump(frame);
if (_loopback_enabled)
__CanSendLoopback(frame);
if (__socketcan_enabled)
__SocketCAN_Send(frame);
return DNOK;
}
di_errno_t __CanRecv(struct di_can_frame_rx *frame) {
(void)frame;
return DNOK;
}
di_errno_t __CanSendLoopback(const struct di_can_frame_tx *frame) {
struct di_can_ctx *ctx = (struct di_can_ctx *)frame->ctx;
struct di_can_frame_rx *rx = di_can_frame_get_unused(ctx);
if (!rx)
return DNE_NOMEM;
rx->canid = frame->canid;
rx->size = frame->size;
memcpy(rx->buf, frame->buf, rx->size);
di_can_frame_return_ready(rx);
di_can_reassemble(ctx);
return DNOK;
}
void __CanSendDump(const struct di_can_frame_tx *frame) {
printf("[can tx][%08x] ", frame->canid);
for (size_t n = 0; n < frame->size; n++)
printf("%02x ", ((uint8_t *)frame->buf)[n]);
for (size_t n = 0; n < (8 - frame->size); n++)
printf(" ");
printf("| ");
for (size_t n = 0; n < frame->size; n++)
printf("%c", isprint((int)frame->buf[n]) ? frame->buf[n] : '.');
for (size_t n = 0; n < (8 - frame->size); n++)
printf(" ");
printf("\n");
}
void __CanRecvDump(const struct di_can_frame_rx *frame) {
printf("[can rx][%08x] ", frame->canid);
for (size_t n = 0; n < frame->size; n++)
printf("%02x ", ((uint8_t *)frame->buf)[n]);
for (size_t n = 0; n < (8 - frame->size); n++)
printf(" ");
printf("| ");
for (size_t n = 0; n < frame->size; n++)
printf("%c", isprint((int)frame->buf[n]) ? frame->buf[n] : '.');
for (size_t n = 0; n < (8 - frame->size); n++)
printf(" ");
printf("\n");
}
bool _loopback_enabled;
struct di_can_ctx _ctx;
struct di_can_frame_rx *_frame_rx_pool;
uint8_t *_msg_buffer_data;
struct di_buffer *_msg_buffer_pool;
struct di_can_msg *_msg_pool;
private:
bool __socketcan_enabled;
int __socketcan_fd;
di_errno_t __SocketCAN_Send(const struct di_can_frame_tx *frame) {
ssize_t ret;
struct can_frame f;
memset(&f, 0, sizeof(f));
f.can_id = frame->canid;
f.can_id |= CAN_EFF_FLAG;
f.can_dlc = static_cast<uint8_t>(frame->size);
if (f.can_dlc > 0)
memcpy(f.data, frame->buf, f.can_dlc);
ret = write(__socketcan_fd, &f, sizeof(struct can_frame));
if (ret != sizeof(struct can_frame))
return DNE_CAN_IO;
return DNOK;
}
int __SocketCAN_Open(std::string iface = "vcan0") {
int fd;
struct ifreq ifr;
struct sockaddr_can addr;
if (iface.size() > sizeof(ifr.ifr_name))
return -1;
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (fd < 0)
return -1;
addr.can_family = AF_CAN;
memcpy(ifr.ifr_name, iface.c_str(), iface.size());
ifr.ifr_name[iface.size()] = 0;
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
return -1;
addr.can_ifindex = ifr.ifr_ifindex;
fcntl(fd, F_SETFL, O_NONBLOCK);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
return -1;
return fd;
}
void __SocketCAN_Close() {
if (__socketcan_fd) {
close(__socketcan_fd);
__socketcan_fd = -1;
}
}
};