src.dualinventive.com/dinet/libdi/tests/can_net_discover.cpp

193 lines
7.5 KiB
C++

/**
* @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);
}