/** * @file include/di/can.h * @defgroup can CAN Messaging Stack * @brief DI CAN messaging stack * @date Aug 25, 2015 * @author rheijden * @copyright 2015 Dual Inventive Technology Centre B.V. * * DI CAN messaging stack * @{ */ #ifndef INCLUDE_DI_CAN_H_ #define INCLUDE_DI_CAN_H_ #include #include #include #include #include #include #include #include #include /** CAN subsystem context */ struct di_can_ctx { di_bsem_t lock; uint32_t nodeid; /**< Local nodeid */ uint8_t transaction; /**< Current transaction id */ uint16_t rt_seqnr; /**< Current Realtime message sequence number */ struct di_can_frame frame; struct { bool timesync_enabled; /**< Timesync when RAW DINET_TIME is received */ bool dst_id_filter_enabled; /**< Node destination ID filter (see di_can_msg_enable_dst_id_filter) */ di_bsem_t lock; struct di_array pool; struct di_array callback; uint32_t timeout; /**< Garbage collection timeout of messages in assembly (milliseconds) */ struct { bool is_blocking; di_bsem_t any; di_bsem_t raw; di_bsem_t rpc; di_bsem_t net; di_bsem_t log; size_t any_cnt; size_t raw_cnt; size_t rpc_cnt; size_t net_cnt; size_t log_cnt; uint32_t timeout; } recv; } msg; struct { struct di_can_reqrep_item item; } reqrep; struct di_can_net net; struct di_can_stat stat; di_errno_t (*recv)(struct di_can_frame_rx *frame); /**< Platform specific CAN frame receive callback */ di_errno_t (*send)(const struct di_can_frame_tx *frame); /**< Platform specific CAN send callback */ void *private_data; /**< Application specific private data */ }; #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Initialize and verifies the CAN context */ di_errno_t di_can_init(struct di_can_ctx *ctx); /** * Set can nodeid based on uid hex-string (e.g di_device_uid_get) */ void di_can_set_nodeid(struct di_can_ctx *ctx, const char *uid); /** * Set di_can_ctx private_data for application */ void di_can_set_private_data(struct di_can_ctx *ctx, void *private_data); /** * Get private_data for application */ void *di_can_get_private_data(struct di_can_ctx *ctx); /** * Send can message, this function returns * the di_can_msg back to the msg pool. * A message needs to be requested from the message pool with * @ref di_can_msg_alloc * * The Source Node ID is read from ctx->nodeid when src_id == DI_CAN_NODEID_UNSET * (must be set with @ref di_can_set_nodeid). * * If msg->broadcast is true then the Destination Node ID is set to @ref DI_CAN_NODEID_BROADCAST * @param msg Message to send * @retval DNOK when send succeeded !DNOK otherwise. * @note When !DNOK is returned the application is responsible to free the message or try to send again */ di_errno_t di_can_send(struct di_can_msg **msg); /** * Send data as DI-CAN message * @param ctx CAN driver context * @param dst_id Destination ID * @param msgtype Message type * @param ttype Transfertype * @param dtype Datatype * @param ptype Payload type * @param data Data * @param size Size of data in bytes * @warning When something goes wrong on send the message is implicit freed */ di_errno_t di_can_send_data(struct di_can_ctx *ctx, uint32_t dst_id, enum di_can_msgtype msgtype, enum di_can_transfertype ttype, uint16_t dtype, enum di_can_ptypes ptype, const void *data, size_t size); /** * Send broadcast message * @warning When something goes wrong on send the message is implicit freed * @note The canid is not modified and needs to be prepared before */ di_errno_t di_can_send_broadcast(struct di_can_msg **msg); /** * Send reply where payload of reply is already written * @note Reply message is always freed */ di_errno_t di_can_send_reply(struct di_can_msg **rep, const struct di_can_msg *req); /** * Send di_errno reply where payload of reply is already written * @note Reply message is always freed */ di_errno_t di_can_send_errno_reply(const struct di_can_msg *req, const di_errno_t err); /** * Send can message as empty reply * @note It modifies the canid and write TRANSFERTYPE to REP. * And it set the message size field to zero. */ di_errno_t di_can_send_empty_reply(const struct di_can_msg *req); /** * Receive (assembled) can message, with matching canid fields: * * @ref DI_CAN_GET_MSGTYPE * * @ref DI_CAN_GET_DATATYPE * @param ctx CAN driver context * @param type Message type to receive * @return NULL if no packet is ready */ struct di_can_msg *di_can_recv(struct di_can_ctx *ctx, enum di_can_msgtype type); /** * Reassamble di_can_frame_rx into di_can_msg. * This function needs to be called at least every ~50 milliseconds */ di_errno_t di_can_reassemble(struct di_can_ctx *ctx); #ifdef __cplusplus } #endif /** @} */ #endif /* INCLUDE_DI_CAN_H_ */