/** * @file tests/can_net_node_events.cpp * @brief CAN Net node events (for application) * @date Dec 14, 2016 * @author jjacobs * @copyright 2016 Dual Inventive Technology Centre B.V. */ #include "fixtures/CANTest.hpp" /** * Verify if the correct node role events are emitted * We fake a node on the network which publishes its type/role using the heartbeat publish message */ void net_node_events_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; static size_t idx = 0; static const struct _tv { const enum di_can_net_node_events ev; const enum di_can_net_node_roles role; } tv[] = { // The NEW and PASSIVE events are emitted by the new node detection { DI_CAN_NET_NODE_EVENT_NEW, DI_CAN_NET_NODE_ROLE_PASSIVE }, { DI_CAN_NET_NODE_EVENT_ROLE_PASSIVE, DI_CAN_NET_NODE_ROLE_PASSIVE }, // Node transition events PASSIVE -> FOLLOWER-> LEADER { DI_CAN_NET_NODE_EVENT_ROLE_FOLLOWER, DI_CAN_NET_NODE_ROLE_PASSIVE }, { DI_CAN_NET_NODE_EVENT_ROLE_LEADER, DI_CAN_NET_NODE_ROLE_FOLLOWER } }; printf("event[%zu](%d): node: %04x, type: %02x, role: %02x\n", idx, ev, node->nodeid, node->type, node->role); ASSERT_EQ(0xcafebabe, node->nodeid); ASSERT_EQ(DI_CAN_NET_NODE_TYPE_UNKNOWN, node->type); ASSERT_GT(DI_ARRAY_SIZE(tv), idx); ASSERT_EQ(node->role, tv[idx].role); ASSERT_EQ(ev, tv[idx].ev); idx++; } TEST_F(DI_CAN, net_node_events) { static struct di_can_callback msg_callbacks[] = { DI_CAN_NET_CALLBACK_HEARTBEAT_PUBLISH_ITEM }; SetNodeid(0xdead1337); di_can_callback_init(&_ctx, msg_callbacks, DI_ARRAY_SIZE(msg_callbacks)); di_can_net_node_set_event_callback(&_ctx, net_node_events_event_cb); /* Fake role PASSIVE, FOLLOWER publishes */ SetNodeid(0xcafebabe); _ctx.net.self.role = DI_CAN_NET_NODE_ROLE_UNKNOWN; ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_PASSIVE)); ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER)); /* Fake role LEADER publish */ _ctx.net.self.role = DI_CAN_NET_NODE_ROLE_LEADER; ASSERT_EQ(DNOK, di_can_net_self_publish_heartbeat(&_ctx)); /* Recv all messages (we need to reset to the "real/receiving" nodeid */ SetNodeid(0xdead1337); struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); do { ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); } while (msg); PrintNetNodes(); } /** * When the discovery is missed on the peer node the leader node is not seen. * We expect after the first leader heartbeat to receive a NEW and ROLE_LEADER event. * @note This test is created to make sure Jira issue TWS-23 fix works */ static size_t g_net_node_events_event_leader_ping_cb_idx = 0; void net_node_events_event_leader_ping_cb(const struct di_can_net *ctx, const enum di_can_net_node_events ev, const struct di_can_net_node *node) { (void)ctx; static const struct _tv { const enum di_can_net_node_events ev; const enum di_can_net_node_roles role; } tv[] = { { DI_CAN_NET_NODE_EVENT_NEW, DI_CAN_NET_NODE_ROLE_LEADER }, { DI_CAN_NET_NODE_EVENT_ROLE_LEADER, DI_CAN_NET_NODE_ROLE_LEADER } }; printf("event[%zu](%d): node: %04x, type: %02x, role: %02x\n", g_net_node_events_event_leader_ping_cb_idx, ev, node->nodeid, node->type, node->role); ASSERT_EQ(0xcafebabe, node->nodeid); ASSERT_EQ(DI_CAN_NET_NODE_TYPE_UNKNOWN, node->type); ASSERT_GT(DI_ARRAY_SIZE(tv), g_net_node_events_event_leader_ping_cb_idx); ASSERT_EQ(tv[g_net_node_events_event_leader_ping_cb_idx].ev, ev); ASSERT_EQ(tv[g_net_node_events_event_leader_ping_cb_idx].role, node->role); g_net_node_events_event_leader_ping_cb_idx++; } TEST_F(DI_CAN, net_node_event_new_leader_ping) { static struct di_can_callback msg_callbacks[] = { DI_CAN_NET_CALLBACK_HEARTBEAT_PUBLISH_ITEM }; SetNodeid(0xdead1337); di_can_callback_init(&_ctx, msg_callbacks, DI_ARRAY_SIZE(msg_callbacks)); di_can_net_node_set_event_callback(&_ctx, net_node_events_event_leader_ping_cb); /* Fake role PASSIVE, FOLLOWER publishes */ SetNodeid(0xcafebabe); _ctx.net.self.role = DI_CAN_NET_NODE_ROLE_LEADER; /* Fake role LEADER publish */ _ctx.net.self.role = DI_CAN_NET_NODE_ROLE_LEADER; ASSERT_EQ(DNOK, di_can_net_self_publish_heartbeat(&_ctx)); /* Recv all messages (we need to reset to the "real/receiving" nodeid */ SetNodeid(0xdead1337); struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); do { ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); } while (msg); EXPECT_EQ(2U, g_net_node_events_event_leader_ping_cb_idx); PrintNetNodes(); }