feat: add unified SET protocol v2
This commit is contained in:
89
c/set-protocol/include/set_can.h
Normal file
89
c/set-protocol/include/set_can.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef SET_CAN_H
|
||||
#define SET_CAN_H
|
||||
|
||||
#include "set_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETP_CAN_ID_PREFIX 0x12U
|
||||
#define SETP_CAN_ID_PREFIX_MASK 0x1F000000UL
|
||||
#define SETP_CAN_ID_MASK 0x1FFFFFFFUL
|
||||
|
||||
#define SETP_CAN_PCI_FIRST 0x10U
|
||||
#define SETP_CAN_PCI_CONSECUTIVE 0x20U
|
||||
#define SETP_CAN_PCI_FLOW_CONTROL 0x30U
|
||||
#define SETP_CAN_PCI_TYPE_MASK 0xF0U
|
||||
#define SETP_CAN_PCI_VALUE_MASK 0x0FU
|
||||
|
||||
#define SETP_CAN_FC_CONTINUE 0x00U
|
||||
#define SETP_CAN_FC_WAIT 0x01U
|
||||
#define SETP_CAN_FC_OVERFLOW 0x02U
|
||||
|
||||
#define SETP_CAN_FIRST_DATA 5U
|
||||
#define SETP_CAN_CONSECUTIVE_DATA 7U
|
||||
|
||||
#ifndef SETP_CAN_REASSEMBLY_TIMEOUT_MS
|
||||
#define SETP_CAN_REASSEMBLY_TIMEOUT_MS 500U
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint8_t length;
|
||||
uint8_t data[8];
|
||||
} setp_can_frame_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t source;
|
||||
uint8_t destination;
|
||||
uint8_t priority;
|
||||
uint8_t channel;
|
||||
} setp_can_id_t;
|
||||
|
||||
typedef enum {
|
||||
SETP_CAN_RX_NONE = 0,
|
||||
SETP_CAN_RX_COMPLETE = 1,
|
||||
SETP_CAN_RX_FORMAT_ERROR = 2,
|
||||
SETP_CAN_RX_SEQUENCE_ERROR = 3,
|
||||
SETP_CAN_RX_TIMEOUT = 4
|
||||
} setp_can_rx_result_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[SETP_FRAME_MAX];
|
||||
uint16_t expected_length;
|
||||
uint16_t received_length;
|
||||
uint32_t can_id;
|
||||
uint32_t deadline_ms;
|
||||
uint8_t next_sequence;
|
||||
uint8_t active;
|
||||
} setp_can_rx_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *data;
|
||||
uint16_t length;
|
||||
uint32_t can_id;
|
||||
} setp_can_packet_t;
|
||||
|
||||
typedef bool (*setp_can_send_fn)(const setp_can_frame_t *frame, void *user);
|
||||
|
||||
uint32_t setp_can_id_pack(const setp_can_id_t *value);
|
||||
bool setp_can_id_unpack(uint32_t raw, setp_can_id_t *out);
|
||||
|
||||
/** Segment one complete SETP frame. Flow-control pacing belongs to the port. */
|
||||
bool setp_can_segment(const uint8_t *packet, uint16_t length, uint32_t can_id,
|
||||
setp_can_send_fn send, void *user);
|
||||
|
||||
void setp_can_rx_init(setp_can_rx_t *state);
|
||||
setp_can_rx_result_t setp_can_rx_feed(setp_can_rx_t *state,
|
||||
const setp_can_frame_t *frame,
|
||||
uint32_t now_ms, setp_can_packet_t *out);
|
||||
|
||||
bool setp_can_flow_control(setp_can_frame_t *out, uint32_t can_id,
|
||||
uint8_t status, uint8_t block_size, uint8_t st_min_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SET_CAN_H */
|
||||
91
c/set-protocol/include/set_firmware.h
Normal file
91
c/set-protocol/include/set_firmware.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#ifndef SET_FIRMWARE_H
|
||||
#define SET_FIRMWARE_H
|
||||
|
||||
#include "set_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETP_SHA256_SIZE 32U
|
||||
#define SETP_FW_BEGIN_FIXED_SIZE 58U
|
||||
#define SETP_FW_DATA_HEADER_SIZE 12U
|
||||
#define SETP_FW_END_SIZE 40U
|
||||
#define SETP_FW_STATUS_SIZE 16U
|
||||
#define SETP_FW_MANIFEST_SIZE 57U
|
||||
|
||||
#define SETP_FW_FLAG_RESUME 0x01U
|
||||
#define SETP_FW_FLAG_SIGNED 0x02U
|
||||
#define SETP_FW_FLAG_ERASE_SLOT 0x04U
|
||||
#define SETP_FW_FLAG_ACTIVATE 0x08U
|
||||
|
||||
typedef enum {
|
||||
SETP_FW_IDLE = 0,
|
||||
SETP_FW_RECEIVING = 1,
|
||||
SETP_FW_VERIFYING = 2,
|
||||
SETP_FW_READY = 3,
|
||||
SETP_FW_ACTIVE = 4,
|
||||
SETP_FW_FAILED = 5
|
||||
} setp_fw_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t image_size;
|
||||
uint32_t image_crc32;
|
||||
uint32_t image_version;
|
||||
uint32_t base_address;
|
||||
uint8_t slot;
|
||||
uint8_t flags;
|
||||
uint16_t block_size;
|
||||
uint8_t sha256[SETP_SHA256_SIZE];
|
||||
uint32_t signing_key_id;
|
||||
uint16_t signature_length;
|
||||
const uint8_t *signature;
|
||||
} setp_fw_begin_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint16_t data_length;
|
||||
uint16_t flags;
|
||||
uint32_t data_crc32;
|
||||
const uint8_t *data;
|
||||
} setp_fw_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t image_size;
|
||||
uint32_t image_crc32;
|
||||
uint8_t sha256[SETP_SHA256_SIZE];
|
||||
} setp_fw_end_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t active_slot;
|
||||
uint16_t max_block_size;
|
||||
uint32_t next_offset;
|
||||
uint32_t image_size;
|
||||
uint16_t last_error;
|
||||
uint16_t flags;
|
||||
} setp_fw_status_t;
|
||||
|
||||
size_t setp_fw_begin_encode(const setp_fw_begin_t *value, uint8_t *out, size_t capacity);
|
||||
bool setp_fw_begin_decode(const uint8_t *payload, uint16_t length, setp_fw_begin_t *out);
|
||||
|
||||
size_t setp_fw_data_encode(uint32_t offset, uint16_t flags,
|
||||
const uint8_t *data, uint16_t data_length,
|
||||
uint8_t *out, size_t capacity);
|
||||
bool setp_fw_data_decode(const uint8_t *payload, uint16_t length, setp_fw_data_t *out);
|
||||
|
||||
size_t setp_fw_end_encode(const setp_fw_end_t *value, uint8_t *out, size_t capacity);
|
||||
bool setp_fw_end_decode(const uint8_t *payload, uint16_t length, setp_fw_end_t *out);
|
||||
|
||||
size_t setp_fw_status_encode(const setp_fw_status_t *value, uint8_t *out, size_t capacity);
|
||||
bool setp_fw_status_decode(const uint8_t *payload, uint16_t length, setp_fw_status_t *out);
|
||||
|
||||
/** Canonical bytes verified by a firmware-signature backend. */
|
||||
size_t setp_fw_manifest_encode(const setp_fw_begin_t *value,
|
||||
uint8_t *out, size_t capacity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SET_FIRMWARE_H */
|
||||
148
c/set-protocol/include/set_protocol.h
Normal file
148
c/set-protocol/include/set_protocol.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#ifndef SET_PROTOCOL_H
|
||||
#define SET_PROTOCOL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETP_VERSION 0x02U
|
||||
#define SETP_SOF0 0xA5U
|
||||
#define SETP_SOF1 0x5AU
|
||||
#define SETP_HEADER_SIZE 14U
|
||||
#define SETP_CRC_SIZE 4U
|
||||
|
||||
#ifndef SETP_MAX_PAYLOAD
|
||||
#define SETP_MAX_PAYLOAD 512U
|
||||
#endif
|
||||
|
||||
#define SETP_FRAME_MAX (SETP_HEADER_SIZE + SETP_MAX_PAYLOAD + SETP_CRC_SIZE)
|
||||
#define SETP_NODE_LOCAL 0x0000U
|
||||
#define SETP_NODE_BROADCAST 0xFFFFU
|
||||
|
||||
/* Frame flags. Reserved bits must be transmitted as zero. */
|
||||
#define SETP_FLAG_RESPONSE 0x01U
|
||||
#define SETP_FLAG_EVENT 0x02U
|
||||
#define SETP_FLAG_ERROR 0x04U
|
||||
#define SETP_FLAG_ACK_REQUIRED 0x08U
|
||||
#define SETP_FLAG_MORE 0x10U
|
||||
#define SETP_FLAG_PRIORITY 0x20U
|
||||
#define SETP_FLAG_KNOWN_MASK 0x3FU
|
||||
#define SETP_FLAG_RESERVED_MASK 0xC0U
|
||||
|
||||
typedef enum {
|
||||
SETP_IFACE_NONE = 0,
|
||||
SETP_IFACE_RS232 = 1,
|
||||
SETP_IFACE_RS485 = 2,
|
||||
SETP_IFACE_CAN = 3,
|
||||
SETP_IFACE_USB_CDC = 4,
|
||||
SETP_IFACE_ETHERNET_TCP = 5,
|
||||
SETP_IFACE_ETHERNET_UDP = 6
|
||||
} setp_iface_t;
|
||||
|
||||
typedef enum {
|
||||
SETP_MSG_PING = 0x0001,
|
||||
SETP_MSG_DEVICE_INFO = 0x0002,
|
||||
SETP_MSG_CAPABILITIES = 0x0003,
|
||||
SETP_MSG_DIAGNOSTICS = 0x0008,
|
||||
SETP_MSG_READ = 0x0009,
|
||||
SETP_MSG_WRITE = 0x000A,
|
||||
SETP_MSG_LOG_READ = 0x0010,
|
||||
SETP_MSG_CATALOG = 0x0011,
|
||||
SETP_MSG_SUBSCRIBE = 0x0012,
|
||||
SETP_MSG_PUBLISH = 0x0013,
|
||||
SETP_MSG_UNSUBSCRIBE = 0x0014,
|
||||
|
||||
SETP_MSG_FW_BEGIN = 0x0100,
|
||||
SETP_MSG_FW_DATA = 0x0101,
|
||||
SETP_MSG_FW_END = 0x0102,
|
||||
SETP_MSG_FW_ABORT = 0x0103,
|
||||
SETP_MSG_FW_STATUS = 0x0104,
|
||||
SETP_MSG_FW_ACTIVATE = 0x0105,
|
||||
|
||||
SETP_MSG_DEVICE_BASE = 0x1000,
|
||||
SETP_MSG_DEVICE_LAST = 0x7FFF
|
||||
} setp_message_type_t;
|
||||
|
||||
typedef enum {
|
||||
SETP_STATUS_OK = 0,
|
||||
SETP_STATUS_INVALID_ARGUMENT = 1,
|
||||
SETP_STATUS_INVALID_LENGTH = 2,
|
||||
SETP_STATUS_NOT_FOUND = 3,
|
||||
SETP_STATUS_ACCESS_DENIED = 4,
|
||||
SETP_STATUS_BUSY = 5,
|
||||
SETP_STATUS_NO_PROVIDER = 6,
|
||||
SETP_STATUS_INTERNAL = 7,
|
||||
SETP_STATUS_CRC = 8,
|
||||
SETP_STATUS_SEQUENCE = 9,
|
||||
SETP_STATUS_NO_SPACE = 10,
|
||||
SETP_STATUS_UNSUPPORTED = 11,
|
||||
SETP_STATUS_VERIFY_FAILED = 12,
|
||||
SETP_STATUS_AUTH_FAILED = 13,
|
||||
SETP_STATUS_TIMEOUT = 14,
|
||||
SETP_STATUS_WRONG_STATE = 15
|
||||
} setp_status_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags;
|
||||
uint16_t message_type;
|
||||
uint16_t source;
|
||||
uint16_t destination;
|
||||
uint16_t sequence;
|
||||
uint16_t payload_length;
|
||||
const uint8_t *payload;
|
||||
} setp_frame_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t frames;
|
||||
uint32_t crc_errors;
|
||||
uint32_t version_errors;
|
||||
uint32_t length_errors;
|
||||
uint32_t flag_errors;
|
||||
uint32_t stray_bytes;
|
||||
uint32_t overflows;
|
||||
} setp_parser_stats_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[SETP_FRAME_MAX];
|
||||
uint16_t length;
|
||||
setp_parser_stats_t stats;
|
||||
} setp_parser_t;
|
||||
|
||||
typedef void (*setp_frame_fn)(const setp_frame_t *frame, void *user);
|
||||
|
||||
uint16_t setp_get_u16(const uint8_t *data);
|
||||
uint32_t setp_get_u32(const uint8_t *data);
|
||||
void setp_put_u16(uint8_t *data, uint16_t value);
|
||||
void setp_put_u32(uint8_t *data, uint32_t value);
|
||||
|
||||
uint32_t setp_crc32(const uint8_t *data, size_t length);
|
||||
|
||||
/** Encode one complete stream/UDP frame. Returns zero on invalid arguments. */
|
||||
size_t setp_frame_encode(const setp_frame_t *frame, uint8_t *out, size_t capacity);
|
||||
|
||||
/** Decode exactly one complete UDP/datagram frame; trailing bytes are rejected. */
|
||||
bool setp_frame_decode_datagram(const uint8_t *data, size_t length, setp_frame_t *out);
|
||||
|
||||
void setp_parser_init(setp_parser_t *parser);
|
||||
void setp_parser_reset(setp_parser_t *parser);
|
||||
|
||||
/** Feed an arbitrary stream chunk. Returns the number of delivered frames. */
|
||||
size_t setp_parser_feed(setp_parser_t *parser, const uint8_t *data, size_t length,
|
||||
setp_frame_fn callback, void *user);
|
||||
|
||||
/** Encode the common two-byte status prefix used by every response. */
|
||||
size_t setp_status_encode(uint16_t status, uint8_t *out, size_t capacity);
|
||||
|
||||
/** Split a response payload into status and optional response body. */
|
||||
bool setp_status_decode(const setp_frame_t *frame, uint16_t *status,
|
||||
const uint8_t **body, uint16_t *body_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SET_PROTOCOL_H */
|
||||
73
c/set-protocol/include/set_telemetry.h
Normal file
73
c/set-protocol/include/set_telemetry.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef SET_TELEMETRY_H
|
||||
#define SET_TELEMETRY_H
|
||||
|
||||
#include "set_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETP_SUBSCRIBE_HEADER_SIZE 8U
|
||||
#define SETP_PUBLISH_HEADER_SIZE 10U
|
||||
#define SETP_PUBLISH_ITEM_HEADER_SIZE 8U
|
||||
|
||||
typedef enum {
|
||||
SETP_VALUE_U16 = 1,
|
||||
SETP_VALUE_I16 = 2,
|
||||
SETP_VALUE_U32 = 3,
|
||||
SETP_VALUE_I32 = 4,
|
||||
SETP_VALUE_F32 = 5,
|
||||
SETP_VALUE_BYTES = 6
|
||||
} setp_value_encoding_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *output;
|
||||
uint16_t capacity;
|
||||
uint16_t length;
|
||||
uint16_t item_count;
|
||||
} setp_publish_builder_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *payload;
|
||||
uint16_t length;
|
||||
uint16_t offset;
|
||||
uint16_t remaining;
|
||||
uint16_t subscription_id;
|
||||
uint16_t sample_sequence;
|
||||
uint32_t timestamp_ms;
|
||||
} setp_publish_view_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
uint8_t encoding;
|
||||
uint8_t element_count;
|
||||
uint16_t data_length;
|
||||
const uint8_t *data;
|
||||
} setp_publish_item_t;
|
||||
|
||||
size_t setp_subscribe_encode(uint16_t subscription_id, uint32_t period_ms,
|
||||
const uint32_t *addresses, uint16_t address_count,
|
||||
uint8_t *out, size_t capacity);
|
||||
bool setp_subscribe_decode_header(const uint8_t *payload, uint16_t length,
|
||||
uint16_t *subscription_id, uint32_t *period_ms,
|
||||
uint16_t *address_count);
|
||||
bool setp_subscribe_address(const uint8_t *payload, uint16_t length,
|
||||
uint16_t index, uint32_t *address);
|
||||
|
||||
bool setp_publish_begin(setp_publish_builder_t *builder,
|
||||
uint16_t subscription_id, uint16_t sample_sequence,
|
||||
uint32_t timestamp_ms, uint8_t *out, uint16_t capacity);
|
||||
bool setp_publish_add(setp_publish_builder_t *builder, uint32_t address,
|
||||
uint8_t encoding, uint8_t element_count,
|
||||
const uint8_t *data, uint16_t data_length);
|
||||
size_t setp_publish_finish(setp_publish_builder_t *builder);
|
||||
|
||||
bool setp_publish_view_init(setp_publish_view_t *view,
|
||||
const uint8_t *payload, uint16_t length);
|
||||
bool setp_publish_next(setp_publish_view_t *view, setp_publish_item_t *item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SET_TELEMETRY_H */
|
||||
Reference in New Issue
Block a user