From 026a5c40479c8a0096685358e2eaea3c4cddbb1b Mon Sep 17 00:00:00 2001 From: John Szewczyk Date: Mon, 27 Jul 2026 15:47:01 -0400 Subject: [PATCH 1/2] Initial commit for basic protocol implementation --- NGAP/UORIBC_C_API/uoribc.c | 164 +++++++++++++++ NGAP/UORIBC_C_API/uoribc.h | 110 ++++++++++ NGAP/UORIBC_C_API/uoribc_messages.c | 0 NGAP/UORIBC_C_API/uoribc_messages.h | 300 ++++++++++++++++++++++++++++ 4 files changed, 574 insertions(+) create mode 100644 NGAP/UORIBC_C_API/uoribc.c create mode 100644 NGAP/UORIBC_C_API/uoribc.h create mode 100644 NGAP/UORIBC_C_API/uoribc_messages.c create mode 100644 NGAP/UORIBC_C_API/uoribc_messages.h diff --git a/NGAP/UORIBC_C_API/uoribc.c b/NGAP/UORIBC_C_API/uoribc.c new file mode 100644 index 0000000..0625af2 --- /dev/null +++ b/NGAP/UORIBC_C_API/uoribc.c @@ -0,0 +1,164 @@ +#include "uoribc.h" +#include +#include + +// The following are macros used by UORIBC: + +#define INTERFACE_REGISTRY_SIZE 4U +#define DISPATCH_TABLE_SIZE 64U +#define MESSAGE_ID_MASK 127U + +// The following are structs used by UORIBC: + +typedef struct { + uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t); + uoribc_interface_id_t interface_id; +} interface_t; + + +typedef struct { + void (*callback_function)(uoribc_message_context_t context); + uoribc_interface_id_t interface_id; + uint8_t class_id; + uint8_t message_id; +} callback_entry_t; + + +// The following are buffers, registrys, and other statics used by UORIBC: + +static uint8_t device_node_id = 0; + +static interface_t interface_registry[INTERFACE_REGISTRY_SIZE]; +static uint8_t interface_registry_index = 0; + +static callback_entry_t callback_dispatch_table[DISPATCH_TABLE_SIZE]; +static uint8_t callback_table_index = 0; + +static bool device_initialized = false; + +// The following are weakly implemented private functions: + +__weak void uoribc_recieve_callback(uoribc_message_context_t context) { + // DO NOT IMPLEMENT HERE. REDEFINE THE FUNCTION ELSEWHERE, PRESERVING THIS ONE. +}; + + +// The following are implemented public functions: + +uoribc_general_error_t uoribc_initialize(uint8_t node_id){ + if (device_initialized == true) { + return UORIBC_ALREADY_INITIALIZED; + } + + device_node_id = node_id; + device_initialized = true; + + return UORIBC_GEN_OK; +} + +uoribc_interface_error_t uoribc_interface_register(uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t), uoribc_interface_id_t* interface_id) { + + if (device_initialized) { + return UORIBC_INTR_LOCKED; + } + + if (interface_registry_index + 1 >= INTERFACE_REGISTRY_SIZE) { + return UORIBC_MAX_INTERFACES; + } + + interface_t interface_struct; + interface_struct.interface_id = (uoribc_interface_id_t)(0b00000001 << interface_registry_index); + interface_struct.transmit_function = transmit_function; + + *interface_id = interface_struct.interface_id; + + interface_registry[interface_registry_index] = interface_struct; + interface_registry_index += 1; + + return UORIBC_INTERFACE_OK; +} + +uoribc_callback_error_t uoribc_callback_register(uoribc_interface_id_t interface_id, uint8_t class_id, uint8_t message_id, void (*callback_function)(uoribc_message_context_t)) { + + if (device_initialized) { + return UORIBC_CALLBACK_LOCKED; + } + + if (callback_table_index + 1 >= DISPATCH_TABLE_SIZE) { + return UORIBC_MAX_CALLBACKS; + } + + if (callback_function == NULL) { + return UORIBC_CALLBACK_INVALID; + } + + callback_entry_t callback_entry; + callback_entry.callback_function = callback_function; + callback_entry.interface_id = interface_id; + callback_entry.class_id = class_id; + callback_entry.message_id = message_id; + + callback_dispatch_table[callback_table_index] = callback_entry; + callback_table_index += 1; + + return UORIBC_CALLBACK_OK; +} + +uoribc_dispatch_error_t uoribc_message_recieve(uoribc_message_context_t context) { + + uoribc_recieve_callback(context); + + if (device_initialized == false) { + return UORIBC_DISP_LOCKED; + } + + if (context.type == UORIBC_MESSAGE) { + uint8_t class_id = context.identifier; + uint8_t message_id = context.skeleton.frame.header & MESSAGE_ID_MASK; + uoribc_interface_id_t interface_id = context.interface_id; + + for (uint16_t i = 0; i < callback_table_index; i++) { + callback_entry_t entry = callback_dispatch_table[i]; + + // Check if class id matches + if ((entry.class_id == class_id) && + (entry.message_id == message_id) && + (entry.interface_id & interface_id) == interface_id) + { + if (entry.callback_function == NULL) { + return UORIBC_DISPATCH_INVALID_CALLBACK; + } + // Dispatch Callback + entry.callback_function(context); + } + } + } + return UORIBC_DISPATCH_OK; +} + +uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t context) { + + if (device_initialized == false) { + return UORIBC_INTR_LOCKED; + } + + uoribc_interface_id_t interface_id = context.interface_id; + interface_t *interface_ptr = NULL; + + for (uint8_t i = 0; i < interface_registry_index; i++) { + if (interface_registry[i].interface_id == interface_id) { + interface_ptr = &interface_registry[i]; + break; + } + } + + if (interface_ptr == NULL) { + return UORIBC_INTR_NOT_REG; + } + + + context.node_id = device_node_id; + + return interface_ptr->transmit_function(context); +} + diff --git a/NGAP/UORIBC_C_API/uoribc.h b/NGAP/UORIBC_C_API/uoribc.h new file mode 100644 index 0000000..aa58817 --- /dev/null +++ b/NGAP/UORIBC_C_API/uoribc.h @@ -0,0 +1,110 @@ + + +#ifndef UORIBC +#define UORIBC + +#include + + +// Contains all public structs, enums, and function prototypes for the UORIBC API: + + +// The following are public enums: + +typedef enum { + UORIBC_GEN_OK = 0, + UORIBC_ALREADY_INITIALIZED = 1, +} uoribc_general_error_t; + +typedef enum { + UORIBC_INTERFACE_OK = 0, + + UORIBC_TRANSMIT_ERROR_0 = 1, + UORIBC_TRANSMIT_ERROR_1 = 2, + UORIBC_TRANSMIT_ERROR_2 = 3, + UORIBC_TRANSMIT_ERROR_3 = 4, + UORIBC_TRANSMIT_ERROR_4 = 5, + UORIBC_TRANSMIT_ERROR_5 = 6, + UORIBC_TRANSMIT_ERROR_6 = 7, + UORIBC_TRANSMIT_ERROR_7 = 8, + + UORIBC_MAX_INTERFACES = 9, + UORIBC_INTR_NOT_REG = 10, + UORIBC_INTR_LOCKED = 12, +} uoribc_interface_error_t; + +typedef enum { + UORIBC_CALLBACK_OK = 0, + UORIBC_CALLBACK_INVALID = 1, + UORIBC_CALLBACK_ERROR = 2, + UORIBC_MAX_CALLBACKS = 3, + UORIBC_CALLBACK_LOCKED = 4, +} uoribc_callback_error_t; + +typedef enum { + UORIBC_DISPATCH_OK = 0, + UORIBC_DISPATCH_INVALID_CALLBACK = 1, + UORIBC_DISP_LOCKED = 2, +} uoribc_dispatch_error_t; + +typedef enum { + UORIBC_MESSAGE = 0, + UORIBC_STREAM = 1, +} uoribc_payload_types_t; + +typedef enum { + UORIBC_INTERFACE_0 = 0b00000001, + UORIBC_INTERFACE_1 = 0b00000010, + UORIBC_INTERFACE_2 = 0b00000100, + UORIBC_INTERFACE_3 = 0b00001000 +} uoribc_interface_id_t; + +// The following are skeleton related public structs & unions + +typedef struct { + uint8_t header; + uint8_t *payload; +} uoribc_frame_skeleton_t; + +typedef struct { + uint8_t *payload; +} uoribc_stream_skeleton_t; + +typedef union { + uoribc_frame_skeleton_t frame; + uoribc_stream_skeleton_t stream; + +} uoribc_skeleton_t; + + + +// The following are structs related to messages +typedef struct { + uoribc_interface_id_t interface_id; + uoribc_skeleton_t skeleton; + uint8_t skeleton_size; + uoribc_payload_types_t type; + uint8_t identifier; + uint8_t node_id; +} uoribc_message_context_t; + + +\ +// The following are function prototypes for weakly defined functions: + + void uoribc_recieve_callback(uoribc_message_context_t context); + + +// The following are public function prototypes: + + uoribc_general_error_t uoribc_initialize(uint8_t node_id); + + uoribc_interface_error_t uoribc_interface_register(uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t), uoribc_interface_id_t* interface_id); + + uoribc_callback_error_t uoribc_callback_register(uoribc_interface_id_t interface_id, uint8_t class_id, uint8_t message_id, void (*callback_function)(uoribc_message_context_t)); + + uoribc_dispatch_error_t uoribc_message_recieve(uoribc_message_context_t context); + + uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t context); + +#endif \ No newline at end of file diff --git a/NGAP/UORIBC_C_API/uoribc_messages.c b/NGAP/UORIBC_C_API/uoribc_messages.c new file mode 100644 index 0000000..e69de29 diff --git a/NGAP/UORIBC_C_API/uoribc_messages.h b/NGAP/UORIBC_C_API/uoribc_messages.h new file mode 100644 index 0000000..80add9b --- /dev/null +++ b/NGAP/UORIBC_C_API/uoribc_messages.h @@ -0,0 +1,300 @@ +#include + +#ifndef UORIBC_MESSAGES +#define UORIBC_MESSAGES + +#define DEFAULT_CLASSES + +/* ========================================================================= + *UORIBC Class Definitions + * ========================================================================= */ + +#define UORIBC_CLASS_ESTOP 0U +#define UORIBC_CLASS_EMATCH 1U +#define UORIBC_CLASS_IAP 5U +#define UORIBC_CLASS_CONFIG 6U +#define UORIBC_CLASS_RESP_ACK 7U +#define UORIBC_CLASS_GEN_STAT 8U +#define UORIBC_CLASS_FC 9U +#define UORIBC_CLASS_REC 10U +#define UORIBC_CLASS_LT 11U + + +#ifdef DEFAULT_CLASSES + +#define ESTOP_CLASS +#define IAP_CLASS +#define CONFIG_CLASS +#define RESP_ACK_CLASS +#define GEN_STAT_CLASS + +#endif + + +#ifdef ESTOP_CLASS + +/* ========================================================================= + * Class 0 - E-Stop + * ========================================================================= */ + +#define UORIBC_ESTOP_ASSERT 0U + +typedef struct +{ + +} uoribc_estop_assert_t; + +#endif + +#ifdef EMATCH_CLASS + +/* ========================================================================= + * Class 1 - E-Match Deployment + * ========================================================================= */ + +#define UORIBC_EMATCH_DEPLOY 0U + +typedef struct +{ + + uint8_t charge_group; +} uoribc_ematch_deploy_t; + +#endif + +#ifdef IAP_CLASS + +/* ========================================================================= + * Class 5 - IAP + * + * No messages currently defined. + * ========================================================================= */ + +#endif + +#ifdef CONFIG_CLASS + +/* ========================================================================= + * Class 6 - Board Configuration + * ========================================================================= */ + +#define UORIBC_CONFIG_GET_DESCRIPTOR 0U +#define UORIBC_CONFIG_GET_LED_INFO 1U +#define UORIBC_CONFIG_LED_INFO 2U +#define UORIBC_CONFIG_BOARD_DESCRIPTOR 3U +#define UORIBC_CONFIG_CONFIGURATION_DESCRIPTOR 4U +#define UORIBC_CONFIG_LED_DESCRIPTOR 5U +#define UORIBC_CONFIG_SET_CONFIGURATION 6U +#define UORIBC_CONFIG_SET_LED 7U +#define UORIBC_CONFIG_OPEN_STREAM 8U +#define UORIBC_CONFIG_CLOSE_STREAM 9U +#define UORIBC_CONFIG_GET_STRING 10U + + +typedef struct +{ + + uint8_t node_id; + uint8_t descriptor_type; + uint8_t descriptor_index; +} uoribc_get_descriptor_t; + + +typedef struct +{ + + uint8_t node_id; +} uoribc_get_led_info_t; + + +typedef struct +{ + + uint8_t number_of_leds; +} uoribc_led_info_t; + + +typedef struct +{ + + uint8_t name_id; + uint8_t board_type; + uint8_t number_of_configurables; + uint8_t major_revision; + uint8_t minor_revision; + uint8_t board_variant; + uint8_t board_extended_functionality; +} uoribc_board_descriptor_t; + + +typedef struct +{ + + uint8_t descriptor_id; + uint8_t description_id; + uint8_t data_type; + uint8_t data[4]; +} uoribc_configuration_descriptor_t; + + +typedef struct +{ + + uint8_t descriptor_id; + uint8_t description_id; + uint8_t current_state; + uint8_t maximum_state; +} uoribc_led_descriptor_t; + + +typedef struct +{ + + uint8_t node_id; + uint8_t descriptor_id; + uint8_t data[4]; +} uoribc_set_configuration_t; + + +typedef struct +{ + + uint8_t descriptor_id; + uint8_t state; +} uoribc_set_led_t; + + +typedef struct +{ + + uint8_t node_id; + uint8_t stream_id; + uint8_t direction; + uint8_t stream_type; + uint8_t length; + uint8_t timeout[2]; +} uoribc_open_stream_t; + + +typedef struct +{ + + uint8_t stream_id; +} uoribc_close_stream_t; + + +typedef struct +{ + + uint8_t node_id; + uint8_t string_id; + uint8_t stream_id; +} uoribc_get_string_t; + +#endif + +#ifdef RESP_ACK_CLASS + +/* ========================================================================= + * Class 7 - Response and Acknowledgement + * ========================================================================= */ + +#define UORIBC_RESP_MESSAGE_ACK 0U +#define UORIBC_RESP_MESSAGE_NACK 1U +#define UORIBC_RESP_NODE_ACK 2U +#define UORIBC_RESP_NODE_NACK 3U + + +typedef struct +{ + + uint8_t node_id; + uint8_t class_id; + uint8_t message_id; +} uoribc_message_ack_t; + + +typedef struct +{ + + uint8_t node_id; + uint8_t class_id; + uint8_t message_id; +} uoribc_message_nack_t; + + +typedef struct +{ + + uint8_t node_id; +} uoribc_node_ack_t; + + +typedef struct +{ + + uint8_t node_id; +} uoribc_node_nack_t; + +#endif + +#ifdef GEN_STAT_CLASS + +/* ========================================================================= + * Class 8 - General Board Status + * ========================================================================= */ + +#define UORIBC_GEN_STAT_BOARD_RESET 0U + +typedef struct +{ + + uint8_t reason; +} uoribc_board_reset_t; + +#endif + +#ifdef FC_CLASS + +/* ========================================================================= + * Class 9 - Flight Controller + * ========================================================================= */ + +#endif + +#ifdef REC_CLASS + +/* ========================================================================= + * Class 10 - Recovery/Pyro + * ========================================================================= */ + +#define UORIBC_REC_CHANNEL_STATE 0U +#define UORIBC_REC_CHANNEL_DEPLOYED 1U + + +typedef struct +{ + + uint8_t physical_channel; + uint8_t charge_group; + uint8_t state; +} uoribc_channel_state_t; + + +typedef struct +{ + + uint8_t physical_channel; + uint8_t charge_group; +} uoribc_channel_deployed_t; + +#endif + +#ifdef CONFIG_CLASS + +/* ========================================================================= + * Class 11 - Logger/Telemetry + * ========================================================================= */ + +#endif +#endif \ No newline at end of file From 8e1bd27718f487a82597daa7dae024c9dcc216fc Mon Sep 17 00:00:00 2001 From: John Szewczyk Date: Sat, 1 Aug 2026 22:30:02 -0400 Subject: [PATCH 2/2] Feat: Add support for streams. WARNING - AN EXPLOIT EXISTS WITH THE STREAM SYSTEM. CURRENT IMPLEMENTATION SHOULD NOT BE USED IN FIELD --- NGAP/UORIBC_C_API/uoribc.c | 497 +++++++++++++++++++++++++--- NGAP/UORIBC_C_API/uoribc.h | 101 ++++-- NGAP/UORIBC_C_API/uoribc_messages.h | 2 - 3 files changed, 521 insertions(+), 79 deletions(-) diff --git a/NGAP/UORIBC_C_API/uoribc.c b/NGAP/UORIBC_C_API/uoribc.c index 0625af2..ef5ce87 100644 --- a/NGAP/UORIBC_C_API/uoribc.c +++ b/NGAP/UORIBC_C_API/uoribc.c @@ -1,40 +1,80 @@ #include "uoribc.h" #include #include +#include +#include + // The following are macros used by UORIBC: #define INTERFACE_REGISTRY_SIZE 4U + #define DISPATCH_TABLE_SIZE 64U -#define MESSAGE_ID_MASK 127U + +#define STREAM_REGISTRY_SIZE 2U +#define STREAM_BUFFER_SIZE 255U +#define STREAM_ID_MAX 15U +#define STREAM_REGISTRY_MASK_WIDTH 8U +#define STREAM_SEARCH_MASK 0b00000001U +#define STREAM_MAX_PAYLOAD_SIZE 8U + +#define MESSAGE_ID_MASK 0b01111111U + + + +#if STREAM_REGISTRY_SIZE > STREAM_REGISTRY_MASK_WIDTH + +#undef STREAM_REGISTRY_SIZE +#define STREAM_REGISTRY_SIZE STREAM_REGISTRY_MASK_WIDTH + +#endif // The following are structs used by UORIBC: typedef struct { - uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t); - uoribc_interface_id_t interface_id; + uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t); + uoribc_interface_id_t interface_id; } interface_t; typedef struct { - void (*callback_function)(uoribc_message_context_t context); - uoribc_interface_id_t interface_id; - uint8_t class_id; - uint8_t message_id; + void (*callback_function)(uoribc_message_context_t context); + uoribc_interface_id_t interface_id; + uint8_t class_id; + uint8_t message_id; } callback_entry_t; +typedef struct { + void (*stream_full_callback)(uint8_t stream_id); + uoribc_stream_dir_t stream_dir; + uoribc_interface_id_t interface_id; + uint8_t stream_size; + uint8_t stream_id; + bool stream_awaiting_closure; +} stream_t; + // The following are buffers, registrys, and other statics used by UORIBC: -static uint8_t device_node_id = 0; +static uint8_t device_node_id = 0U; + +static interface_t interface_registry[INTERFACE_REGISTRY_SIZE]; +static uint8_t interface_registry_index = 0U; + +static callback_entry_t callback_dispatch_table[DISPATCH_TABLE_SIZE]; +static uint8_t callback_table_index = 0U; + +static stream_t stream_registry[STREAM_REGISTRY_SIZE]; +static uint8_t stream_registry_mask = 0b00000000U; -static interface_t interface_registry[INTERFACE_REGISTRY_SIZE]; -static uint8_t interface_registry_index = 0; +static uint8_t stream_buffers[STREAM_REGISTRY_SIZE][STREAM_BUFFER_SIZE]; +static uint8_t stream_buffer_indexes[STREAM_REGISTRY_SIZE] = {0U}; -static callback_entry_t callback_dispatch_table[DISPATCH_TABLE_SIZE]; -static uint8_t callback_table_index = 0; +static atomic_bool stream_rw_locked = false; +static atomic_uint_fast8_t streams_in_use = 0; -static bool device_initialized = false; +// TODO: Although this is flaged as atomic, current usages are not atomic. Update usages to be atomic +static atomic_bool device_initialized = false; // The following are weakly implemented private functions: @@ -42,110 +82,255 @@ __weak void uoribc_recieve_callback(uoribc_message_context_t context) { // DO NOT IMPLEMENT HERE. REDEFINE THE FUNCTION ELSEWHERE, PRESERVING THIS ONE. }; +// The following are implemented private functions: + +static uoribc_interface_id_t u8_to_interface_id(uint8_t bit_value) { + + uoribc_interface_id_t return_value; + + switch(bit_value) { + case 0b00000001U: + return_value = UORIBC_INTERFACE_0; + break; + case 0b00000010U: + return_value = UORIBC_INTERFACE_1; + break; + case 0b00000100U: + return_value = UORIBC_INTERFACE_2; + break; + case 0b00001000U: + return_value = UORIBC_INTERFACE_3; + break; + default: + return_value = UORIBC_INTERFACE_0; + break; + } + + return return_value; +} + +static uint8_t interface_id_to_u8(uoribc_interface_id_t interface_id) { + + uint8_t return_value; + + switch(interface_id) { + case UORIBC_INTERFACE_0: + return_value = 0b00000001U; + break; + case UORIBC_INTERFACE_1: + return_value = 0b00000010U; + break; + case UORIBC_INTERFACE_2: + return_value = 0b00000100U; + break; + case UORIBC_INTERFACE_3: + return_value = 0b00001000U; + break; + default: + return_value = 0b00000001U; + break; + } + + return return_value; +} + +// Returns true if stream was found and false if stream was not found +static bool find_stream(uint8_t stream_id, stream_t **stream, uint8_t *index) { + + // Scan stream registry, checking mask to see if index is valid + for (uint8_t i = 0U; i < STREAM_REGISTRY_SIZE; i++) { + if (((stream_registry_mask >> i & STREAM_SEARCH_MASK) == STREAM_SEARCH_MASK) && + (stream_registry[i].stream_id == stream_id)) { + + if (index != NULL) { + *index = i; + } + + if (stream != NULL) { + *stream = &stream_registry[i]; + } + + return true; + } + } + return false; +} // The following are implemented public functions: uoribc_general_error_t uoribc_initialize(uint8_t node_id){ - if (device_initialized == true) { + + bool initialized = atomic_load(&device_initialized); + + if (initialized) { return UORIBC_ALREADY_INITIALIZED; } device_node_id = node_id; - device_initialized = true; + atomic_store(&device_initialized, true); return UORIBC_GEN_OK; } uoribc_interface_error_t uoribc_interface_register(uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t), uoribc_interface_id_t* interface_id) { - - if (device_initialized) { + // TODO: Update function to check if interface function pointer is null + bool initialized = atomic_load(&device_initialized); + + if (initialized) { return UORIBC_INTR_LOCKED; } - if (interface_registry_index + 1 >= INTERFACE_REGISTRY_SIZE) { + if (interface_registry_index + 1U > INTERFACE_REGISTRY_SIZE) { return UORIBC_MAX_INTERFACES; } - interface_t interface_struct; - interface_struct.interface_id = (uoribc_interface_id_t)(0b00000001 << interface_registry_index); + if (transmit_function == NULL){ + return UORIBC_INTR_PTR_NULL; + } + + // Fill interface struct + interface_t interface_struct = {0}; + interface_struct.interface_id = u8_to_interface_id(0b00000001U << interface_registry_index); interface_struct.transmit_function = transmit_function; - *interface_id = interface_struct.interface_id; + if (interface_id != NULL) { + *interface_id = interface_struct.interface_id; + } + // Update registy interface_registry[interface_registry_index] = interface_struct; - interface_registry_index += 1; + interface_registry_index += 1U; return UORIBC_INTERFACE_OK; } uoribc_callback_error_t uoribc_callback_register(uoribc_interface_id_t interface_id, uint8_t class_id, uint8_t message_id, void (*callback_function)(uoribc_message_context_t)) { - if (device_initialized) { + bool initialized = atomic_load(&device_initialized); + + if (initialized) { return UORIBC_CALLBACK_LOCKED; } - if (callback_table_index + 1 >= DISPATCH_TABLE_SIZE) { + if (callback_table_index + 1U > DISPATCH_TABLE_SIZE) { return UORIBC_MAX_CALLBACKS; - } + } if (callback_function == NULL) { return UORIBC_CALLBACK_INVALID; } - callback_entry_t callback_entry; + // Fill callback struct + callback_entry_t callback_entry = {0}; callback_entry.callback_function = callback_function; callback_entry.interface_id = interface_id; callback_entry.class_id = class_id; callback_entry.message_id = message_id; + // Update dispatch table callback_dispatch_table[callback_table_index] = callback_entry; - callback_table_index += 1; + callback_table_index += 1U; return UORIBC_CALLBACK_OK; } -uoribc_dispatch_error_t uoribc_message_recieve(uoribc_message_context_t context) { - +uoribc_dispatch_error_t uoribc_message_receive(uoribc_message_context_t context) { + // Call general recieve callback uoribc_recieve_callback(context); - if (device_initialized == false) { + bool initialized = atomic_load(&device_initialized); + + if (!initialized) { return UORIBC_DISP_LOCKED; } + // Check if frame is of message type if (context.type == UORIBC_MESSAGE) { uint8_t class_id = context.identifier; uint8_t message_id = context.skeleton.frame.header & MESSAGE_ID_MASK; - uoribc_interface_id_t interface_id = context.interface_id; + uint8_t interface_id_u8 = interface_id_to_u8(context.interface_id); - for (uint16_t i = 0; i < callback_table_index; i++) { + for (uint16_t i = 0U; i < callback_table_index; i++) { callback_entry_t entry = callback_dispatch_table[i]; // Check if class id matches if ((entry.class_id == class_id) && (entry.message_id == message_id) && - (entry.interface_id & interface_id) == interface_id) - { - if (entry.callback_function == NULL) { - return UORIBC_DISPATCH_INVALID_CALLBACK; - } + (interface_id_to_u8(entry.interface_id) & interface_id_u8) == interface_id_u8) + { + if (entry.callback_function == NULL) { + return UORIBC_DISPATCH_INVALID_CALLBACK; + } // Dispatch Callback - entry.callback_function(context); - } + entry.callback_function(context); + } + } + } + // TODO: The current implementation of recieving data on a stream allows for a node to hold the rw access of the registry hostage. + // This can occur if a node spams the stream with data, forcing the engine to constantly consume which never allows rw access to the registry. + // MUST FIX + else if (context.type == UORIBC_STREAM) { + uint8_t stream_id = context.identifier; + uint8_t registry_index = 0U; + + bool locked = atomic_load(&stream_rw_locked); + + if (locked) { + return UORIBC_DISP_LOCKED; + } + + streams_in_use += 1U; + + + for (uint8_t i = 0U; i < STREAM_REGISTRY_SIZE; i++) { + // Check that stream is recieving from interface + if (((stream_registry_mask >> i & STREAM_SEARCH_MASK) == STREAM_SEARCH_MASK) && + (stream_registry[i].stream_id == stream_id) && + // TODO: Expand these to improve quality of error reporting + (stream_registry[i].interface_id == context.interface_id) && + (stream_registry[i].stream_dir == UORIBC_STREAM_DIR_RX)) { + + uint8_t num_to_write = context.skeleton_size; + + if (num_to_write > stream_registry[i].stream_size) { + streams_in_use -= 1U; + return UORIBC_DISPATCH_STREAM_FULL; + } + + + // Prevent buffer overflow + if (stream_buffer_indexes[i] + num_to_write >= stream_registry[i].stream_size) { + num_to_write = (uint8_t)((uint16_t)(stream_buffer_indexes[i] + num_to_write) - stream_registry[i].stream_size); + } + + memcpy(&stream_buffers[i][stream_buffer_indexes[i]], context.skeleton.stream.payload, num_to_write); + stream_buffer_indexes[i] += num_to_write; + + if (stream_buffer_indexes[i] == stream_registry[i].stream_size) { + stream_registry[i].stream_full_callback(stream_registry[i].stream_id); + } + + break; } + } + streams_in_use -= 1U; } return UORIBC_DISPATCH_OK; } uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t context) { - if (device_initialized == false) { + bool initialized = atomic_load(&device_initialized); + + if (!initialized) { return UORIBC_INTR_LOCKED; } uoribc_interface_id_t interface_id = context.interface_id; interface_t *interface_ptr = NULL; - for (uint8_t i = 0; i < interface_registry_index; i++) { + // Look for interface in registry + for (uint8_t i = 0U; i < interface_registry_index; i++) { if (interface_registry[i].interface_id == interface_id) { interface_ptr = &interface_registry[i]; break; @@ -162,3 +347,233 @@ uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t contex return interface_ptr->transmit_function(context); } +uoribc_stream_error_t uoribc_stream_open(uoribc_interface_id_t interface_id, uint8_t stream_id, uoribc_stream_dir_t stream_dir, uint8_t stream_size, void (*stream_full_callback)(uint8_t stream_id)) { + + uint8_t free_index = 0U; + bool free_index_found = false; + bool locked = false; + + if (stream_id > STREAM_ID_MAX) { + return UORIBC_STREAM_ID_INVALID; + } + + uint8_t streams_tally = atomic_load(&streams_in_use); + if (streams_tally > 0U) { + return UORIBC_STREAM_LOCKED; + } + + atomic_compare_exchange_strong(&stream_rw_locked, &locked, true); + + if (locked) { + return UORIBC_STREAM_LOCKED; + } + + // Look for a free index in stream registry + for (uint8_t i = 0U; i < STREAM_REGISTRY_SIZE; i++) { + if (((stream_registry_mask >> i) & STREAM_SEARCH_MASK) != STREAM_SEARCH_MASK) { + free_index = i; + free_index_found = true; + break; + } + } + + if (free_index_found == false) { + atomic_store(&stream_rw_locked, false); + return UORIBC_MAX_STREAMS; + } + + // Check for duplicate stream ids + for (uint8_t i = 0U; i < STREAM_REGISTRY_SIZE; i++) { + uint8_t slot_mask = STREAM_SEARCH_MASK << i; + + if ((stream_registry_mask & slot_mask) != 0U) { + if (stream_registry[i].stream_id == stream_id) { + atomic_store(&stream_rw_locked, false); + return UORIBC_STREAM_EXISTS; + } + } +} + + // Register stream + stream_t new_stream = { + .stream_full_callback = stream_full_callback, + .interface_id = interface_id, + .stream_id = stream_id, + .stream_dir = stream_dir, + .stream_size = stream_size, + .stream_awaiting_closure = false, + }; + + stream_registry[free_index] = new_stream; + stream_registry_mask |= STREAM_SEARCH_MASK << free_index; + + atomic_store(&stream_rw_locked, false); + return UORIBC_STREAM_OK; +} + +uoribc_stream_error_t uoribc_stream_close(uint8_t stream_id) { + + uint8_t streams_tally = atomic_load(&streams_in_use); + if (streams_tally > 0U) { + return UORIBC_STREAM_LOCKED; + } + + bool locked = false; + atomic_compare_exchange_strong(&stream_rw_locked, &locked, true); + + + if (locked) { + return UORIBC_STREAM_LOCKED; + } + + + + for (uint8_t i = 0; i < STREAM_REGISTRY_SIZE; i++) { + if (((stream_registry_mask >> i) & STREAM_SEARCH_MASK) == STREAM_SEARCH_MASK) { + if (stream_registry[i].stream_id == stream_id) { + // Clear bit to indicate that slot is available + stream_registry_mask ^= STREAM_SEARCH_MASK << i; + stream_buffer_indexes[i] = 0; + atomic_store(&stream_rw_locked, false); + return UORIBC_STREAM_OK; + } + } + } + atomic_store(&stream_rw_locked, false); + return UORIBC_STREAM_ID_INVALID; +} + +uoribc_stream_error_t uoribc_stream_read_bytes(uint8_t stream_id, uint8_t *buffer, uint8_t num_to_read, uint8_t *num_read_ptr) { + uint8_t stream_index = 0; + stream_t *stream_ptr = NULL; + bool stream_found; + + bool locked = atomic_load(&stream_rw_locked); + + if (locked) { + return UORIBC_STREAM_LOCKED; + } + + streams_in_use += 1U; + + locked = atomic_load(&stream_rw_locked); + if (locked) { + streams_in_use -= 1U; + return UORIBC_STREAM_LOCKED; + } + + stream_found = find_stream(stream_id, &stream_ptr, &stream_index); + + + if (stream_found == false) { + streams_in_use -= 1U; + return UORIBC_STREAM_ID_INVALID; + } + + if (stream_ptr->stream_dir != UORIBC_STREAM_DIR_RX) { + streams_in_use -= 1U; + return UORIBC_STREAM_DIR_MISMATCH; + } + + + if (num_to_read > stream_buffer_indexes[stream_index]) { + num_to_read = stream_buffer_indexes[stream_index]; + } + + memcpy(buffer, stream_buffers[stream_index], num_to_read); + stream_buffer_indexes[stream_index] -= num_to_read; + + if (num_read_ptr != NULL) { + *num_read_ptr = num_to_read; + } + + streams_in_use -= 1U; + return UORIBC_STREAM_OK; + +} + +uoribc_stream_error_t uoribc_stream_write_bytes(uint8_t stream_id, uint8_t *buffer, uint8_t num_to_write) { + bool stream_found = false; + stream_t *stream_ptr = NULL; + + if (num_to_write == 0U) { + return UORIBC_STREAM_INVALID_SIZE; + } + + bool locked = atomic_load(&stream_rw_locked); + + if (locked) { + return UORIBC_STREAM_LOCKED; + } + + streams_in_use += 1U; + + locked = atomic_load(&stream_rw_locked); + + if (locked) { + streams_in_use -= 1U; + return UORIBC_STREAM_LOCKED; + } + + stream_found = find_stream(stream_id, &stream_ptr, NULL); + + if (stream_found == false) { + streams_in_use -= 1U; + return UORIBC_STREAM_ID_INVALID; + } + + if (stream_ptr->stream_dir != UORIBC_STREAM_DIR_TX) { + streams_in_use -= 1U; + return UORIBC_STREAM_DIR_MISMATCH; + } + + // Split the payload into chunks that fit within a UORIBC Frame + uint8_t number_of_payloads = (num_to_write / STREAM_MAX_PAYLOAD_SIZE); + uint8_t tail_size = num_to_write % STREAM_MAX_PAYLOAD_SIZE; + uoribc_interface_error_t tx_error; + + // Create write context + uoribc_message_context_t context_to_send = { + .interface_id = stream_ptr->interface_id, + .identifier = stream_ptr->stream_id, + .type = UORIBC_STREAM, + .skeleton_size = STREAM_MAX_PAYLOAD_SIZE, + }; + + + for (uint8_t i = 0U; i < number_of_payloads; i++) { + memcpy(context_to_send.skeleton.stream.payload, &buffer[i*8U], STREAM_MAX_PAYLOAD_SIZE); + tx_error = uoribc_message_transmit(context_to_send); + switch (tx_error) { + case (UORIBC_INTR_LOCKED): + streams_in_use -= 1U; + return UORIBC_STREAM_INTR_ERR; + break; + case (UORIBC_INTR_NOT_REG): + streams_in_use -= 1U; + return UORIBC_STREAM_INTR_ERR; + break; + default: + break; + } + } + + // Send tail + if (tail_size > 0U) { + memcpy(context_to_send.skeleton.stream.payload, &buffer[num_to_write-tail_size], tail_size); + tx_error = uoribc_message_transmit(context_to_send); + switch (tx_error) { + case (UORIBC_INTR_LOCKED): + return UORIBC_STREAM_INTR_ERR; + break; + case (UORIBC_INTR_NOT_REG): + return UORIBC_STREAM_INTR_ERR; + break; + default: + break; + } + } + + streams_in_use -= 1U; + return UORIBC_STREAM_OK; +} diff --git a/NGAP/UORIBC_C_API/uoribc.h b/NGAP/UORIBC_C_API/uoribc.h index aa58817..364431e 100644 --- a/NGAP/UORIBC_C_API/uoribc.h +++ b/NGAP/UORIBC_C_API/uoribc.h @@ -12,62 +12,82 @@ // The following are public enums: typedef enum { - UORIBC_GEN_OK = 0, - UORIBC_ALREADY_INITIALIZED = 1, + UORIBC_GEN_OK, + UORIBC_ALREADY_INITIALIZED, } uoribc_general_error_t; typedef enum { - UORIBC_INTERFACE_OK = 0, + UORIBC_INTERFACE_OK, - UORIBC_TRANSMIT_ERROR_0 = 1, - UORIBC_TRANSMIT_ERROR_1 = 2, - UORIBC_TRANSMIT_ERROR_2 = 3, - UORIBC_TRANSMIT_ERROR_3 = 4, - UORIBC_TRANSMIT_ERROR_4 = 5, - UORIBC_TRANSMIT_ERROR_5 = 6, - UORIBC_TRANSMIT_ERROR_6 = 7, - UORIBC_TRANSMIT_ERROR_7 = 8, + UORIBC_TRANSMIT_ERROR_0, + UORIBC_TRANSMIT_ERROR_1, + UORIBC_TRANSMIT_ERROR_2, + UORIBC_TRANSMIT_ERROR_3, + UORIBC_TRANSMIT_ERROR_4, + UORIBC_TRANSMIT_ERROR_5, + UORIBC_TRANSMIT_ERROR_6, + UORIBC_TRANSMIT_ERROR_7, - UORIBC_MAX_INTERFACES = 9, - UORIBC_INTR_NOT_REG = 10, - UORIBC_INTR_LOCKED = 12, + UORIBC_MAX_INTERFACES, + UORIBC_INTR_NOT_REG, + UORIBC_INTR_LOCKED, + UORIBC_INTR_PTR_NULL, } uoribc_interface_error_t; typedef enum { - UORIBC_CALLBACK_OK = 0, - UORIBC_CALLBACK_INVALID = 1, - UORIBC_CALLBACK_ERROR = 2, - UORIBC_MAX_CALLBACKS = 3, - UORIBC_CALLBACK_LOCKED = 4, + UORIBC_CALLBACK_OK, + UORIBC_CALLBACK_INVALID, + UORIBC_CALLBACK_ERROR, + UORIBC_MAX_CALLBACKS, + UORIBC_CALLBACK_LOCKED, } uoribc_callback_error_t; typedef enum { - UORIBC_DISPATCH_OK = 0, - UORIBC_DISPATCH_INVALID_CALLBACK = 1, - UORIBC_DISP_LOCKED = 2, + UORIBC_DISPATCH_OK, + UORIBC_DISPATCH_INVALID_CALLBACK, + UORIBC_DISPATCH_STREAM_FULL, + UORIBC_DISP_LOCKED, } uoribc_dispatch_error_t; typedef enum { - UORIBC_MESSAGE = 0, - UORIBC_STREAM = 1, + UORIBC_STREAM_OK, + UORIBC_STREAM_ID_INVALID, + UORIBC_STREAM_EXISTS, + UORIBC_MAX_STREAMS, + UORIBC_STREAM_INVALID_MASK_WIDTH, + UORIBC_STREAM_INVALID_SIZE, + UORIBC_STREAM_DIR_MISMATCH, + UORIBC_STREAM_LOCKED, + UORIBC_STREAM_INTR_ERR, +} uoribc_stream_error_t; + +typedef enum { + UORIBC_MESSAGE, + UORIBC_STREAM, } uoribc_payload_types_t; typedef enum { - UORIBC_INTERFACE_0 = 0b00000001, - UORIBC_INTERFACE_1 = 0b00000010, - UORIBC_INTERFACE_2 = 0b00000100, - UORIBC_INTERFACE_3 = 0b00001000 + UORIBC_INTERFACE_0 = 0b00000001U, + UORIBC_INTERFACE_1 = 0b00000010U, + UORIBC_INTERFACE_2 = 0b00000100U, + UORIBC_INTERFACE_3 = 0b00001000U, } uoribc_interface_id_t; +typedef enum { + UORIBC_STREAM_DIR_TX, + UORIBC_STREAM_DIR_RX, +} uoribc_stream_dir_t; // The following are skeleton related public structs & unions + + typedef struct { uint8_t header; - uint8_t *payload; + uint8_t payload[7]; } uoribc_frame_skeleton_t; typedef struct { - uint8_t *payload; + uint8_t payload[8]; } uoribc_stream_skeleton_t; typedef union { @@ -89,7 +109,7 @@ typedef struct { } uoribc_message_context_t; -\ + // The following are function prototypes for weakly defined functions: void uoribc_recieve_callback(uoribc_message_context_t context); @@ -97,14 +117,23 @@ typedef struct { // The following are public function prototypes: - uoribc_general_error_t uoribc_initialize(uint8_t node_id); + uoribc_general_error_t uoribc_initialize(uint8_t node_id); - uoribc_interface_error_t uoribc_interface_register(uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t), uoribc_interface_id_t* interface_id); + uoribc_interface_error_t uoribc_interface_register(uoribc_interface_error_t (*transmit_function)(uoribc_message_context_t), uoribc_interface_id_t* interface_id); - uoribc_callback_error_t uoribc_callback_register(uoribc_interface_id_t interface_id, uint8_t class_id, uint8_t message_id, void (*callback_function)(uoribc_message_context_t)); + uoribc_callback_error_t uoribc_callback_register(uoribc_interface_id_t interface_id, uint8_t class_id, uint8_t message_id, void (*callback_function)(uoribc_message_context_t)); - uoribc_dispatch_error_t uoribc_message_recieve(uoribc_message_context_t context); + uoribc_dispatch_error_t uoribc_message_receive(uoribc_message_context_t context); - uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t context); + uoribc_interface_error_t uoribc_message_transmit(uoribc_message_context_t context); + uoribc_stream_error_t uoribc_stream_open(uoribc_interface_id_t interface_id, uint8_t stream_id, uoribc_stream_dir_t stream_dir, uint8_t stream_size, void (*stream_full_callback)(uint8_t stream_id)); + + uoribc_stream_error_t uoribc_stream_close(uint8_t stream_id); + + uoribc_stream_error_t uoribc_stream_read_bytes(uint8_t stream_id, uint8_t *buffer, uint8_t num_to_read, uint8_t *num_read_ptr); + + uoribc_stream_error_t uoribc_stream_write_bytes(uint8_t stream_id, uint8_t *buffer, uint8_t num_to_write); + + #endif \ No newline at end of file diff --git a/NGAP/UORIBC_C_API/uoribc_messages.h b/NGAP/UORIBC_C_API/uoribc_messages.h index 80add9b..b135c81 100644 --- a/NGAP/UORIBC_C_API/uoribc_messages.h +++ b/NGAP/UORIBC_C_API/uoribc_messages.h @@ -66,8 +66,6 @@ typedef struct /* ========================================================================= * Class 5 - IAP - * - * No messages currently defined. * ========================================================================= */ #endif