/** * @file include/di/can/net/node.h * @brief DI-Net CAN network node maintenaince * @date Nov 2, 2016 * @author jjacobs * @copyright 2016 Dual Inventive Technology Centre B.V. * * CAN network discovery */ #ifndef LIBDI_INCLUDE_DI_CAN_NET_NODE_H_ #define LIBDI_INCLUDE_DI_CAN_NET_NODE_H_ #include #include #ifdef __cplusplus extern "C" { #endif struct di_can_ctx; struct di_can_msg; struct di_can_net; struct di_can_net_node; /** * Node state */ enum di_can_net_node_states { DI_CAN_NET_NODE_STATE_UNKNOWN, /**< Node is in unknown state */ DI_CAN_NET_NODE_STATE_ONLINE, /**< Node is online */ DI_CAN_NET_NODE_STATE_OFFLINE /**< Node is offline */ }; /** * Node events for callbacks */ enum di_can_net_node_events { DI_CAN_NET_NODE_EVENT_NEW, /**< New node detected */ DI_CAN_NET_NODE_EVENT_ERROR, /**< Node error change detected */ DI_CAN_NET_NODE_EVENT_ROLE_PASSIVE, /**< Node fulfils the passive role */ DI_CAN_NET_NODE_EVENT_ROLE_FOLLOWER, /**< Node fulfils the follower role */ DI_CAN_NET_NODE_EVENT_ROLE_LEADER, /**< Node fulfils the leader role */ DI_CAN_NET_NODE_EVENT_LEADER_OFFLINE, /**< Leader node went offline (due to heartbeat timeout) */ DI_CAN_NET_NODE_EVENT_LEADER_TAKEOVER_FAILED, /**< Leader takeover failed (application gave up leadership) */ DI_CAN_NET_NODE_EVENT_CONFLICT /**< Node conflict (role, nodeid) */ }; /** * Node types list */ #define DI_CAN_NET_NODE_TYPE_LIST \ DI_CAN_NET_NODE_TYPE(UNKNOWN, "unknown", 0x00) \ DI_CAN_NET_NODE_TYPE(GATEWAY, "gateway", 0x01) \ DI_CAN_NET_NODE_TYPE(DEVICE, "device", 0x02) #define DI_CAN_NET_NODE_TYPE(enumerator, str, id) \ DI_CAN_NET_NODE_TYPE_##enumerator = id, enum di_can_net_node_types { DI_CAN_NET_NODE_TYPE_LIST }; #undef DI_CAN_NET_NODE_TYPE /** * Node role list */ #define DI_CAN_NET_NODE_ROLE_LIST \ DI_CAN_NET_NODE_ROLE(UNKNOWN, "unknown", 0x00) \ DI_CAN_NET_NODE_ROLE(PASSIVE, "passive", 0x01) \ DI_CAN_NET_NODE_ROLE(FOLLOWER, "follower", 0x02) \ DI_CAN_NET_NODE_ROLE(LEADER, "leader", 0x03) #define DI_CAN_NET_NODE_ROLE(enumerator, str, id) \ DI_CAN_NET_NODE_ROLE_##enumerator = id, enum di_can_net_node_roles { DI_CAN_NET_NODE_ROLE_LIST }; #undef DI_CAN_NET_NODE_ROLE /** * @name Callbacks * @{ */ /** * Node event callback (including self), application is responsible for filtering * @note When the application receives an event, the node type/role is updated AFTER the event * is processed by the application. This mechanism is chosen so the application is able * to make decisions based on the event and the previous role. The only exception is the * DI_CAN_NET_NODE_NEW event which has role/type set before the application callback is * executed. * @param ctx CAN net subsystem context * @param ev Node event * @param node Node which triggered the event */ typedef void (*di_can_net_node_event_cb_t)(const struct di_can_net *ctx, const enum di_can_net_node_events ev, const struct di_can_net_node *node); /** @} */ /** * Update or add node */ void di_can_net_node_update(struct di_can_net *ctx, const struct di_can_net_node *data); /** Update node error field */ di_errno_t di_can_net_node_update_error(struct di_can_net *ctx, const uint32_t nodeid, const di_errno_t err); /** * Check if node is self */ bool di_can_net_node_is_self(const struct di_can_net *ctx, const struct di_can_net_node *node); /** Check if the node is of the same type as self (di_can_net_node_type enum) */ bool di_can_net_node_is_same_type_as_self(const struct di_can_net *ctx, const struct di_can_net_node *node); /** * Check if the node has the error field set (!DNOK) * @note The ctx is locked in this function */ bool di_can_net_node_has_error(struct di_can_net *ctx, const struct di_can_net_node *node); /** * Update leader nodes state (OFFLINE) based on last seen time (heartbeat updates the node->seen time * @note Must be called after di_can_net_lock * @note The di_can_ctx is necessary when self becomes the leader */ void di_can_net_node_update_leaders_last_seen(struct di_can_ctx *ctx); /** * Set node event callback for application * @note This callback is executed on node state change in di_can_net_execute. */ void di_can_net_node_set_event_callback(struct di_can_ctx *ctx, di_can_net_node_event_cb_t cb); /** * Run the registered node event callback */ void di_can_net_node_run_event_callback(const struct di_can_net *ctx, const enum di_can_net_node_events ev, const struct di_can_net_node *node); /** * Finish the registered node event callback by signalling the application * di_can_node_wait_for_event_callback_finish. * @note When finish is called, all node updates should be processed! */ void di_can_net_node_run_event_callback_finish(struct di_can_net *ctx); /** * Wait for event callback to be finished * @param ctx CAN context * @param timeout_ms Timeout for wait in milliseconds * @return DNOK when callback is finished, DNE_TIMEOUT when not finished */ di_errno_t di_can_node_wait_for_event_callback_finish(struct di_can_ctx *ctx, uint32_t timeout_ms); #ifdef __cplusplus } #endif #endif /* LIBDI_INCLUDE_DI_CAN_NET_NODE_H_ */