/** * @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 #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_UNKNOWN, /**< Unknown event, never emitted to application callback */ 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(ZKL3000RC_MAIN, "zkl3000rc-main", 0x02) \ DI_CAN_NET_NODE_TYPE(ZKL3000RC_SWITCH_CONTROL, "zkl3000rc-switch-control", 0x03) \ DI_CAN_NET_NODE_TYPE(ZKL3000RC_SWITCH_MEAS, "zkl3000rc-switch-meas", 0x04) \ DI_CAN_NET_NODE_TYPE(ZKL3000RC_SWITCH_DRIVE, "zkl3000rc-switch-drive", 0x05) \ DI_CAN_NET_NODE_TYPE(TWS3000_WUM_MAIN, "tws3000-wum-main", 0x06) \ DI_CAN_NET_NODE_TYPE(TWS3000_WUM_MONITOR, "tws3000-wum-monitor", 0x07) \ DI_CAN_NET_NODE_TYPE(TWS3000_DUU, "tws3000-duu", 0x08) \ DI_CAN_NET_NODE_TYPE(TWS3000_DUM, "tws3000-dum", 0x09) \ DI_CAN_NET_NODE_TYPE(RVM_COMBOARD, "rvm-comboard", 0x0A) \ DI_CAN_NET_NODE_TYPE(RVM_SENSOR, "rvm-sensor", 0x0B) #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); /** * Foreach node type callback, used to itterate over the discovered/known nodes and perform some action * @param ctx CAN context * @param private_data Callback private data * @param node Node found which is of searched type * @retval DNOK when foreach can continue onto the next node, !DNOK when foreach must stop */ typedef di_errno_t (*di_can_node_foreach_type_cb)(struct di_can_ctx *ctx, void *private_data, 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); /** * Itterate over each node within the node type group * @param ctx CAN context * @param private_data Callback private data * @param cb Callback for each found node * @param type Nodes for given type to search for */ di_errno_t di_can_node_foreach_type(struct di_can_ctx *ctx, void *private_data, di_can_node_foreach_type_cb cb, const enum di_can_net_node_types type); #ifdef __cplusplus } #endif #endif /* LIBDI_INCLUDE_DI_CAN_NET_NODE_H_ */