src.dualinventive.com/dinet/sec-multi-proxy/libdi/include/di/can/msg.h

423 lines
14 KiB
C
Executable File

/**
* @ingroup can
* @defgroup can_msg Message pooling
* @brief di_can_msg pooling
* @date Oct 29, 2015
* @author jjacobs
* @copyright 2015 Dual Inventive Technology Centre B.V.
*
* CAN message buffer pooling
* @{
*/
#ifndef LIBDI_INCLUDE_DI_CAN_MSG_H_
#define LIBDI_INCLUDE_DI_CAN_MSG_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <di/types.h>
#include <di/buffer.h>
#include <di/can/ptypes.h>
#include <di/can/defines.h>
struct di_can_ctx;
#ifdef __cplusplus
extern "C" {
#endif
/** Declare di_can_msg array */
#define DI_CAN_MSG_DECL_ARRAY(name, elements, size) \
DI_BUFFER_DECL_ARRAY(name##_buffers, elements, size); \
static struct di_can_msg name[elements]
/** Initialize di_can_msg array */
#define DI_CAN_MSG_INIT_ARRAY(ctx, name, elements, size) \
DI_BUFFER_INIT_ARRAY(name##_buffers, elements, size); \
di_can_msg_init_array(ctx, name, elements, name##_buffers, elements)
/** Set new message state */
#define DI_CAN_MSG_SET_STATE(msg, msg_state) \
msg->state = msg_state
/**
* Message state
*/
enum di_can_msg_state {
DI_CAN_MSG_STATE_UNUSED = 0, /**< Message unused */
DI_CAN_MSG_STATE_REASSEMBLE, /**< Message in use by reassemble, as not all frames have been received */
DI_CAN_MSG_STATE_SEND, /**< Message in queue for async send */
DI_CAN_MSG_STATE_READY, /**< Message ready (crc checked) */
DI_CAN_MSG_STATE_APPLICATION, /**< Message in use by the application (WILL NOT GC!) */
DI_CAN_MSG_STATE_DIRTY, /**< Message marked for garbage collection */
DI_CAN_MSG_STATE_ERROR /**< Message in error state, after async send */
};
/**
* DI CAN Message
*/
struct di_can_msg {
enum di_can_msg_state state; /**< Message state */
di_errno_t error; /**< Message error (DNOK when good) */
uint32_t canid; /**< DI CAN id */
uint32_t src_id; /**< Source Node ID */
uint32_t dst_id; /**< Destination Node ID */
enum di_can_ptypes ptype; /**< Payload type */
uint8_t emflags; /**< Extended metadata flags */
uint64_t timeout; /**< Garbage collection timeout (di timestamp milliseconds) */
uint8_t *msg; /**< Message (when set, message is fully assembled and valid crc) */
size_t size; /**< Message size */
size_t size_written; /**< Message size already written by di_can_reassemble */
struct di_buffer *buf; /**< Raw buffer */
const struct di_can_ctx *ctx; /**< DI CAN context */
di_bsem_t lock; /**< Message lock (wait) */
};
/**
* DI CAN message field byte offsets in msg->buf
*/
enum di_can_msg_offsets {
DI_CAN_MSG_OFFSET_SRC_ID = 0, /**< Source node ID */
DI_CAN_MSG_OFFSET_DST_ID = 4, /**< Destination node ID */
DI_CAN_MSG_OFFSET_PTYPE = 8, /**< Payload type */
DI_CAN_MSG_OFFSET_PSIZE = 9, /**< Payload size */
DI_CAN_MSG_OFFSET_CRC = 11, /**< Payload CRC */
DI_CAN_MSG_OFFSET_EMFLAGS = 13, /**< Extended metadata flags */
DI_CAN_MSG_OFFSET_EMDATA = 14, /**< Extended metadata */
DI_CAN_MSG_OFFSET_DATA = 16 /**< Payload data */
};
/**
* DI CAN message Extended Metadata flags
*/
enum di_can_msg_emflags {
DI_CAN_MSG_EMFLAGS_NONE = 0,
DI_CAN_MSG_EMFLAG_EM_DISABLE = (1 << 7), /**< Extended Metadata Flags and Extended Metadata disable */
DI_CAN_MSG_EMFLAG_RT = (1 << 6), /**< Realtime message flag (emdata field contains uint16 seqnr) */
};
/**
* @name Initialisation and configuration
* @{
*/
/**
* Initialize can message subsystem
* @param ctx CAN context
* @param list List of can messages
* @param size Elements of can messages in list
* @note When the subsystem is already initialized next function calls will be ignored
*/
void di_can_msg_init(struct di_can_ctx *ctx, struct di_can_msg *list, size_t size);
/**
* Attach di_buffer to di_can_msg
* @param ctx CAN context where the messages are attached to
* @param msg_list Array of di_can_msg
* @param msg_size Element count of msg_list
* @param buffer_list Array of di_buffer (which are already initialized)
* @param buffer_size Element count of buffer_size
* @note msg_size and buffer_size MUST be equal
*/
void di_can_msg_init_array(const struct di_can_ctx *ctx,
struct di_can_msg *msg_list, size_t msg_size,
struct di_buffer *buffer_list, size_t buffer_size);
/**
* Enable time synchronisation (default disabled)
* When enable di_time_set_ms is called
* * msg['ttype'] = DI_CAN_TRANSFERTYPE_PUBLISH
* * msg['dtype'] = DI_CAN_RAW_DTYPE_DINET_TIME
* * msg['ptype'] = DI_CAN_PTYPE_U64
* @param ctx CAN context
* @param enable Enable or disable
*/
void di_can_msg_enable_timesync(struct di_can_ctx *ctx, bool enable);
/**
* Enable invalid dst_id filter, which only allows:
* * msg->dst == DI_CAN_NODEID_BROADCAST
* * msg->dst == ctx->nodeid
* These are filtered when the messages are reassemble and tried to set to the READY state
*/
void di_can_msg_enable_dst_id_filter(struct di_can_ctx *ctx, bool enable);
/** @} */
/**
* @name Locking
* @{
*/
/** Lock the message subsystem */
void di_can_msg_lock(struct di_can_ctx *ctx);
/** Unlock the message subsystem */
void di_can_msg_unlock(struct di_can_ctx *ctx);
/** @} */
/**
* @name Pooling
*/
/** Allocate message */
struct di_can_msg *di_can_msg_alloc(struct di_can_ctx *ctx);
/** Allocate message and initialize with canid
* @param ctx CAN context
* @param msgtype Message type
* @param ttype Transfer type
* @param dtype Data type
*/
struct di_can_msg *di_can_msg_alloc_with_canid(struct di_can_ctx *ctx,
const enum di_can_msgtype msgtype,
const enum di_can_transfertype ttype,
const uint16_t dtype);
/** Get unused message for di_can_reassemble */
struct di_can_msg *di_can_msg_alloc_reassemble(struct di_can_ctx *ctx);
/** Give message back to the pool */
void di_can_msg_free(struct di_can_msg **msg);
/** Search for first message which match canid, msg->state == DI_CAN_MSG_STATE_REASSEMBLY */
struct di_can_msg *di_can_msg_search(struct di_can_ctx *ctx, uint32_t canid);
/**
* Garbage collect where di_can_msg timeouts are exceeded
* This will use the di_time_get_uptime to test against
* the message timeout
* * When di_can_msg.timeout is set to DI_CAN_TIMEOUT_GC_SKIP it is not garbage collected
* * When di_can_msg.timeout is set to DI_CAN_TIMEOUT_GC_IMMEDIATE it is immediate collected
* @note This should be run with ~50ms interval from thread with all being freed up
*/
void di_can_msg_gc(struct di_can_ctx *ctx, enum di_can_gc gc);
/** @} */
/**
* @name Receive
* @{
*/
/**
* Initialize message receive semaphores
* @warning This is called by di_can_msg_init and should not be called directly
*/
void di_can_msg_recv_init(struct di_can_ctx *ctx);
/**
* Reset message receive counters
*/
void di_can_msg_recv_reset(struct di_can_ctx *ctx);
/**
* Set timeout for di_can_msg_recv_wait
*/
void di_can_msg_recv_set_timeout(struct di_can_ctx *ctx, uint32_t timeout_ms);
/**
* Set block/nonblocking mode for di_can_msg_recv_wait
* @param ctx CAN context
* @param recv_is_blocking Flag to set blocking/non-blocking mode on recv
*/
void di_can_msg_recv_set_blocking(struct di_can_ctx *ctx, bool recv_is_blocking);
/**
* Increment message counter for received msgtype
*/
void di_can_msg_recv_incr(struct di_can_ctx *ctx, enum di_can_msgtype type);
/**
* Decrement message counter for received msgtype
*/
void di_can_msg_recv_decr(struct di_can_ctx *ctx, enum di_can_msgtype type);
/**
* Wait until di_can_msgtype is received the behaviour is controlled with
* - di_can_msg_recv_set_timeout
* - di_can_msg_recv_set_blocking
* @param ctx CAN context
* @param type Wait until one message of type is ready
*/
di_errno_t di_can_msg_recv_wait(struct di_can_ctx *ctx, enum di_can_msgtype type);
/**
* Signal a di_can_msgtype is ready
*/
void di_can_msg_recv_post(struct di_can_ctx *ctx, enum di_can_msgtype type);
/**
* Check if one or more messages are received of type msgtype
*/
bool di_can_msg_recv_is_ready(struct di_can_ctx *ctx, enum di_can_msgtype type);
/** @} */
/**
* @name Message ready
* @{
*/
void di_can_msg_set_ready(struct di_can_msg **msg);
/**
* Get ready (assembled) message based on msgtype
* When DI_CAN_MSGTYPE_ANY any is given, the first ready message in the queue is returned
*/
struct di_can_msg *di_can_msg_get_ready_type(struct di_can_ctx *ctx, enum di_can_msgtype type);
/**
* Get ready (assembled) message based on canid
* - enum di_can_msgtype
* - enum di_can_raw_dtypes, enum di_rpc_types or enum di_can_net_dtypes
* - enum di_can_transfertype
*/
struct di_can_msg *di_can_msg_get_ready_canid(struct di_can_ctx *ctx, uint32_t canid);
/**
* Synchronize the di_time with the incoming di_can_msg when:
* * Transfertype is DI_CAN_TRANSFERTYPE_PUBLISH
* * Msgtype is DI_CAN_MSGTYPE_RAW
* * Datatype is DI_CAN_RAW_DTYPE_DINET_TIME
* * Payload type is DI_CAN_PTYPE_U64
* * Size is 8 bytes
* @param ctx CAN context
* @param msg CAN message to be checked
* @return true when msg time is synced
* @note The caller needs to cleanup the message with di_can_msg_free
*/
bool di_can_msg_timesync(struct di_can_ctx *ctx, const struct di_can_msg *msg);
/** @} */
/**
* @name Read message fields
* @{
*/
uint32_t di_can_msg_read_src_id(const struct di_can_msg *msg);
uint32_t di_can_msg_read_dst_id(const struct di_can_msg *msg);
enum di_can_ptypes di_can_msg_read_ptype(const struct di_can_msg *msg);
uint16_t di_can_msg_read_crc(const struct di_can_msg *msg);
uint8_t di_can_msg_read_emflags(const struct di_can_msg *msg);
uint16_t di_can_msg_read_emdata(const struct di_can_msg *msg);
uint16_t di_can_msg_read_psize(const struct di_can_msg *msg);
di_errno_t di_can_msg_read_data_bool(const struct di_can_msg *msg, bool *value);
di_errno_t di_can_msg_read_data_i8(const struct di_can_msg *msg, int8_t *value);
di_errno_t di_can_msg_read_data_i16(const struct di_can_msg *msg, int16_t *value);
di_errno_t di_can_msg_read_data_i32(const struct di_can_msg *msg, int32_t *value);
di_errno_t di_can_msg_read_data_i64(const struct di_can_msg *msg, int64_t *value);
di_errno_t di_can_msg_read_data_u8(const struct di_can_msg *msg, uint8_t *value);
di_errno_t di_can_msg_read_data_u16(const struct di_can_msg *msg, uint16_t *value);
di_errno_t di_can_msg_read_data_u32(const struct di_can_msg *msg, uint32_t *value);
di_errno_t di_can_msg_read_data_u64(const struct di_can_msg *msg, uint64_t *value);
di_errno_t di_can_msg_read_data_float(const struct di_can_msg *msg, float *value);
di_errno_t di_can_msg_read_data_double(const struct di_can_msg *msg, double *value);
di_errno_t di_can_msg_read_data_di_errno(const struct di_can_msg *msg, di_errno_t *err);
/** @} */
/**
* @name Write message fields
* @{
*/
di_errno_t di_can_msg_write_src_id(struct di_can_msg *msg, uint32_t src_id);
di_errno_t di_can_msg_write_dst_id(struct di_can_msg *msg, uint32_t dst_id);
di_errno_t di_can_msg_write_ptype(struct di_can_msg *msg, enum di_can_ptypes ptype);
di_errno_t di_can_msg_write_crc(struct di_can_msg *msg, uint16_t crc);
di_errno_t di_can_msg_write_psize(struct di_can_msg *msg, uint16_t psize);
di_errno_t di_can_msg_write_data_bool(struct di_can_msg *msg, bool value);
di_errno_t di_can_msg_write_data_i8(struct di_can_msg *msg, int8_t value);
di_errno_t di_can_msg_write_data_i16(struct di_can_msg *msg, int16_t value);
di_errno_t di_can_msg_write_data_i32(struct di_can_msg *msg, int32_t value);
di_errno_t di_can_msg_write_data_i64(struct di_can_msg *msg, int64_t value);
di_errno_t di_can_msg_write_data_u8(struct di_can_msg *msg, uint8_t value);
di_errno_t di_can_msg_write_data_u16(struct di_can_msg *msg, uint16_t value);
di_errno_t di_can_msg_write_data_u32(struct di_can_msg *msg, uint32_t value);
di_errno_t di_can_msg_write_data_u64(struct di_can_msg *msg, uint64_t value);
di_errno_t di_can_msg_write_data_float(struct di_can_msg *msg, float value);
di_errno_t di_can_msg_write_data_double(struct di_can_msg *msg, double value);
di_errno_t di_can_msg_write_data_string(struct di_can_msg *msg, const char *value);
di_errno_t di_can_msg_write_data_di_errno(struct di_can_msg *msg, di_errno_t err);
/** Copy raw buffer into can message at correct offset */
void di_can_msg_memcpy(struct di_can_msg *msg, const uint8_t *buffer, size_t size);
/** @} */
/**
* @name CAN identifier
* @{
*/
/**
* Set CAN message CAN identifier
* @note Only the msgtype, ttype and type fields are overwritten. The other bits are
* untouched
*/
void di_can_msg_set_canid(struct di_can_msg *msg, const enum di_can_msgtype msgtype,
const enum di_can_transfertype ttype, const uint16_t dtype);
/** @} */
/**
* @name Message checking helpers
* @{
*/
/**
* Check if the message has the request transfertype set
* @param msg CAN message
* @return true when the can message is a request, false otherwise
*/
bool di_can_msg_is_request(const struct di_can_msg *msg);
/** @} */
/**
* @name Extended metadata
* @{
*/
/**
* Set the Extended Metadata RT flag which marks the message a Realtime
* @param[in] msg CAN message
* @param state State of the flag
*/
void di_can_msg_emflag_set_rt(struct di_can_msg *msg, const bool state);
/**
* Set the Extended Metadata EM disable flag which marks the message
* the emdata and emflags fields are reserved (compatibility with older can stack messages)
* @param[in] msg CAN message
* @param state State of the flag
*/
void di_can_msg_emflag_set_em_disable(struct di_can_msg *msg, const bool state);
/**
* Get the RT flag from the Extended Metadata flags field
* @return true when flag is set, false otherwise
*/
bool di_can_msg_emflag_rt(const struct di_can_msg *msg);
/**
* Get the EM disable flag from the Extended Metadata flags field
* @return true when flag is set, false otherwise
*/
bool di_can_msg_emflag_em_disable(const struct di_can_msg *msg);
/** @} */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* LIBDI_INCLUDE_DI_CAN_MSG_H_ */