196 lines
6.8 KiB
C
Executable File
196 lines
6.8 KiB
C
Executable File
/**
|
|
* @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 <stdbool.h>
|
|
#include <di/can/callback.h>
|
|
#include <di/can/net/node.h>
|
|
|
|
#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_ */
|