src.dualinventive.com/dinet/libdi-php/libdi/include/di/rpc/lowlevel.h

234 lines
7.2 KiB
C

/**
* @file include/di/rpc/lowlevel.h
* @brief Lowlevel RPC
* @date Aug 27, 2015
* @author rheijden
* @copyright 2015 Dual Inventive Technology Centre B.V.
*
* @defgroup rpc_ll DI-Net RPC lowlevel
* @{
*/
#ifndef INCLUDE_DI_RPC_LL_H_
#define INCLUDE_DI_RPC_LL_H_
#include <stdint.h>
#include <stdlib.h>
#include <di/types.h>
#include <di/buffer.h>
#include <di/device.h>
#include <mpack/mpack.h>
#ifdef __cplusplus
extern "C" {
#endif
/**< DI-Net lowlevel message header magic */
#define DI_RPC_LL_MSG_HDR_MAGIC \
"\x44\x4a\x52"
#define DI_RPC_LL_MSG_HDR_MAGIC_SIZE \
(sizeof(DI_RPC_LL_MSG_HDR_MAGIC) - 1)
#define DI_RPC_LL_MSG_HDR_TYPE_LEN 1U /** Message type field length in bytes */
#define DI_RPC_LL_MSG_HDR_TYPE_OFFSET 3U /** Message type field byte offset, after magic */
#define DI_RPC_LL_MSG_HDR_SIZE_LEN 2U /** Message size field length in bytes */
#define DI_RPC_LL_MSG_HDR_SIZE_OFFSET 4U /** Message size field byte offset, after magic */
#define DI_RPC_LL_MSG_HANDSHAKE_DEVICE_UID_SIZE 32U /** Message handshake device:uid size */
/** DI-Net lowlevel message header size */
#define DI_RPC_LL_MSG_HDR_SIZE \
(DI_RPC_LL_MSG_HDR_MAGIC_SIZE + \
DI_RPC_LL_MSG_HDR_TYPE_LEN + \
DI_RPC_LL_MSG_HDR_SIZE_LEN)
#define DI_RPC_LL_MSG_REPLY_MKAY "MKAY"
#define DI_RPC_LL_MSG_REPLY_MKAY_SIZE (sizeof(DI_RPC_LL_MSG_REPLY_MKAY) - 1)
#define DI_RPC_LL_MSG_REPLY_WTF "WTF"
#define DI_RPC_LL_MSG_REPLY_WTF_SIZE (sizeof(DI_RPC_LL_MSG_REPLY_WTF) - 1)
/** Message status */
enum di_rpc_ll_msg_status {
DI_RPC_LL_MSG_STAT_ERR_INVALID_TYPE = -3, /**< Message has invalid type */
DI_RPC_LL_MSG_STAT_ERR_MORE_DATA_NEEDED = -2, /**< Message incomplete, buffer needs more data */
DI_RPC_LL_MSG_STAT_UNKNOWN = -1, /**< Unknown message, header magic not found */
DI_RPC_LL_MSG_STAT_OK = 0, /**< Message ok */
};
/** DI-Net available lowlevel message types */
enum di_rpc_ll_msg_type {
DI_RPC_LL_MSG_TYPE_UNKNOWN = 0x00, /**< Unknown */
DI_RPC_LL_MSG_TYPE_HS_REQUEST = 0x01, /**< Handshake request */
DI_RPC_LL_MSG_TYPE_REPLY = 0x02, /**< Reply @see di_rpc_ll_msg_reply_status */
DI_RPC_LL_MSG_TYPE_REGISTER = 0x03, /**< Register device:uid on existing connection */
DI_RPC_LL_MSG_TYPE_UNREGISTER = 0x04, /**< Unregister device:uid on existing connection */
DI_RPC_LL_MSG_TYPE_PLAIN = 0x10, /**< Plain DI-Net RPC message */
DI_RPC_LL_MSG_TYPE_ENCRYPTED = 0x20, /**< Encrypted DI-Net RPC message */
DI_RPC_LL_MSG_TYPE_TIME = 0x40 /**< DI-Net time request/reply message */
};
/** Reply status when message is of type `DI_RPC_LL_MSG_TYPE_REPLY` */
enum di_rpc_ll_msg_reply {
DI_RPC_LL_MSG_REPLY_UNKNOWN, /**< Unknown reply status */
DI_RPC_LL_MSG_REPLY_ERROR, /**< Reply error (`"WTF"`) */
DI_RPC_LL_MSG_REPLY_OK, /**< Reply ok (`"MKAY"`) */
DI_RPC_LL_MSG_REPLY_TIME /**< Reply DI-Net timestamp */
};
/** DI-Net RPC lowlevel message */
struct di_rpc_ll_msg {
enum di_rpc_ll_msg_status status; /**< Message status */
enum di_rpc_ll_msg_reply reply; /**< Reply status when status == `DI_RPC_LL_MSG_TYPE_REPLY` */
enum di_rpc_ll_msg_type type; /**< Message type */
uint8_t *data; /**< Message data payload */
uint16_t size; /**< Message data payload size */
size_t remaining; /**< Bytes remaining in buf after message */
struct di_buffer *buf; /**< Buffer of current message */
};
/**
* @name Encoding
* @{
*/
/**
* Encode message from src buffer with src->used into dst buffer
* @param dst Destination buffer
* @param src Source buffer
* @param type Lowlevel message type of source buffer
*/
di_errno_t di_rpc_ll_encode(struct di_buffer *dst, struct di_buffer *src, enum di_rpc_ll_msg_type type);
/**
* Encode handshake which uses device:uid
* @param buf The destination buffer to encode the handshake message to
* @param device_uid The device:uid must be 33 bytes which must include the NULL termination
* @retval DNOK when device_uid is correct and buf holds the encoded message
*/
di_errno_t di_rpc_ll_encode_handshake(struct di_buffer *buf,
const char device_uid[DI_DEVICE_UID_LEN]);
/**
* Write register which uses device:uid
* @param buf The destination buffer to encode the register message to
* @param device_uid The device:uid must be 33 bytes which must include the NULL termination
* @retval DNOK when device_uid is correct and buf holds the encoded message
*/
di_errno_t di_rpc_ll_encode_register(struct di_buffer *buf,
const char device_uid[DI_DEVICE_UID_LEN]);
/**
* Write time request
*/
di_errno_t di_rpc_ll_encode_time_request(struct di_buffer *buf);
/**
* Encode time
*/
di_errno_t di_rpc_ll_encode_time(struct di_buffer *buf, uint64_t time);
/**
* @}
*/
/**
* @name Decoding
* @{
*/
/** Decode buffer into rpc lowlevel message
* @note DI_RPC_LL_MSG_STAT_OK -> DNOK, set llmsg->status accordingly ... DNOK is more convenient
*/
enum di_rpc_ll_msg_status di_rpc_ll_decode(struct di_buffer *buf, struct di_rpc_ll_msg *llmsg);
/**
* Decode the time from the message
*/
di_errno_t di_rpc_ll_decode_time(struct di_rpc_ll_msg *llmsg, uint64_t *time);
/**
* @}
*/
/**
* @name RPC reader
* @{
*/
/**
* Prepare RPC reader from buffer. It decodes the message header.
*/
di_errno_t di_rpc_ll_rpc_reader_start(mpack_writer_t *reader, struct di_buffer *buf);
/**
* Finish RPC reader.
* @todo how to return there is more data in buf, with di_errno?
*/
di_errno_t di_rpc_ll_rpc_reader_finish(mpack_writer_t *reader, struct di_buffer *buf);
/**
* @}
*/
/**
* @name RPC writer
* @{
*/
/**
* Prepare RPC writer with buffer. Skips enough bytes to write the lowlevel header.
*/
di_errno_t di_rpc_ll_rpc_writer_start(mpack_writer_t *writer, struct di_buffer *buf);
/**
* Finish RPC writer. Writers the lowlevel header.
*/
di_errno_t di_rpc_ll_rpc_writer_finish(mpack_writer_t *writer, struct di_buffer *buf);
/**
* @}
*/
/**
* @name Lowlevel operations
* @{
*/
/**
* Write lowlevel message header
* @note The buffer size must be minimal size of DI_RPC_LL_MSG_HDR_SIZE
* @param buf Target buffer (starts writing at offset 0)
* @param type Lowlevel message type
* @param data_len Length of data payload
* @note The current DI-Net RPC protocol specification has a limit of uint16_t frame length
*/
di_errno_t di_rpc_ll_write_header(struct di_buffer *buf, enum di_rpc_ll_msg_type type, size_t data_len);
/**
* Write lowlevel message data payload
* @note This only writes the payload, the header needs to be written first with di_rpc_ll_write_header.
* @param buf Target buffer (starts writing at offset after the lowlevel header)
* @param data Data payload
* @param len Data payload length
* @note The current DI-Net RPC protocol specification has a limit of uint16_t frame length
*/
di_errno_t di_rpc_ll_write_data(struct di_buffer *buf, const uint8_t *data, size_t len);
/**
* Copy remaining data from lowlevel message into a di_buffer
* @param dst Destination buffer (starts writing at offset 0)
* @param src Decoded lowlevel message which holds remaining data
*/
di_errno_t di_rpc_ll_memcpy_remaining(struct di_buffer *dst, struct di_rpc_ll_msg *src);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* INCLUDE_DI_RPC_LL_H_ */