/** * @file tests/can_net_discover_fsm.cpp * @brief CAN Net discover mechanism (leader,follower) * @date Sep 5, 2015 * @author jjacobs * @copyright 2015 Dual Inventive Technology Centre B.V. */ #include "fixtures/CANTest.hpp" /** * Verify the correct network discover request broadcast message is send * * msgtype : DI_CAN_MSGTYPE_NET * * transfertype : DI_CAN_TRANSFERTYPE_REQUEST * * datatype : DI_CAN_NET_DTYPE_DISCOVER * * src node id : 0xdead1337 * * dst node id : DI_CAN_NODEID_BROADCAST (0xffffffff) */ TEST_F(DI_CAN, net_discover) { SetNodeid(0xdead1337); ASSERT_EQ(DNOK, di_can_net_discover(&_ctx)); struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE((void *)NULL, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdead1337, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); di_can_msg_free(&msg); } /** * Verify the DISCOVER request is correctly handled by the DI_CAN_NET_CALLBACK_DISCOVER_ITEM * * Call di_can_net_discover (src_id: 0xdeadbeef -> dst_id: broadcast) * * Execute callback on msg (src_id: 0xcafebabe -> dst_id: 0xdeadbeef) * * Verify reply is send */ static struct di_can_callback test_discover_callbacks[] = { DI_CAN_NET_DISCOVER_CALLBACK_REQUEST_ITEM, DI_CAN_NET_DISCOVER_CALLBACK_REPLY_ITEM }; TEST_F(DI_CAN, discover_cb_trigger_on_request) { di_can_callback_init(&_ctx, test_discover_callbacks, DI_ARRAY_SIZE(test_discover_callbacks)); /* Request discover from node id 0xdeadbeef */ SetNodeid(0xdeadbeef); ASSERT_EQ(DNOK, di_can_net_discover(&_ctx)); /* Reply discover */ SetNodeid(0xcafebabe); di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_GATEWAY); di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER); /* Read request and execute request callback (which sends a reply) */ struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdeadbeef, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); ASSERT_EQ(0U, msg->size); ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); /* Read the DI_CAN_NET_DTYPE_HEARTBEAT publish message which was send by the * di_can_net_self_set_node_role call (necessary for fast-takeover) */ msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_HEARTBEAT, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype); ASSERT_EQ(2U, msg->size); ASSERT_EQ(0xcafebabe, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); di_can_msg_free(&msg); /* Check if the correct reply is send from the callback */ msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE((void *)NULL, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype); ASSERT_EQ(2U, msg->size); ASSERT_EQ(0xcafebabe, msg->src_id); ASSERT_EQ(0xdeadbeef, msg->dst_id); } /** * Verify execution of DI_CAN_NET_DISCOVER_CALLBACK_REPLY_ITEM * The nodes list is updated with: * - nodeid: 0xdeadbeef * - type: DI_CAN_NET_NODE_TYPE_GATEWAY * - role: DI_CAN_NET_NODE_ROLE_FOLLOWER */ static bool discover_cb_trigger_on_reply_node_new; static bool discover_cb_trigger_on_reply_node_conflict; static struct di_can_net_node discover_cb_trigger_on_reply_node; void discover_cb_trigger_on_reply_event_cb(const struct di_can_net *ctx, const enum di_can_net_node_events ev, const struct di_can_net_node *node) { (void)ctx; printf("event(%d): node: %04x, type: %02x, role: %02x\n", ev, node->nodeid, node->type, node->role); /* Only copy the node structure for the test when it is correct */ if (node->nodeid == 0xcafebabe && node->type == DI_CAN_NET_NODE_TYPE_GATEWAY) { memcpy(&discover_cb_trigger_on_reply_node, node, sizeof(*node)); switch (ev) { case DI_CAN_NET_NODE_EVENT_NEW: if (node->role == DI_CAN_NET_NODE_ROLE_FOLLOWER) discover_cb_trigger_on_reply_node_new = true; break; case DI_CAN_NET_NODE_EVENT_CONFLICT: discover_cb_trigger_on_reply_node_conflict = true; break; default: break; } } } TEST_F(DI_CAN, discover_cb_trigger_on_reply) { di_can_callback_init(&_ctx, test_discover_callbacks, DI_ARRAY_SIZE(test_discover_callbacks)); di_can_net_node_set_event_callback(&_ctx, discover_cb_trigger_on_reply_event_cb); /* Request discover from node id 0xdeadbeef */ SetNodeid(0xdeadbeef); ASSERT_EQ(DNOK, di_can_net_discover(&_ctx)); /* Reply discover */ SetNodeid(0xcafebabe); // Fake a nodeid (for reply) di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_GATEWAY); di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER); struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0U, msg->size); ASSERT_EQ(0xdeadbeef, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); SetNodeid(0xdeadbeef); // Restore the local nodeid, else a nodeid conflict is detected /* Read the DI_CAN_NET_DTYPE_HEARTBEAT publish message which was send by the * di_can_net_self_set_node_role call (necessary for fast-takeover) */ msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_HEARTBEAT, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype); ASSERT_EQ(2U, msg->size); ASSERT_EQ(0xcafebabe, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); di_can_msg_free(&msg); /* Check if the correct reply is send from the callback */ msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype); ASSERT_EQ(2U, msg->size); ASSERT_EQ(0xcafebabe, msg->src_id); ASSERT_EQ(0xdeadbeef, msg->dst_id); ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); /* Check if the discover_cb_trigger_on_reply_event_cb is fired and the node is correct */ ASSERT_EQ(0xcafebabe, discover_cb_trigger_on_reply_node.nodeid); ASSERT_EQ(DI_CAN_NET_NODE_TYPE_GATEWAY, discover_cb_trigger_on_reply_node.type); ASSERT_EQ(DI_CAN_NET_NODE_ROLE_FOLLOWER, discover_cb_trigger_on_reply_node.role); /* Check if NEW event is fired */ ASSERT_TRUE(discover_cb_trigger_on_reply_node_new); ASSERT_FALSE(discover_cb_trigger_on_reply_node_conflict); /* Check if the CONFLICT event is NOT fired (due to probably self and node[0] have the same nodeid) */ PrintNetNodes(); ASSERT_FALSE(discover_cb_trigger_on_reply_node_conflict); }