src.dualinventive.com/jjacobs/dinetrpcll-sniffer/libdi/tests/can_msg_reqrep.cpp

174 lines
4.7 KiB
C++

/**
* @file tests/can_msg.cpp
* @brief CAN message unit test
* @date Sep 30, 2015
* @author jjacobs
* @copyright 2015 Dual Inventive Technology Centre B.V.
*
* CAN Message unit test
*/
#include <thread>
#include "fixtures/CANTest.hpp"
/** Check if DNE_TIMEOUT is returned when no reply is received */
TEST_F(DI_CAN, reqrep_timeout) {
struct di_can_msg *msg = di_can_msg_alloc_with_canid(&_ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REPLY,
DI_CAN_RAW_DTYPE_DEVICE_UID);
msg->src_id = 0xdeadbeef;
msg->dst_id = 0xcafebabe;
ASSERT_EQ(DNE_TIMEOUT, di_can_reqrep(&msg, 10));
}
/** Check if the the di_can_reqrep parameters are check correct */
TEST_F(DI_CAN, reqrep_params) {
struct di_can_msg *msg = di_can_msg_alloc_with_canid(&_ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REPLY,
DI_CAN_RAW_DTYPE_DEVICE_UID);
struct di_can_msg **_msg = NULL;
// NULL check
ASSERT_EQ(DNE_PARAM, di_can_reqrep(NULL, 10));
ASSERT_EQ(DNE_PARAM, di_can_reqrep(_msg, 10));
// dst_id unset is a protocol error
msg->dst_id = DI_CAN_NODEID_UNSET;
ASSERT_EQ(DNE_PROTO, di_can_reqrep(&msg, 10));
}
void reqrep_dnok_thread(struct di_can_ctx *ctx) {
struct di_can_msg *msg;
while (true) {
msg = di_can_recv(ctx, DI_CAN_MSGTYPE_ANY);
if (!msg)
continue;
struct di_can_msg *rep = di_can_msg_alloc_with_canid(ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REPLY,
DI_CAN_RAW_DTYPE_DEVICE_UID);
rep->src_id = msg->dst_id;
rep->dst_id = msg->src_id;
DI_CAN_SET_TRANSACTION(rep->canid, DI_CAN_GET_TRANSACTION(msg->canid));
di_can_send(&rep);
break;
}
}
/** Check if DNOK is returned when a reply is received with a unicast */
TEST_F(DI_CAN, reqrep_unicast_dnok) {
auto thr = std::thread(reqrep_dnok_thread, &_ctx);
/* Prepare request */
struct di_can_msg *msg = di_can_msg_alloc_with_canid(&_ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REQUEST,
DI_CAN_RAW_DTYPE_DEVICE_UID);
struct di_can_msg *req = msg;
msg->src_id = 0xdeadbeef;
msg->dst_id = 0xcafebabe;
ASSERT_EQ(DNOK, di_can_reqrep(&msg, 10));
ASSERT_NE(nullptr, msg);
ASSERT_NE(req, msg);
di_can_msg_free(&msg);
thr.join();
}
/** Check if DNOK is returned when a reply is received with a broadcast
* * Test msg->broadcast = true
* * Test msg->dst_id = DI_CAN_NODEID_BROADCAST
*/
TEST_F(DI_CAN, reqrep_broadcast_dnok) {
auto thr = std::thread(reqrep_dnok_thread, &_ctx);
/* Prepare request */
struct di_can_msg *msg = di_can_msg_alloc_with_canid(&_ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REQUEST,
DI_CAN_RAW_DTYPE_DEVICE_UID);
struct di_can_msg *req = msg;
// Send broadcast request by setting msg->dst_id
ASSERT_EQ(DI_CAN_NODEID_UNSET, msg->dst_id);
msg->src_id = 0xdeadbeef;
msg->dst_id = DI_CAN_NODEID_BROADCAST;
ASSERT_EQ(DNOK, di_can_reqrep(&msg, 10));
ASSERT_NE(nullptr, msg);
ASSERT_NE(req, msg);
di_can_msg_free(&msg);
thr.join();
}
/** Verify unicast outstanding reply is matched correctly and the semaphore works as expected */
TEST_F(DI_CAN, reqrep_add_item_unicast) {
// Prepare a outstanding reply item
_ctx.reqrep.item.canid = 0x12345678;
_ctx.reqrep.item.src_id = 0xdeadbeef;
// Prepare and add the reply
struct di_can_msg *msg = di_can_msg_alloc(&_ctx);
msg->canid = _ctx.reqrep.item.canid;
msg->src_id = _ctx.reqrep.item.src_id;
msg->dst_id = 0xcafebabe;
ASSERT_EQ(DNOK, di_can_reqrep_add_reply(&_ctx, msg));
// Verify the message pointer is set, and the semaphore works as expected
ASSERT_EQ(_ctx.reqrep.item.msg, msg);
ASSERT_EQ(DNOK, di_bsem_wait_timeout(&_ctx.reqrep.item.sem, 10));
ASSERT_EQ(DNE_TIMEOUT, di_bsem_wait_timeout(&_ctx.reqrep.item.sem, 10));
}
void reqrep_error_reply_thread(struct di_can_ctx *ctx) {
struct di_can_msg *msg;
while (true) {
msg = di_can_recv(ctx, DI_CAN_MSGTYPE_ANY);
if (!msg)
continue;
di_can_send_errno_reply(msg, DNE_OPNOTSUPP);
di_can_msg_free(&msg);
break;
}
}
/** Verify reply error sets the message error property */
TEST_F(DI_CAN, reqrep_error_reply) {
auto thr = std::thread(reqrep_error_reply_thread, &_ctx);
/* Prepare request */
struct di_can_msg *msg = di_can_msg_alloc_with_canid(&_ctx,
DI_CAN_MSGTYPE_RAW,
DI_CAN_TRANSFERTYPE_REQUEST,
DI_CAN_RAW_DTYPE_DEVICE_UID);
struct di_can_msg *req = msg;
// Send broadcast request by setting msg->dst_id
ASSERT_EQ(DI_CAN_NODEID_UNSET, msg->dst_id);
msg->src_id = 0xdeadbeef;
msg->dst_id = DI_CAN_NODEID_BROADCAST;
ASSERT_EQ(DNOK, di_can_reqrep(&msg, 100));
ASSERT_NE(nullptr, msg);
ASSERT_NE(req, msg);
ASSERT_EQ(DNE_OPNOTSUPP, msg->error);
di_can_msg_free(&msg);
thr.join();
}