/** * @file tests/can_net_self_leader.cpp * @brief CAN Net node events (for application) * @date Dec 14, 2016 * @author jjacobs * @copyright 2016 Dual Inventive Technology Centre B.V. * * Verify if self becomes leader * * Set self TYPE_DEVICE * * Set self ROLE_FOLLOWER * * Discover network (request) * * Discover network (finish) * * Verify ROLE_FOLLOWER -> ROLE_LEADER event on self * * Verify leadership */ #include "fixtures/CANTest.hpp" extern "C" { #include "time.c" } static size_t g_ev_idx = 0; static void net_self_leader_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 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_ROLE_LEADER, DI_CAN_NET_NODE_ROLE_FOLLOWER } }; printf("[%s] event(%d): node: %04x, type: %02x, role: %02x\n", __func__, ev, node->nodeid, node->type, node->role); ASSERT_TRUE(di_can_net_node_is_self(ctx, node)); ASSERT_EQ(0xdeadbeef, node->nodeid); // ASSERT_EQ(DI_CAN_NET_NODE_TYPE_DEVICE, node->type); ASSERT_GT(DI_ARRAY_SIZE(tv), g_ev_idx); ASSERT_EQ(tv[g_ev_idx].ev, ev); ASSERT_EQ(tv[g_ev_idx].role, node->role); g_ev_idx++; } TEST_F(DI_CAN, net_self_leader) { SetNodeid(0xdeadbeef); di_can_net_node_set_event_callback(&_ctx, net_self_leader_event_cb); // ASSERT_EQ(DNOK, di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_DEVICE)); ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER)); /* Check discover state and leadership */ ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_UNKNOWN, _ctx.net.discover.state); ASSERT_FALSE(di_can_net_self_is_leader(&_ctx)); /* Execute net subsystem once (results in discover request) */ di_can_net_execute(&_ctx); ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_REQUEST, _ctx.net.discover.state); ASSERT_FALSE(di_can_net_self_is_leader(&_ctx)); /* Force discover timeout, execute net subsystem (results in leadership) */ _di_time_uptime = DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS; ASSERT_EQ(0U, g_ev_idx); di_can_net_execute(&_ctx); ASSERT_EQ(1U, g_ev_idx); g_ev_idx = 0; ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_FINISH, _ctx.net.discover.state); ASSERT_TRUE(di_can_net_self_is_leader(&_ctx)); } /** * Verify the heartbeat is send every DI_CAN_NET_CFG_SELF_LEADER_HEARTBEAT_MS */ TEST_F(DI_CAN, net_self_leader_heartbeat) { struct di_can_msg *msg; const size_t n_publishes = 8; // TODO: if we send more messages than 8 we are unable to receive them in loopback mode SetNodeid(0xdeadbeef); //ASSERT_EQ(DNOK, di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_DEVICE)); _ctx.net.discover.state = DI_CAN_NET_DISCOVER_STATE_FINISH; _ctx.net.self.role = DI_CAN_NET_NODE_ROLE_LEADER; /* Execute net subsystem and check if first publish is send */ _di_time_uptime = 0; ASSERT_EQ(0U, _ctx.net.self.seen); di_can_net_execute(&_ctx); ASSERT_EQ(DI_CAN_NET_CFG_SELF_LEADER_HEARTBEAT_MS, _ctx.net.self.seen); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_NE(nullptr, msg); /* Execute net subsystem second time, no publish is send (due to publish timeout not exceeded) */ di_can_net_execute(&_ctx); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); ASSERT_EQ(nullptr, msg); /* Execute net subsystem 10 times (results in LEADER heartbeat publishes) */ _di_time_uptime = DI_CAN_NET_CFG_SELF_LEADER_HEARTBEAT_MS; for (size_t n = 0; n < n_publishes; n++) { di_can_net_execute(&_ctx); _di_time_uptime += DI_CAN_NET_CFG_SELF_LEADER_HEARTBEAT_MS; } /* Verify 10 leader heartbeat publishes */ for (size_t n = 0; n < n_publishes; n++) { msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET); if (!msg) ASSERT_TRUE(false) << "di_can_recv == NULL (n: " << n << ")"; 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(0xdeadbeef, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); /* Verify the payload struct */ ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype); ASSERT_EQ(2U, msg->size); // ASSERT_EQ(DI_CAN_NET_NODE_TYPE_DEVICE, msg->msg[0]); ASSERT_EQ(DI_CAN_NET_NODE_ROLE_LEADER, msg->msg[1]); di_can_msg_free(&msg); } }