/** * @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 #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)); // !broadcast and dst_id unset is a protocol error msg->dst_id = DI_CAN_NODEID_UNSET; msg->broadcast = false; 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; /* Send reply on request */ if (DI_CAN_GET_TRANSFERTYPE(msg->canid) == DI_CAN_TRANSFERTYPE_REQUEST) { 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); return; } di_can_msg_free(&msg); di_can_msg_gc(ctx, DI_CAN_GC_ALL); di_can_frame_gc(ctx, DI_CAN_GC_ALL); } } /** 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->broadcast ASSERT_EQ(DI_CAN_NODEID_UNSET, msg->dst_id); msg->src_id = 0xdeadbeef; msg->broadcast = true; ASSERT_EQ(DNOK, di_can_reqrep(&msg, 10)); ASSERT_NE(nullptr, msg); ASSERT_NE(req, msg); di_can_msg_free(&msg); thr.join(); // Send broadcast request by setting msg->dst_id to DI_CAN_NODEID_BROADCAST thr = std::thread(reqrep_dnok_thread, &_ctx); msg = di_can_msg_alloc_with_canid(&_ctx, DI_CAN_MSGTYPE_RAW, DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_RAW_DTYPE_DEVICE_UID); req = msg; ASSERT_FALSE(msg->broadcast); 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)); }