From da0b87bee986c8bf98e03e81a5868e3a80bc7439 Mon Sep 17 00:00:00 2001 From: NawfalMotii79 Date: Mon, 9 Mar 2026 00:18:58 +0000 Subject: [PATCH] Add files via upload --- .../9_1_1_C_Cpp_Libraries/iio.c | 2039 +++++++++++++++++ .../9_1_1_C_Cpp_Libraries/iio.h | 143 ++ .../9_1_1_C_Cpp_Libraries/iio_app.c | 475 ++++ .../9_1_1_C_Cpp_Libraries/iio_app.h | 138 ++ .../9_1_1_C_Cpp_Libraries/iio_trigger.c | 227 ++ .../9_1_1_C_Cpp_Libraries/iio_trigger.h | 138 ++ .../9_1_1_C_Cpp_Libraries/iio_types.h | 280 +++ .../9_1_1_C_Cpp_Libraries/iiod.c | 927 ++++++++ .../9_1_1_C_Cpp_Libraries/iiod.h | 192 ++ .../9_1_1_C_Cpp_Libraries/iiod_private.h | 178 ++ .../9_1_1_C_Cpp_Libraries/jesd204.h | 295 +++ .../9_1_1_C_Cpp_Libraries/no_os_ain.h | 70 + .../9_1_1_C_Cpp_Libraries/no_os_alloc.c | 67 + .../9_1_1_C_Cpp_Libraries/no_os_alloc.h | 49 + .../9_1_1_C_Cpp_Libraries/no_os_aout.h | 78 + .../9_1_1_C_Cpp_Libraries/no_os_axi_io.h | 45 + .../no_os_circular_buffer.c | 390 ++++ .../no_os_circular_buffer.h | 94 + .../9_1_1_C_Cpp_Libraries/no_os_clk.c | 193 ++ .../9_1_1_C_Cpp_Libraries/no_os_clk.h | 128 ++ .../9_1_1_C_Cpp_Libraries/no_os_crc.h | 40 + .../9_1_1_C_Cpp_Libraries/no_os_crc16.c | 97 + .../9_1_1_C_Cpp_Libraries/no_os_crc16.h | 49 + .../9_1_1_C_Cpp_Libraries/no_os_crc24.c | 98 + .../9_1_1_C_Cpp_Libraries/no_os_crc24.h | 49 + .../9_1_1_C_Cpp_Libraries/no_os_crc8.c | 94 + .../9_1_1_C_Cpp_Libraries/no_os_crc8.h | 48 + .../9_1_1_C_Cpp_Libraries/no_os_delay.h | 56 + .../9_1_1_C_Cpp_Libraries/no_os_dma.c | 449 ++++ .../9_1_1_C_Cpp_Libraries/no_os_dma.h | 265 +++ .../9_1_1_C_Cpp_Libraries/no_os_eeprom.c | 119 + .../9_1_1_C_Cpp_Libraries/no_os_eeprom.h | 99 + .../9_1_1_C_Cpp_Libraries/no_os_error.h | 48 + .../9_1_1_C_Cpp_Libraries/no_os_fifo.c | 126 + .../9_1_1_C_Cpp_Libraries/no_os_fifo.h | 58 + .../9_1_1_C_Cpp_Libraries/no_os_flash.h | 96 + .../9_1_1_C_Cpp_Libraries/no_os_font_8x8.c | 166 ++ .../9_1_1_C_Cpp_Libraries/no_os_gpio.c | 231 ++ .../9_1_1_C_Cpp_Libraries/no_os_gpio.h | 166 ++ .../9_1_1_C_Cpp_Libraries/no_os_i2c.c | 209 ++ .../9_1_1_C_Cpp_Libraries/no_os_i2c.h | 146 ++ .../9_1_1_C_Cpp_Libraries/no_os_i3c.c | 698 ++++++ .../9_1_1_C_Cpp_Libraries/no_os_i3c.h | 396 ++++ .../9_1_1_C_Cpp_Libraries/no_os_init.h | 38 + .../9_1_1_C_Cpp_Libraries/no_os_irq.c | 265 +++ .../9_1_1_C_Cpp_Libraries/no_os_irq.h | 235 ++ .../9_1_1_C_Cpp_Libraries/no_os_lf256fifo.c | 148 ++ .../9_1_1_C_Cpp_Libraries/no_os_lf256fifo.h | 53 + .../9_1_1_C_Cpp_Libraries/no_os_list.c | 871 +++++++ .../9_1_1_C_Cpp_Libraries/no_os_list.h | 309 +++ .../9_1_1_C_Cpp_Libraries/no_os_mdio.c | 119 + .../9_1_1_C_Cpp_Libraries/no_os_mdio.h | 107 + .../9_1_1_C_Cpp_Libraries/no_os_mutex.c | 63 + .../9_1_1_C_Cpp_Libraries/no_os_mutex.h | 78 + .../9_1_1_C_Cpp_Libraries/no_os_pid.c | 202 ++ .../9_1_1_C_Cpp_Libraries/no_os_pid.h | 79 + .../9_1_1_C_Cpp_Libraries/no_os_print_log.h | 132 ++ .../9_1_1_C_Cpp_Libraries/no_os_pwm.c | 273 +++ .../9_1_1_C_Cpp_Libraries/no_os_pwm.h | 190 ++ .../9_1_1_C_Cpp_Libraries/no_os_rtc.h | 91 + .../9_1_1_C_Cpp_Libraries/no_os_semaphore.c | 63 + .../9_1_1_C_Cpp_Libraries/no_os_semaphore.h | 48 + .../9_1_1_C_Cpp_Libraries/no_os_sin_lut.c | 68 + .../9_1_1_C_Cpp_Libraries/no_os_spi.c | 278 +++ .../9_1_1_C_Cpp_Libraries/no_os_spi.h | 275 +++ .../9_1_1_C_Cpp_Libraries/no_os_tdm.c | 125 + .../9_1_1_C_Cpp_Libraries/no_os_tdm.h | 152 ++ .../9_1_1_C_Cpp_Libraries/no_os_timer.c | 213 ++ .../9_1_1_C_Cpp_Libraries/no_os_timer.h | 145 ++ .../9_1_1_C_Cpp_Libraries/no_os_trng.c | 98 + .../9_1_1_C_Cpp_Libraries/no_os_trng.h | 97 + .../9_1_1_C_Cpp_Libraries/no_os_uart.c | 220 ++ .../9_1_1_C_Cpp_Libraries/no_os_uart.h | 191 ++ .../9_1_1_C_Cpp_Libraries/no_os_units.h | 83 + .../9_1_1_C_Cpp_Libraries/no_os_util.c | 568 +++++ .../9_1_1_C_Cpp_Libraries/no_os_util.h | 215 ++ 76 files changed, 16041 insertions(+) create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_types.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod_private.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/jesd204.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_ain.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_aout.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_axi_io.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_delay.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_error.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_flash.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_font_8x8.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_init.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_print_log.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_rtc.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_sin_lut.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_units.h create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.c create mode 100644 9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.h diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.c new file mode 100644 index 0000000..2ec966e --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.c @@ -0,0 +1,2039 @@ +/***************************************************************************//** + * @file iio.c + * @brief Implementation of iio. + * @author Cristian Pop (cristian.pop@analog.com) + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include "iio.h" +#include "iio_types.h" +#include "iiod.h" +#include "ctype.h" +#include "no_os_util.h" +#include "no_os_list.h" +#include "no_os_error.h" +#include "no_os_uart.h" +#include "no_os_error.h" +#include "no_os_alloc.h" +#include "no_os_circular_buffer.h" +#include +#include +#include + +#ifdef NO_OS_NETWORKING +#include "no_os_delay.h" +#include "tcp_socket.h" +#endif + +#ifdef NO_OS_LWIP_NETWORKING +#include "no_os_delay.h" +#include "tcp_socket.h" +#include "lwip_socket.h" +#endif + +#define IIOD_PORT 30431 +#define MAX_SOCKET_TO_HANDLE 10 +#define REG_ACCESS_ATTRIBUTE "direct_reg_access" +#define IIOD_CONN_BUFFER_SIZE 0x1000 +#define NO_TRIGGER (uint32_t)-1 + +#define NO_OS_STRINGIFY(x) #x +#define NO_OS_TOSTRING(x) NO_OS_STRINGIFY(x) + +static char uart_buff[IIOD_CONN_BUFFER_SIZE]; + +static char header[] = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "]>" + ""; +static char header_end[] = ""; + +static const char * const iio_chan_type_string[] = { + [IIO_VOLTAGE] = "voltage", + [IIO_CURRENT] = "current", + [IIO_ALTVOLTAGE] = "altvoltage", + [IIO_ANGL_VEL] = "anglvel", + [IIO_TEMP] = "temp", + [IIO_CAPACITANCE] = "capacitance", + [IIO_ACCEL] = "accel", + [IIO_RESISTANCE] = "resistance", + [IIO_MAGN] = "magn", + [IIO_INCLI] = "incli", + [IIO_VELOCITY] = "velocity", + [IIO_ANGL] = "angl", + [IIO_ROT] = "rot", + [IIO_COUNT] = "count", + [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", + [IIO_WEIGHT] = "weight", +}; + +static const char * const iio_modifier_names[] = { + [IIO_MOD_X] = "x", + [IIO_MOD_Y] = "y", + [IIO_MOD_Z] = "z", + [IIO_MOD_TEMP_AMBIENT] = "ambient", + [IIO_MOD_PITCH] = "pitch", + [IIO_MOD_YAW] = "yaw", + [IIO_MOD_ROLL] = "roll", +}; + +/* Parameters used in show and store functions */ +struct attr_fun_params { + void *dev_instance; + char *buf; + uint32_t len; + struct iio_ch_info *ch_info; +}; + +struct iio_buffer_priv { + /* Field visible by user */ + struct iio_buffer public; + /** Buffer to read or write data. A reference will be found in buffer */ + struct no_os_circular_buffer cb; + /* Buffer provide by user. */ + int8_t *raw_buf; + /* Length of raw_buf */ + uint32_t raw_buf_len; + /* Set when this devices has buffer */ + bool initalized; + /* Set when no_os_calloc was used to initalize cb.buf */ + bool allocated; +}; + +/** + * @struct iio_dev_priv + * @brief Links a physical device instance "void *dev_instance" + * with a "iio_device *iio" that describes capabilities of the device. + */ +struct iio_dev_priv { + /** Will be: iio:device[0...n] n beeing the count of registerd devices*/ + char dev_id[MAX_DEV_ID]; + /** Device name */ + const char *name; + /** Physical instance of a device */ + void *dev_instance; + /** Structure to be passed to callbacks */ + struct iio_device_data dev_data; + /** Used to read debug attributes */ + uint32_t active_reg_addr; + /** Device descriptor(describes channels and attributes) */ + struct iio_device *dev_descriptor; + /* Structure storing buffer related fields */ + struct iio_buffer_priv buffer; + /* Set to -1 when no trigger is set*/ + uint32_t trig_idx; +}; + +/** + * @struct iio_trig_priv + * @brief Links a physical trigger instance "void *instance" + * with a "iio_trigger *descriptor" that describes capabilities of the trigger. + */ +struct iio_trig_priv { + /** Will be: iio:trigger[0...n] */ + char id[MAX_TRIG_ID]; + /** Trigger name */ + char *name; + /** Physical instance of a trigger */ + void *instance; + /** Trigger descriptor(describes type of trigger and its attributes) */ + struct iio_trigger *descriptor; + /** Set to true when the triggering condition is met */ + bool triggered; +}; + +struct iio_desc { + struct iiod_desc *iiod; + struct iiod_ops iiod_ops; + void *phy_desc; + char *xml_desc; + uint32_t xml_size; + struct iio_ctx_attr *ctx_attrs; + uint32_t nb_ctx_attr; + struct iio_dev_priv *devs; + uint32_t nb_devs; + struct iio_trig_priv *trigs; + uint32_t nb_trigs; + struct no_os_uart_desc *uart_desc; + int (*recv)(void *conn, uint8_t *buf, uint32_t len); + int (*send)(void *conn, uint8_t *buf, uint32_t len); + /* FIFO for socket descriptors */ + struct no_os_circular_buffer *conns; +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + struct tcp_socket_desc *current_sock; + /* Instance of server socket */ + struct tcp_socket_desc *server; +#endif +}; + +static inline int32_t _pop_conn(struct iio_desc *desc, uint32_t *conn_id) +{ + uint32_t size; + + no_os_cb_size(desc->conns, &size); + if (size < sizeof(uint32_t)) + return -EAGAIN; + + return no_os_cb_read(desc->conns, conn_id, sizeof(*conn_id)); +} + +static inline int32_t _push_conn(struct iio_desc *desc, uint32_t conn_id) +{ + return no_os_cb_write(desc->conns, &conn_id, sizeof(conn_id)); +} + +static inline int32_t _nb_active_conns(struct iio_desc *desc) +{ + uint32_t size; + + no_os_cb_size(desc->conns, &size); + + return size / sizeof(uint32_t); +} + + +static int iio_recv(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len) +{ + struct iio_desc *desc = ctx->instance; + + return desc->recv(ctx->conn, buf, len); +} + +static int iio_send(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len) +{ + struct iio_desc *desc = ctx->instance; + + return desc->send(ctx->conn, buf, len); +} + +static inline void _print_ch_id(char *buff, struct iio_channel *ch) +{ + if (ch->modified) { + sprintf(buff, "%s_%s", iio_chan_type_string[ch->ch_type], + iio_modifier_names[ch->channel2]); + } else { + if (ch->indexed) { + if (ch->diferential) + sprintf(buff, "%s%d-%s%d", iio_chan_type_string[ch->ch_type], + (int)ch->channel, iio_chan_type_string[ch->ch_type], + (int)ch->channel2); + else + sprintf(buff, "%s%d", iio_chan_type_string[ch->ch_type], + (int)ch->channel); + } else { + sprintf(buff, "%s", iio_chan_type_string[ch->ch_type]); + } + } +} + +/** + * @brief Get channel ID from a list of channels. + * @param channel - Channel name. + * @param desc - Device descriptor + * @param ch_out - If "true" is output channel, if "false" is input channel. + * @return Channel ID, or negative value if attribute is not found. + */ +static inline struct iio_channel *iio_get_channel(const char *channel, + struct iio_device *desc, bool ch_out) +{ + int16_t i = 0; + char ch_id[MAX_CHN_ID]; + + while (i < desc->num_ch) { + _print_ch_id(ch_id, &desc->channels[i]); + if (!strcmp(channel, ch_id) && + (desc->channels[i].ch_out == ch_out)) + return &desc->channels[i]; + i++; + } + + return NULL; +} + +/** + * @brief Find interface with "device_name". + * @param device_name - Device name. + * @param iio_dev_privs - List of interfaces. + * @return Interface pointer if interface is found, NULL otherwise. + */ +static struct iio_dev_priv *get_iio_device(struct iio_desc *desc, + const char *device_name) +{ + uint32_t i; + + for (i = 0; i < desc->nb_devs; i++) { + if (strcmp(desc->devs[i].dev_id, device_name) == 0) + return &desc->devs[i]; + } + + return NULL; +} + +/** + * @brief Find interface with "trigger_id". + * @param trigger_id - Trigger id (trigger0, trigger1, etc.). + * @param iio_trig_privs - List of interfaces. + * @return Interface pointer if interface is found, NULL otherwise. + */ +static struct iio_trig_priv *get_iio_trig_device(struct iio_desc *desc, + const char *trigger_id) +{ + uint32_t i; + + for (i = 0; i < desc->nb_trigs; i++) { + if (strcmp(desc->trigs[i].id, trigger_id) == 0) + return &desc->trigs[i]; + } + + return NULL; +} + +/** + * @brief Sets buffers count. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param buffers_count - Value to be set. + * @return Positive if index was set, negative if not. + */ +static int iio_set_buffers_count(struct iiod_ctx *ctx, const char *device, + uint32_t buffers_count) +{ + struct iio_desc *desc = ctx->instance; + + if (!get_iio_device(desc, device)) + return -ENODEV; + + /* Our implementation uses a circular buffer to send/receive data so + * only 1 is a valid value. + */ + if (buffers_count != 1) + return -EINVAL; + + return 0; +} + +/** + * @brief Read all attributes from an attribute list. + * @param device - Physical instance of a device. + * @param buf - Buffer where values are read. + * @param len - Maximum length of value to be stored in buf. + * @param channel - Channel properties. + * @param attributes - List of attributes to be read. + * @return Number of bytes read or negative value in case of error. + */ +static int iio_read_all_attr(struct attr_fun_params *params, + struct iio_attribute *attributes) +{ + /* TODO Not sure if working corectly */ + return -EINVAL; + +#if 0 + int16_t i = 0, j = 0; + char local_buf[256]; + int attr_length; + uint32_t *pattr_length; + + while (attributes[i].name) { + attr_length = attributes[i].show(params->dev_instance, + local_buf, params->len, + params->ch_info, + attributes[i].priv); + if (NO_OS_IS_ERR_VALUE(attr_length)) + attr_length = snprintf(local_buf, params->len, "%d", + attr_length); + + attr_length += 1;//Add '\0' to the count + pattr_length = (uint32_t *)(params->buf + j); + if (j + 4 > params->len) + return -EINVAL; + *pattr_length = no_os_bswap_constant_32(attr_length); + j += 4; + if (attr_length >= 0) { + if (attr_length + j > params->len) + return -EINVAL; + sprintf(params->buf + j, "%s", local_buf); + if (attr_length & 0x3) /* multiple of 4 */ + attr_length = ((attr_length >> 2) + 1) << 2; + j += attr_length; + } + i++; + } + if (j == 0) + return -ENOENT; + + return j; +#endif +} + +/** + * @brief Write all attributes from an attribute list. + * @param device - Physical instance of a device. + * @param buf - Values to be written. + * @param len - Length of buf. + * @param channel - Channel properties. + * @param attributes - List of attributes to be written. + * @return Number of written bytes or negative value in case of error. + */ +static int iio_write_all_attr(struct attr_fun_params *params, + struct iio_attribute *attributes) +{ + /* TODO Not sure if working corectly */ + return -EINVAL; + +#if 0 + int16_t i = 0, j = 0; + int16_t attr_length; + + while (attributes[i].name) { + attr_length = no_os_bswap_constant_32((uint32_t)(params->buf + j)); + j += 4; + attributes[i].store(params->dev_instance, (params->buf + j), + attr_length, params->ch_info, + attributes[i].priv); + j += attr_length; + if (j & 0x3) + j = ((j >> 2) + 1) << 2; + i++; + } + + if (params->len == 0) + return -ENOENT; + + return params->len; +#endif +} + +/** + * @brief Read/write attribute. + * @param params - Structure describing parameters for store and show functions + * @param attributes - Array of attributes. + * @param attr_name - Attribute name to be modified + * @param is_write -If it has value "1", writes attribute, otherwise reads + * attribute. + * @return Length of chars written/read or negative value in case of error. + */ +static int iio_rd_wr_attribute(struct attr_fun_params *params, + struct iio_attribute *attributes, + const char *attr_name, + bool is_write) +{ + int16_t i = 0; + + /* Search attribute */ + while (attributes[i].name) { + if (!strcmp(attr_name, attributes[i].name)) + break; + i++; + } + + if (!attributes[i].name) + return -ENOENT; + + if (is_write) { + if (!attributes[i].store) + return -ENOENT; + + return attributes[i].store(params->dev_instance, params->buf, + params->len, params->ch_info, + attributes[i].priv); + } else { + if (!attributes[i].show) + return -ENOENT; + return attributes[i].show(params->dev_instance, params->buf, + params->len, params->ch_info, + attributes[i].priv); + } +} + +/* Read a device register. The register address to read is set on + * in desc->active_reg_addr in the function set_demo_reg_attr + */ +static int32_t debug_reg_read(struct iio_dev_priv *dev, char *buf, uint32_t len) +{ + uint32_t value; + int32_t ret; + + value = 0; + ret = dev->dev_descriptor->debug_reg_read(dev->dev_instance, + dev->active_reg_addr, + &value); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return snprintf(buf, len, "%"PRIu32"", value); +} + +/* Flow of reading and writing registers. This is how iio works for + * direct_reg_access attribute: + * Read register: + * //Reg_addr in decimal + * reg_addr = "10"; + * 1. debug_reg_write(dev, reg_addr, len); + * 2. debug_reg_read(dev, out_buf, out_len); + * Write register: + * sprintf(write_buf, "0x%x 0x%x", reg_addr, value); + * 1. debug_reg_write(dev, write_buf,len); + */ +static int32_t debug_reg_write(struct iio_dev_priv *dev, const char *buf, + uint32_t len) +{ + uint32_t nb_filled; + uint32_t addr; + uint32_t value; + int32_t ret; + + nb_filled = sscanf(buf, "0x%"PRIx32" 0x%"PRIx32"", &addr, &value); + if (nb_filled == 2) { + /* Write register */ + ret = dev->dev_descriptor->debug_reg_write(dev->dev_instance, + addr, value); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + } else { + nb_filled = sscanf(buf, "%"PRIu32, &addr); + if (nb_filled == 1) { + dev->active_reg_addr = addr; + return len; + } else { + return -EINVAL; + } + } + + return len; +} + +static int32_t __iio_str_parse(char *buf, int32_t *integer, int32_t *_fract, + int32_t *_fract_scale, bool scale_db) +{ + char *p; + + p = strtok(buf, "."); + if (p == NULL) + return -EINVAL; + + *integer = strtol(p, NULL, 0); + + if (scale_db) { + p = strtok(NULL, "db"); + if (p == NULL) + p = strtok(NULL, " db"); + } else + p = strtok(NULL, "\n"); + + if (p == NULL) + return -EINVAL; + + *_fract = strtol(p, NULL, 10); + + /* Handle leading zeroes */ + while (*p++ == '0' && *_fract > 0) + *_fract_scale *= 10; + + /* Handle values between -1 and 0 */ + if (*integer == 0 && buf[0] == '-') + *_fract *= -1; + + return 0; +} + +static int32_t _iio_fract_interpret(int32_t fract, int32_t subunits) +{ + int32_t temp; + int32_t mult = 1; + + if (fract < 0) { + mult = -1; + fract = -fract; + } + + /* Divide to nearest subunit-scale if fract part is more than subunit */ + while (fract >= subunits) + fract = NO_OS_DIV_ROUND_CLOSEST(fract, 10); + + temp = fract; + + while ((subunits != 0) || (temp != 0)) { + temp /= 10; + subunits /= 10; + if (!temp) + break; + if (subunits <= 1) + fract /= 10; + } + + return fract * subunits * mult; +} + +int32_t iio_parse_value(char *buf, enum iio_val fmt, int32_t *val, + int32_t *val2) +{ + int32_t ret = 0; + int32_t integer, _fract = 0, _fract_scale = 1; + char ch; + + switch (fmt) { + case IIO_VAL_INT: + integer = strtol(buf, NULL, 0); + break; + case IIO_VAL_INT_PLUS_MICRO_DB: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, true); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale); + break; + case IIO_VAL_INT_PLUS_MICRO: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale); + break; + case IIO_VAL_INT_PLUS_NANO: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, + 1000000000 / _fract_scale); + break; + case IIO_VAL_FRACTIONAL: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + break; + case IIO_VAL_CHAR: + if (sscanf(buf, "%c", &ch) != 1) + return -EINVAL; + integer = ch; + break; + default: + return -EINVAL; + } + + if (val) + *val = integer; + if (val2) + *val2 = _fract; + + return ret; +} + +int iio_format_value(char *buf, uint32_t len, enum iio_val fmt, + int32_t size, int32_t *vals) +{ + int64_t tmp; + int32_t integer, fractional; + bool dB = false; + int32_t i = 0; + uint32_t l = 0; + + switch (fmt) { + case IIO_VAL_INT: + return snprintf(buf, len, "%"PRIi32"", vals[0]); + case IIO_VAL_INT_PLUS_MICRO_DB: + dB = true; + /* intentional fall through */ + case IIO_VAL_INT_PLUS_MICRO: + return snprintf(buf, len, "%s%"PRIi32".%06"PRIu32"%s", + vals[1] < 0 ? "-" : "", vals[0], + (uint32_t)vals[1], dB ? " dB" : ""); + case IIO_VAL_INT_PLUS_NANO: + return snprintf(buf, len, "%s%"PRIi32".%09"PRIu32"", + vals[1] < 0 ? "-" : "", vals[0], + (uint32_t)vals[1]); + case IIO_VAL_FRACTIONAL: + tmp = no_os_div_s64((int64_t)vals[0] * 1000000000LL, vals[1]); + fractional = vals[1]; + integer = (int32_t)no_os_div_s64_rem(tmp, 1000000000, &fractional); + + if (integer == 0 && fractional < 0) + return snprintf(buf, len, "-0.%09u", abs(fractional)); + + return snprintf(buf, len, "%"PRIi32".%09u", integer, + abs(fractional)); + case IIO_VAL_FRACTIONAL_LOG2: + tmp = no_os_shift_right((int64_t)vals[0] * 1000000000LL, vals[1]); + integer = (int32_t)no_os_div_s64_rem(tmp, 1000000000LL, &fractional); + + if (integer == 0 && fractional < 0) + return snprintf(buf, len, "-0.%09u", abs(fractional)); + + return snprintf(buf, len, "%"PRIi32".%09u", integer, + abs(fractional)); + case IIO_VAL_INT_MULTIPLE: { + while (i < size) { + l += snprintf(&buf[l], len - l, "%"PRIi32" ", vals[i]); + if (l >= len) + break; + i++; + } + return l; + } + case IIO_VAL_CHAR: + return snprintf(buf, len, "%c", (char)vals[0]); + default: + return 0; + } +} + +static struct iio_attribute *get_attributes(enum iio_attr_type type, + struct iio_dev_priv *dev, + struct iio_channel *ch) +{ + switch (type) { + case IIO_ATTR_TYPE_DEBUG: + return dev->dev_descriptor->debug_attributes; + break; + case IIO_ATTR_TYPE_DEVICE: + return dev->dev_descriptor->attributes; + break; + case IIO_ATTR_TYPE_BUFFER: + return dev->dev_descriptor->buffer_attributes; + break; + case IIO_ATTR_TYPE_CH_IN: + case IIO_ATTR_TYPE_CH_OUT: + return ch->attributes; + } + + return NULL; +} + +/** + * @brief Returns trigger attributes. + * @param type - Attribute type. + * @param trig - Trigger instance. + * @return Attributes pointer if attributes exist, NULL otherwise. + */ +static struct iio_attribute *get_trig_attributes(enum iio_attr_type type, + struct iio_trig_priv *trig) +{ + switch (type) { + /* Only device type attributes allowed for triggers */ + case IIO_ATTR_TYPE_DEVICE: + return trig->descriptor->attributes; + break; + default: + break; + } + + return NULL; +} + +/** + * @brief Read global attribute of a device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @param attr - String containing attribute name. + * @param buf - Buffer where value is read. + * @param len - Maximum length of value to be stored in buf. + * @return Number of bytes read. + */ +static int iio_read_attr(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig_dev; + struct iio_ch_info ch_info; + struct iio_channel *ch = NULL; + struct attr_fun_params params; + struct iio_attribute *attributes; + int8_t ch_out; + + dev = get_iio_device(ctx->instance, device); + + /* If IIO device with given name is found, handle reading of attributes */ + if (dev) { + if (attr->type == IIO_ATTR_TYPE_DEBUG && + strcmp(attr->name, REG_ACCESS_ATTRIBUTE) == 0) { + if (dev->dev_descriptor->debug_reg_read) + return debug_reg_read(dev, buf, len); + return -ENOENT; + } + + if (attr->channel[0] != '\0') { + ch_out = attr->type == IIO_ATTR_TYPE_CH_OUT ? 1 : 0; + ch = iio_get_channel(attr->channel, dev->dev_descriptor, + ch_out); + if (!ch) + return -ENOENT; + ch_info.ch_out = ch_out; + ch_info.ch_num = ch->channel; + ch_info.type = ch->ch_type; + ch_info.differential = ch->diferential; + ch_info.address = ch->address; + params.ch_info = &ch_info; + } else { + params.ch_info = NULL; + } + + params.buf = buf; + params.len = len; + params.dev_instance = dev->dev_instance; + attributes = get_attributes(attr->type, dev, ch); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 0); + } + + /* IIO device with given name is not found, verify if it corresponds to a trigger */ + trig_dev = get_iio_trig_device(ctx->instance, device); + + /* If IIO trigger with given name is found, handle reading of attributes */ + if (trig_dev) { + params.ch_info = NULL; /* Triggers cannot have channels */ + params.buf = buf; + params.len = len; + params.dev_instance = trig_dev->instance; + attributes = get_trig_attributes(attr->type, trig_dev); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 0); + } + + /* No device and no trigger with given name were found */ + return -ENODEV; +} + +/** + * @brief Write global attribute of a device. + * @param device - String containing device name. + * @param ctx - IIO instance and conn instance + * @param attr - String containing attribute name. + * @param buf - Value to be written. + * @param len - Length of data. + * @return Number of written bytes. + */ +static int iio_write_attr(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig_dev; + struct attr_fun_params params; + struct iio_attribute *attributes; + struct iio_ch_info ch_info; + struct iio_channel *ch = NULL; + int8_t ch_out; + + dev = get_iio_device(ctx->instance, device); + + /* If IIO device with given name is found, handle writing of attributes */ + if (dev) { + + if (attr->type == IIO_ATTR_TYPE_DEBUG && + strcmp(attr->name, REG_ACCESS_ATTRIBUTE) == 0) { + if (dev->dev_descriptor->debug_reg_write) + return debug_reg_write(dev, buf, len); + return -ENOENT; + } + + if (attr->channel[0] != '\0') { + ch_out = attr->type == IIO_ATTR_TYPE_CH_OUT ? 1 : 0; + ch = iio_get_channel(attr->channel, dev->dev_descriptor, + ch_out); + if (!ch) + return -ENOENT; + + ch_info.ch_out = ch_out; + ch_info.ch_num = ch->channel; + ch_info.type = ch->ch_type; + ch_info.differential = ch->diferential; + ch_info.address = ch->address; + params.ch_info = &ch_info; + } else { + params.ch_info = NULL; + } + + params.buf = (char *)buf; + params.len = len; + params.dev_instance = dev->dev_instance; + attributes = get_attributes(attr->type, dev, ch); + if (!strcmp(attr->name, "")) + return iio_write_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 1); + } + + /* IIO device with given name is not found, verify if it corresponds to a trigger */ + trig_dev = get_iio_trig_device(ctx->instance, device); + + /* If IIO trigger with given name is found, handle writing of attributes */ + if (trig_dev) { + params.ch_info = NULL; /* Triggers cannot have channels */ + params.buf = (char *)buf; + params.len = len; + params.dev_instance = trig_dev->instance; + attributes = get_trig_attributes(attr->type, trig_dev); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 1); + } + + /* No device and no trigger with given name were found */ + return -ENODEV; +} + +/** + * @brief Searches for trigger id and returns trigger index. + * @param desc - IIO descriptor. + * @param id - Trigger id (trigger0, trigger1, etc.). + * @return Trigger index. NO_TRIGGER in case trigger is not found. + */ +static uint32_t iio_get_trig_idx_by_id(struct iio_desc *desc, const char *id) +{ + uint32_t i; + + if (!id) + return NO_TRIGGER; + + for (i = 0; i < desc->nb_trigs; i++) + if (strcmp(desc->trigs[i].id, id) == 0) + return i; + + return NO_TRIGGER; +} + +/** + * @brief Searches for trigger name and returns trigger index. + * @param desc - IIO descriptor. + * @param name - Trigger name. + * @return Trigger index. NO_TRIGGER in case trigger is not found. + */ +static uint32_t iio_get_trig_idx_by_name(struct iio_desc *desc, + const char *name) +{ + uint32_t i; + + if (!name) + return NO_TRIGGER; + + for (i = 0; i < desc->nb_trigs; i++) + if (strcmp(desc->trigs[i].name, name) == 0) + return i; + + return NO_TRIGGER; +} + +/** + * @brief Searches for active trigger of the given device and returns trigger name. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param trigger - Trigger name to be returned. + * @param len - Maximum length of value to be stored in name. + * @return Number of bytes written in name. + */ +static int iio_get_trigger(struct iiod_ctx *ctx, const char *device, + char *trigger, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + struct iio_desc *desc = ctx->instance; + + if (!desc->nb_trigs) + return -ENOENT; + + trig = get_iio_trig_device(desc, device); + /* Device is a trigger and triggers cannot have other triggers */ + if (trig) + return -ENOENT; + + dev = get_iio_device(desc, device); + if (!dev) + return -ENODEV; + + if (dev->trig_idx == NO_TRIGGER) { + trigger[0] = '\0'; + + return 0; + } + + return snprintf(trigger, len, "%s", desc->trigs[dev->trig_idx].name); +} + +/** + * @brief Searches for given trigger id for the given device and if found, it + * sets the trigger. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param trigger - Trigger id to be set. + * @param len - Maximum length of value to be returned. + * @return Positive if index was set, negative if not. + */ +static int iio_set_trigger(struct iiod_ctx *ctx, const char *device, + const char *trigger, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + uint32_t i; + struct iio_desc *desc = ctx->instance; + + if (!desc->nb_trigs) + return -ENOENT; + + trig = get_iio_trig_device(desc, device); + /* Device is a trigger and triggers cannot have other triggers */ + if (trig) + return -ENOENT; + + dev = get_iio_device(desc, device); + if (!dev) + return -ENODEV; + + if (trigger[0] == '\0') { + dev->trig_idx = NO_TRIGGER; + return 0; + } + + i = iio_get_trig_idx_by_id(desc, trigger); + if (i == NO_TRIGGER) + return -EINVAL; + + dev->trig_idx = i; + + return len; +} + +/** + * @brief Asynchronous trigger processing routine. + * @param desc - IIO descriptor. + */ +static void iio_process_async_triggers(struct iio_desc *desc) +{ + struct iio_dev_priv *dev; + uint32_t i; + + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + if (dev->trig_idx == NO_TRIGGER) + continue; + + if (!desc->trigs[dev->trig_idx].triggered) + continue; + + if (dev->dev_descriptor->trigger_handler) { + dev->dev_descriptor->trigger_handler(&dev->dev_data); + desc->trigs[i].triggered = 0; + } + } +} + +/** + * @brief Searches for trigger name and processes the trigger based on its + * type (sync or async with the interrupt). + * @param desc - IIO descriptor. + * @param trigger_name - Trigger name. + * + * @return ret - Result of the processing procedure. + */ +int iio_process_trigger_type(struct iio_desc *desc, char *trigger_name) +{ + uint32_t i; + uint32_t trig_id; + struct iio_trig_priv *trig; + + trig_id = iio_get_trig_idx_by_name(desc, trigger_name); + + if (trig_id == NO_TRIGGER) + return -EINVAL; + + struct iio_dev_priv *dev; + + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + if (dev->trig_idx == trig_id) { + trig = &desc->trigs[trig_id]; + if (trig->descriptor->is_synchronous) { + if (dev->dev_descriptor->trigger_handler) + dev->dev_descriptor->trigger_handler(&dev->dev_data); + } else { + trig->triggered = 1; + } + } + } + + return 0; +} + +static uint32_t bytes_per_scan(struct iio_channel *channels, uint32_t mask) +{ + uint32_t cnt, i, length, largest = 1; + + cnt = 0; + i = 0; + while (mask) { + if ((mask & 1)) { + length = channels[i].scan_type->storagebits / 8; + + if (length > largest) + largest = length; + + if (cnt % length) + cnt += 2 * length - (cnt % length); + else + cnt += length; + } + + mask >>= 1; + ++i; + } + + if (cnt % largest) + cnt += largest - (cnt % largest); + + return cnt; +} + +/** + * @brief Open device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @param sample_size - Sample size. + * @param mask - Channels to be opened. + * @return 0, negative value in case of failure. + */ +static int iio_open_dev(struct iiod_ctx *ctx, const char *device, + uint32_t samples, uint32_t mask, bool cyclic) +{ + struct iio_desc *desc; + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + uint32_t ch_mask; + int32_t ret; + int8_t *buf; + uint32_t buf_size; + + dev = get_iio_device(ctx->instance, device); + if (!dev) + return -ENODEV; + + if (!dev->buffer.initalized) + return -EINVAL; + + ch_mask = 0xFFFFFFFF >> (32 - dev->dev_descriptor->num_ch); + mask &= ch_mask; + if (!mask) + return -ENOENT; + + dev->buffer.public.cyclic_info.is_cyclic = cyclic; + dev->buffer.public.cyclic_info.buff_index = 0; + + dev->buffer.public.active_mask = mask; + dev->buffer.public.bytes_per_scan = + bytes_per_scan(dev->dev_descriptor->channels, mask); + dev->buffer.public.size = dev->buffer.public.bytes_per_scan * samples; + dev->buffer.public.samples = samples; + if (dev->buffer.raw_buf && dev->buffer.raw_buf_len) { + if (dev->buffer.raw_buf_len < dev->buffer.public.size) + /* Need a bigger buffer or to allocate */ + return -ENOMEM; + buf_size = dev->buffer.raw_buf_len - (dev->buffer.raw_buf_len % + dev->buffer.public.size); + buf = dev->buffer.raw_buf; + } else { + if (dev->buffer.allocated) { + /* Free in case iio_close_dev wasn't called to free it*/ + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + buf_size = dev->buffer.public.size; + buf = (int8_t *)no_os_calloc(dev->buffer.public.size, sizeof(*buf)); + if (!buf) + return -ENOMEM; + dev->buffer.allocated = 1; + } + + ret = no_os_cb_cfg(&dev->buffer.cb, buf, buf_size); + if (NO_OS_IS_ERR_VALUE(ret)) { + if (dev->buffer.allocated) { + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + + return ret; + } + + if (dev->dev_descriptor->pre_enable) { + ret = dev->dev_descriptor->pre_enable(dev->dev_instance, mask); + if (NO_OS_IS_ERR_VALUE(ret)) { + if (dev->buffer.allocated) { + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + return ret; + } + } + + desc = ctx->instance; + if (dev->trig_idx != NO_TRIGGER) { + trig = &desc->trigs[dev->trig_idx]; + if (trig->descriptor->enable) + ret = trig->descriptor->enable(trig->instance); + } + + return ret; +} + +/** + * @brief Close device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @return 0, negative value in case of failure. + */ +static int iio_close_dev(struct iiod_ctx *ctx, const char *device) +{ + struct iio_desc *desc; + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + int ret = 0; + + dev = get_iio_device(ctx->instance, device); + if (!dev) + return -1; + + if (!dev->buffer.initalized) + return -EINVAL; + + if (dev->buffer.allocated) { + /* Should something else be used to free internal strucutre */ + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + + desc = ctx->instance; + if (dev->trig_idx != NO_TRIGGER) { + trig = &desc->trigs[dev->trig_idx]; + if (trig->descriptor->disable) { + ret = trig->descriptor->disable(trig->instance); + if (ret) + return ret; + } + } + + dev->buffer.public.active_mask = 0; + if (dev->dev_descriptor->post_disable) + ret = dev->dev_descriptor->post_disable(dev->dev_instance); + + return ret; +} + +static int iio_call_submit(struct iiod_ctx *ctx, const char *device, + enum iio_buffer_direction dir) +{ + struct iio_dev_priv *dev; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + dev->buffer.public.dir = dir; + if (dev->dev_descriptor->submit && dev->trig_idx == NO_TRIGGER) + return dev->dev_descriptor->submit(&dev->dev_data); + else if ((dir == IIO_DIRECTION_INPUT && dev->dev_descriptor->read_dev + && dev->trig_idx == NO_TRIGGER) + || (dir == IIO_DIRECTION_OUTPUT && + dev->dev_descriptor->write_dev && dev->trig_idx == NO_TRIGGER)) { + /* Code used to don't break devices using read_dev */ + int32_t ret; + void *buff; + struct iio_buffer *buffer = &dev->buffer.public; + + ret = iio_buffer_get_block(buffer, &buff); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + if (dir == IIO_DIRECTION_INPUT) + ret = dev->dev_descriptor->read_dev(dev->dev_instance, + buff, buffer->samples); + else + ret = dev->dev_descriptor->write_dev(dev->dev_instance, + buff, buffer->samples); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return iio_buffer_block_done(buffer); + } + + return 0; +} + +static int iio_push_buffer(struct iiod_ctx *ctx, const char *device) +{ + return iio_call_submit(ctx, device, IIO_DIRECTION_OUTPUT); +} + +static int iio_refill_buffer(struct iiod_ctx *ctx, const char *device) +{ + return iio_call_submit(ctx, device, IIO_DIRECTION_INPUT); +} + +/** + * @brief Read chunk of data from RAM to pbuf. Call + * "iio_transfer_dev_to_mem()" first. + * @param device - String containing device name. + * @param pbuf - Buffer where value is stored. + * @param offset - Offset to the remaining data after reading n chunks. + * @param bytes_count - Number of bytes to read. + * @return: Bytes_count or negative value in case of error. + */ +static int iio_read_buffer(struct iiod_ctx *ctx, const char *device, char *buf, + uint32_t bytes) +{ + struct iio_dev_priv *dev; + int32_t ret; + uint32_t size; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + ret = no_os_cb_size(&dev->buffer.cb, &size); +#ifdef IIO_IGNORE_BUFF_OVERRUN_ERR +#warning Buffer overrun error checking is disabled. + if (ret != -NO_OS_EOVERRUN) +#endif + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + bytes = no_os_min(size, bytes); + if (!bytes) + return -EAGAIN; + + + ret = no_os_cb_read(&dev->buffer.cb, buf, bytes); +#ifdef IIO_IGNORE_BUFF_OVERRUN_ERR + if (ret != -NO_OS_EOVERRUN) +#endif + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return bytes; +} + + +/** + * @brief Write chunk of data into RAM. + * @param device - String containing device name. + * @param buf - Values to write. + * @param offset - Offset in memory after the nth chunk of data. + * @param bytes_count - Number of bytes to write. + * @return Bytes_count or negative value in case of error. + */ +static int iio_write_buffer(struct iiod_ctx *ctx, const char *device, + const char *buf, uint32_t bytes) +{ + struct iio_dev_priv *dev; + int32_t ret; + uint32_t available; + uint32_t size; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + ret = no_os_cb_size(&dev->buffer.cb, &size); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + available = dev->buffer.public.size - size; + bytes = no_os_min(available, bytes); + ret = no_os_cb_write(&dev->buffer.cb, buf, bytes); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return bytes; +} + +int iio_buffer_get_block(struct iio_buffer *buffer, void **addr) +{ + uint32_t size; + + if (!buffer) + return -EINVAL; + + if (buffer->dir == IIO_DIRECTION_INPUT) + return no_os_cb_prepare_async_write(buffer->buf, buffer->size, addr, &size); + + return no_os_cb_prepare_async_read(buffer->buf, buffer->size, addr, &size); +} + +int iio_buffer_block_done(struct iio_buffer *buffer) +{ + if (!buffer) + return -EINVAL; + + if (buffer->dir == IIO_DIRECTION_INPUT) + return no_os_cb_end_async_write(buffer->buf); + + return no_os_cb_end_async_read(buffer->buf); +} + +/* Write to buffer iio_buffer.bytes_per_scan bytes from data */ +int iio_buffer_push_scan(struct iio_buffer *buffer, void *data) +{ + if (!buffer) + return -EINVAL; + + return no_os_cb_write(buffer->buf, data, buffer->bytes_per_scan); +} + +/* Read from buffer iio_buffer.bytes_per_scan bytes into data */ +int iio_buffer_pop_scan(struct iio_buffer *buffer, void *data) +{ + if (!buffer) + return -EINVAL; + + int ret; + + ret = no_os_cb_read(buffer->buf, data, buffer->bytes_per_scan); + + if (buffer->cyclic_info.is_cyclic) { + if (buffer->buf->read.idx == buffer->buf->write.idx) + buffer->buf->read.idx = 0; + } + + return ret; +} + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + +static int32_t accept_network_clients(struct iio_desc *desc) +{ + struct tcp_socket_desc *sock; + struct iiod_conn_data data; + int32_t ret; + uint32_t id; + + do { + ret = socket_accept(desc->server, &sock); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + data.conn = sock; + data.buf = no_os_calloc(1, IIOD_CONN_BUFFER_SIZE); + data.len = IIOD_CONN_BUFFER_SIZE; + + if (!data.buf) { + ret = -ENOMEM; + goto close_socket; + } + + ret = iiod_conn_add(desc->iiod, &data, &id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_buf; + + ret = _push_conn(desc, id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto remove_conn; + } while (true); + + return 0; + +remove_conn: + iiod_conn_remove(desc->iiod, id, &data); +free_buf: + no_os_free(data.buf); +close_socket: + socket_remove(sock); + + return ret; +} +#endif + +/** + * @brief Execute an iio step + * @param desc - IIo descriptor + * @return 0 in case of success or negative value otherwise. + */ +int iio_step(struct iio_desc *desc) +{ + struct iiod_conn_data data; + uint32_t conn_id; + int32_t ret; + + iio_process_async_triggers(desc); + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + if (desc->server) { + ret = accept_network_clients(desc); + if (NO_OS_IS_ERR_VALUE(ret) && ret != -EAGAIN) + return ret; +#if defined(NO_OS_LWIP_NETWORKING) + no_os_lwip_step(desc->server->net->net, desc->server->net->net); +#endif + } +#endif + + ret = _pop_conn(desc, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + ret = iiod_conn_step(desc->iiod, conn_id); + if (ret == -ENOTCONN) { +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + iiod_conn_remove(desc->iiod, conn_id, &data); + socket_remove(data.conn); + no_os_free(data.buf); +#endif + } else { + _push_conn(desc, conn_id); + } + + return ret; +} + +/** + * @brief Add context attributes into xml string buffer. + * @param desc - IIo descriptor. + * @param buff - xml buffer. + * @param buff_size - size of buffer + * @return 0 in case of success or negative value otherwise. + */ +static uint32_t iio_add_ctx_attr_in_xml(struct iio_desc *desc, char *buff, + uint32_t buff_size) +{ + struct iio_ctx_attr *attr; + char dummy_buff[50]; + int32_t i; + int32_t j; + int32_t n; + + if ((int32_t)buff_size == -1) + n = 0; + else + n = buff_size; + + if (buff == NULL) + /* Set dummy value for buff. It is used only for counting */ + buff = dummy_buff; + + i = 0; + + attr = desc->ctx_attrs; + if (attr) + for (j = 0; j < (int32_t)desc->nb_ctx_attr; j++) { + i += snprintf(buff + i, + no_os_max(n - i, 0), + "", + attr[j].value); + } + + return i; +} + +/* + * Generate an xml describing a device and write it to buff. + * Will return the size of the xml. + * If buff_size is 0, no data will be written to buff, but size will be returned + */ +static uint32_t iio_generate_device_xml(struct iio_device *device, char *name, + char *id, char *buff, + uint32_t buff_size) +{ + struct iio_channel *ch; + struct iio_attribute *attr; + char ch_id[50]; + int32_t i; + int32_t j; + int32_t k; + int32_t n; + + if ((int32_t)buff_size == -1) + n = 0; + else + n = buff_size; + + if (buff == NULL) + /* Set dummy value for buff. It is used only for counting */ + buff = ch_id; + + i = 0; + + i += snprintf(buff + i, no_os_max(n - i, 0), + "", id, name); + + /* Write channels */ + if (device->channels) + for (j = 0; j < device->num_ch; j++) { + ch = &device->channels[j]; + _print_ch_id(ch_id, ch); + i += snprintf(buff + i, no_os_max(n - i, 0), + "name) + i += snprintf(buff + i, no_os_max(n - i, 0), + " name=\"%s\"", + ch->name); + i += snprintf(buff + i, no_os_max(n - i, 0), + " type=\"%s\" >", + ch->ch_out ? "output" : "input"); + + if (ch->scan_type) + i += snprintf(buff + i, no_os_max(n - i, 0), + ">%d\" />", + ch->scan_index, + ch->scan_type->is_big_endian ? "be" : "le", + ch->scan_type->sign, + ch->scan_type->realbits, + ch->scan_type->storagebits, + ch->scan_type->shift); + + /* Write channel attributes */ + if (ch->attributes) + for (k = 0; ch->attributes[k].name; k++) { + attr = &ch->attributes[k]; + i += snprintf(buff + i, no_os_max(n - i, 0), "name); + if (ch->diferential) { + switch (attr->shared) { + case IIO_SHARED_BY_ALL: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s\"", + attr->name); + break; + case IIO_SHARED_BY_DIR: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s\"", + ch->ch_out ? "out" : "in", + attr->name); + break; + case IIO_SHARED_BY_TYPE: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s-%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + iio_chan_type_string[ch->ch_type], + attr->name); + break; + case IIO_SEPARATE: + if (!ch->indexed) { + // Differential channels must be indexed! + return -EINVAL; + } + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s%d-%s%d_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + ch->channel, + iio_chan_type_string[ch->ch_type], + ch->channel2, + attr->name); + break; + } + } else { + switch (attr->shared) { + case IIO_SHARED_BY_ALL: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s\"", + attr->name); + break; + case IIO_SHARED_BY_DIR: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s\"", + ch->ch_out ? "out" : "in", + attr->name); + break; + case IIO_SHARED_BY_TYPE: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + attr->name); + break; + case IIO_SEPARATE: + if (ch->indexed) + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s%d_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + ch->channel, + attr->name); + else + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + attr->name); + break; + } + } + i += snprintf(buff + i, no_os_max(n - i, 0), " />"); + } + + i += snprintf(buff + i, no_os_max(n - i, 0), ""); + } + + /* Write device attributes */ + if (device->attributes) + for (j = 0; device->attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->attributes[j].name); + + /* Write debug attributes */ + if (device->debug_attributes) + for (j = 0; device->debug_attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->debug_attributes[j].name); + if (device->debug_reg_read || device->debug_reg_write) + i += snprintf(buff + i, no_os_max(n - i, 0), + ""); + + /* Write buffer attributes */ + if (device->buffer_attributes) + for (j = 0; device->buffer_attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->buffer_attributes[j].name); + + i += snprintf(buff + i, no_os_max(n - i, 0), ""); + + return i; +} + +static int32_t iio_init_xml(struct iio_desc *desc) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + struct iio_device dummy = { 0 }; + uint32_t i, size, of; + + /* -2 because of the 0 character */ + size = sizeof(header) + sizeof(header_end) - 2; + size += iio_add_ctx_attr_in_xml(desc, NULL, -1); + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + size += iio_generate_device_xml(dev->dev_descriptor, + (char *)dev->name, + dev->dev_id, NULL, -1); + } + for (i = 0; i < desc->nb_trigs; i++) { + trig = desc->trigs + i; + dummy.attributes = trig->descriptor->attributes; + size += iio_generate_device_xml(&dummy, trig->name, trig->id, + NULL, -1); + } + + desc->xml_desc = (char *)no_os_calloc(size + 1, sizeof(*desc->xml_desc)); + if (!desc->xml_desc) + return -ENOMEM; + + desc->xml_size = size; + + strcpy(desc->xml_desc, header); + of = sizeof(header) - 1; + of += iio_add_ctx_attr_in_xml(desc, desc->xml_desc + of, size - of); + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + of += iio_generate_device_xml(dev->dev_descriptor, + (char *)dev->name, dev->dev_id, + desc->xml_desc + of, size - of); + } + for (i = 0; i < desc->nb_trigs; i++) { + trig = desc->trigs + i; + dummy.attributes = trig->descriptor->attributes; + of += iio_generate_device_xml(&dummy, trig->name, trig->id, + desc->xml_desc + of, size - of); + } + + strcpy(desc->xml_desc + of, header_end); + + return 0; +} + +static int32_t iio_init_devs(struct iio_desc *desc, + struct iio_device_init *devs, uint32_t n) +{ + uint32_t i; + struct iio_dev_priv *ldev; + struct iio_device_init *ndev; + + desc->nb_devs = n; + desc->devs = (struct iio_dev_priv *)no_os_calloc(desc->nb_devs, + sizeof(*desc->devs)); + if (!desc->devs) + return -ENOMEM; + + for (i = 0; i < n; i++) { + ndev = devs + i; + ldev = desc->devs + i; + ldev->dev_descriptor = ndev->dev_descriptor; + sprintf(ldev->dev_id, "iio:device%"PRIu32"", i); + ldev->trig_idx = iio_get_trig_idx_by_id(desc, ndev->trigger_id); + ldev->dev_instance = ndev->dev; + ldev->dev_data.dev = ndev->dev; + ldev->dev_data.buffer = &ldev->buffer.public; + ldev->name = ndev->name; + if (ndev->dev_descriptor->read_dev || + ndev->dev_descriptor->write_dev || + ndev->dev_descriptor->submit || + ndev->dev_descriptor->trigger_handler) { + ldev->buffer.raw_buf = ndev->raw_buf; + ldev->buffer.raw_buf_len = ndev->raw_buf_len; + ldev->buffer.public.buf = &ldev->buffer.cb; + ldev->buffer.initalized = 1; + } else { + ldev->buffer.initalized = 0; + } + } + + return 0; +} + +/** + * @brief Initializes IIO triggers. + * @param desc - IIO descriptor. + * @param trigs - Triggers array. + * @param n - Number of triggers to be initialized. + * @return 0 in case of success or negative value otherwise. + */ +static int32_t iio_init_trigs(struct iio_desc *desc, + struct iio_trigger_init *trigs, uint32_t n) +{ + uint32_t i; + struct iio_trig_priv *trig_priv_iter; + struct iio_trigger_init *trig_init_iter; + + desc->nb_trigs = n; + desc->trigs = (struct iio_trig_priv *)no_os_calloc(desc->nb_trigs, + sizeof(*desc->trigs)); + if (!desc->trigs) + return -ENOMEM; + + for (i = 0; i < n; i++) { + trig_init_iter = trigs + i; + trig_priv_iter = desc->trigs + i; + trig_priv_iter->instance = trig_init_iter->trig; + trig_priv_iter->name = trig_init_iter->name; + trig_priv_iter->descriptor = trig_init_iter->descriptor; + sprintf(trig_priv_iter->id, "trigger%"PRIu32"", i); + } + + return 0; +} + +/** + * @brief Set communication ops and read/write ops + * @param desc - iio descriptor. + * @param init_param - appropriate init param. + * @return 0 in case of success or negative value otherwise. + */ +int iio_init(struct iio_desc **desc, struct iio_init_param *init_param) +{ + int32_t ret; + struct iio_desc *ldesc; + struct iiod_ops *ops; + struct iiod_init_param iiod_param; + uint32_t conn_id; + + if (!desc || !init_param) + return -EINVAL; + + ldesc = (struct iio_desc *)no_os_calloc(1, sizeof(*ldesc)); + if (!ldesc) + return -ENOMEM; + + ldesc->ctx_attrs = init_param->ctx_attrs; + ldesc->nb_ctx_attr = init_param->nb_ctx_attr; + + ret = iio_init_trigs(ldesc, init_param->trigs, init_param->nb_trigs); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_devs; + + ret = iio_init_devs(ldesc, init_param->devs, init_param->nb_devs); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_desc; + + ret = iio_init_xml(ldesc); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_trigs; + + /* device operations */ + ops = &ldesc->iiod_ops; + ops->read_attr = iio_read_attr; + ops->write_attr = iio_write_attr; + ops->get_trigger = iio_get_trigger; + ops->set_trigger = iio_set_trigger; + ops->read_buffer = iio_read_buffer; + ops->write_buffer = iio_write_buffer; + ops->refill_buffer = iio_refill_buffer; + ops->push_buffer = iio_push_buffer; + ops->open = iio_open_dev; + ops->close = iio_close_dev; + ops->send = iio_send; + ops->recv = iio_recv; + ops->set_buffers_count = iio_set_buffers_count; + + iiod_param.instance = ldesc; + iiod_param.ops = ops; + iiod_param.xml = ldesc->xml_desc; + iiod_param.xml_len = ldesc->xml_size; + iiod_param.phy_type = init_param->phy_type; + + ret = iiod_init(&ldesc->iiod, &iiod_param); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_xml; + + ret = no_os_cb_init(&ldesc->conns, + sizeof(uint32_t) * (IIOD_MAX_CONNECTIONS + 1)); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_iiod; + + if (init_param->phy_type == USE_UART) { + ldesc->send = (int (*)())no_os_uart_write; + ldesc->recv = (int (*)())no_os_uart_read; + ldesc->uart_desc = init_param->uart_desc; + + struct iiod_conn_data data = { + .conn = ldesc->uart_desc, + .buf = uart_buff, + .len = sizeof(uart_buff) + }; + ret = iiod_conn_add(ldesc->iiod, &data, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + _push_conn(ldesc, conn_id); + } +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + else if (init_param->phy_type == USE_NETWORK) { + ldesc->send = (int (*)())socket_send; + ldesc->recv = (int (*)())socket_recv; + ret = socket_init(&ldesc->server, + init_param->tcp_socket_init_param); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + ret = socket_bind(ldesc->server, IIOD_PORT); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_pylink; + ret = socket_listen(ldesc->server, MAX_BACKLOG); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_pylink; + } +#endif + else if (init_param->phy_type == USE_LOCAL_BACKEND) { + ldesc->recv = init_param->local_backend->local_backend_event_read; + ldesc->send = init_param->local_backend->local_backend_event_write; + + struct iiod_conn_data data = { + .conn = NULL, + .buf = init_param->local_backend->local_backend_buff, + .len = init_param->local_backend->local_backend_buff_len + }; + ret = iiod_conn_add(ldesc->iiod, &data, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + _push_conn(ldesc, conn_id); + } else { + ret = -EINVAL; + goto free_conns; + } + + *desc = ldesc; + + return 0; + +free_pylink: +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + socket_remove(ldesc->server); +#endif +free_conns: + no_os_cb_remove(ldesc->conns); +free_iiod: + iiod_remove(ldesc->iiod); +free_xml: + no_os_free(ldesc->xml_desc); +free_trigs: + no_os_free(ldesc->trigs); +free_devs: + no_os_free(ldesc->devs); +free_desc: + no_os_free(ldesc); + + return ret; +} + +/** + * @brief Free the resources allocated by "iio_init()". + * @param desc: iio descriptor. + * @return 0 in case of success or negative value otherwise. + */ +int iio_remove(struct iio_desc *desc) +{ + struct iiod_conn_data data; + int ret; + + if (!desc) + return -EINVAL; + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + for (int i = 0; i < IIOD_MAX_CONNECTIONS; i++) { + ret = iiod_conn_remove(desc->iiod, i, &data); + if (!ret) { + no_os_free(data.buf); + socket_remove(data.conn); + } + } + socket_remove(desc->server); +#endif + no_os_cb_remove(desc->conns); + iiod_remove(desc->iiod); + no_os_free(desc->devs); + no_os_free(desc->trigs); + no_os_free(desc->xml_desc); + no_os_free(desc); + + return 0; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.h new file mode 100644 index 0000000..c277acb --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.h @@ -0,0 +1,143 @@ +/***************************************************************************//** + * @file iio.h + * @brief Header file of iio + * @author Cristian Pop (cristian.pop@analog.com) + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2013(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef IIO_H_ +#define IIO_H_ + +#include "iio_types.h" +#include "no_os_uart.h" +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) +#include "tcp_socket.h" +#endif + +enum physical_link_type { + USE_UART, + USE_LOCAL_BACKEND, + USE_NETWORK +}; + +struct iio_desc; + +struct iio_device_init { + char *name; + void *dev; + struct iio_device *dev_descriptor; + /* + * IIO buffer implementation can use a user provided buffer in raw_buf. + * If raw_buf is NULL and iio_device has buffer callback function set, + * it will allocate memory for it when needed. + */ + int8_t *raw_buf; + /* Length of raw_buf */ + uint32_t raw_buf_len; + /* If set, trigger will be linked to this device */ + char *trigger_id; +}; + +struct iio_trigger_init { + char *name; + void *trig; + struct iio_trigger *descriptor; +}; + +/** + * @struct iio_ctx_attr + * @brief Structure holding the context attribute members + */ +struct iio_ctx_attr { + /** Attribute name */ + const char *name; + /** Attribute value */ + const char *value; +}; + +/** + * @struct iio_local_backend + * @brief Structure holding the local backend init parameters + */ +struct iio_local_backend { + int(*local_backend_event_read)(void *conn, uint8_t *buf, uint32_t len); + int(*local_backend_event_write)(void *conn, uint8_t *buf, uint32_t len); + char *local_backend_buff; + uint32_t local_backend_buff_len; +}; + +struct iio_init_param { + enum physical_link_type phy_type; + union { + struct no_os_uart_desc *uart_desc; +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + struct tcp_socket_init_param *tcp_socket_init_param; +#endif + }; + struct iio_local_backend *local_backend; + struct iio_ctx_attr *ctx_attrs; + uint32_t nb_ctx_attr; + struct iio_device_init *devs; + uint32_t nb_devs; + struct iio_trigger_init *trigs; + uint32_t nb_trigs; +}; + +/* Set communication ops and read/write ops. */ +int iio_init(struct iio_desc **desc, struct iio_init_param *init_param); +/* Free the resources allocated by iio_init(). */ +int iio_remove(struct iio_desc *desc); +/* Execut an iio step. */ +int iio_step(struct iio_desc *desc); +/* Signal iio that a trigger has been triggered. + * This will be called in interrupt context. An application callback will be + called in interrupt context if trigger is synchronous with the interrupt + (is_synchronous = true) or will be called from iio_step if trigger is + asynchronous (is_synchronous = false) */ +int iio_process_trigger_type(struct iio_desc *desc, char *trigger_name); + +int32_t iio_parse_value(char *buf, enum iio_val fmt, + int32_t *val, int32_t *val2); +int iio_format_value(char *buf, uint32_t len, enum iio_val fmt, + int32_t size, int32_t *vals); + +/* DMA buffer functions. */ +/* Get buffer addr where to write iio_buffer.size bytes */ +int iio_buffer_get_block(struct iio_buffer *buffer, void **addr); +/* To be called to mark last iio_buffer_read as done */ +int iio_buffer_block_done(struct iio_buffer *buffer); + +/* Trigger buffer functions. */ +/* Write to buffer iio_buffer.bytes_per_scan bytes from data */ +int iio_buffer_push_scan(struct iio_buffer *buffer, void *data); +/* Read from buffer iio_buffer.bytes_per_scan bytes into data */ +int iio_buffer_pop_scan(struct iio_buffer *buffer, void *data); + +#endif /* IIO_H_ */ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.c new file mode 100644 index 0000000..5840788 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.c @@ -0,0 +1,475 @@ +/***************************************************************************//** + * @file iio_app.c + * @brief C file of iio_app + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifdef IIO_SUPPORT + +#include +#include +#include "iio_app.h" +#include "parameters.h" +#include "no_os_alloc.h" + +#if defined(ADUCM_PLATFORM) +#include "aducm3029_uart.h" +#include "aducm3029_irq.h" +#endif +#if defined(XILINX_PLATFORM) +#include "xilinx_uart.h" +#include "xilinx_irq.h" +#endif +#if defined(STM32_PLATFORM) +#include +#include "stm32_uart.h" +#include "stm32_irq.h" +#endif +#if defined(MAXIM_PLATFORM) +#include "maxim_irq.h" +#include "maxim_uart.h" +#endif + +#ifdef NO_OS_NETWORKING +/* Fix: Use static buffers instead of calloc for new connections */ +#warning "iio may not work with WIFI on aducm3029." +#ifdef ADUCM_PLATFORM +#include "wifi.h" +#endif +#include "tcp_socket.h" +#endif + +#ifdef LINUX_PLATFORM +#include "linux_socket.h" +#include "tcp_socket.h" +#endif + +#ifdef NO_OS_LWIP_NETWORKING +#include "lwip_socket.h" +#endif + +// The default baudrate iio_app will use to print messages to console. +#define UART_BAUDRATE_DEFAULT 115200 +#define UART_STOPBITS_DEFAULT NO_OS_UART_STOP_1_BIT + +static inline uint32_t _calc_uart_xfer_time(uint32_t len, uint32_t baudrate) +{ + uint32_t ms = 1000ul * len * 8 / UART_BAUDRATE_DEFAULT; + ms += ms / 10; // overhead + return ms; +} + +#if !defined(LINUX_PLATFORM) && !defined(NO_OS_NETWORKING) && !defined(NO_OS_USB_UART) +static int32_t iio_print_uart_info_message(struct no_os_uart_desc **uart_desc, + struct no_os_uart_init_param *user_uart_params, + char *message, int32_t msglen) +{ + int32_t status; + uint32_t delay_ms; + + status = no_os_uart_write(*uart_desc, (uint8_t *)message, msglen); + if (status < 0) + return status; + + delay_ms = _calc_uart_xfer_time(msglen, UART_BAUDRATE_DEFAULT); + no_os_mdelay(delay_ms); + + /** Reinitialize UART with parameters required by the IIO application */ + no_os_uart_remove(*uart_desc); + return no_os_uart_init(uart_desc, user_uart_params); +} +#endif + +static int32_t print_uart_hello_message(struct no_os_uart_desc **uart_desc, + struct no_os_uart_init_param *user_uart_params) +{ +#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART) + return 0; +#else + const char *uart_data_size[] = { "5", "6", "7", "8", "9" }; + const char *uart_parity[] = { "none", "mark", "space", "odd", "even" }; + const char *uart_stop[] = { "1", "2" }; + char message[512]; + uint32_t msglen = sprintf(message, + "Running IIOD server...\n" + "If successful, you may connect an IIO client application by:\n" + "1. Disconnecting the serial terminal you use to view this message.\n" + "2. Connecting the IIO client application using the serial backend configured as shown:\n" + "\tBaudrate: %lu\n" + "\tData size: %s bits\n" + "\tParity: %s\n" + "\tStop bits: %s\n" + "\tFlow control: none\n", + user_uart_params->baud_rate, + uart_data_size[user_uart_params->size], + uart_parity[user_uart_params->parity], + uart_stop[user_uart_params->stop]); + + return iio_print_uart_info_message(uart_desc, user_uart_params, + message, msglen); +#endif +} + +static int32_t print_uart_error_message(struct no_os_uart_desc **uart_desc, + struct no_os_uart_init_param *user_uart_params, + int32_t status) +{ + char message[512]; + uint32_t msglen = sprintf(message, + "IIOD server failed with code %d.\n", + (int)status); +#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART) + (void)msglen; + printf("%s", message); + return 0; +#else + return iio_print_uart_info_message(uart_desc, user_uart_params, + message, msglen); +#endif +} + +#if defined(NO_OS_LWIP_NETWORKING) +static int32_t lwip_network_setup(struct iio_app_desc *app, + struct iio_app_init_param param, + struct iio_init_param *iio_init_param) +{ + static struct tcp_socket_init_param socket_param; + static struct lwip_network_desc lwip_desc; + static bool is_initialized = false; + int ret; + + if (NO_OS_LWIP_INIT_ONETIME && is_initialized) { + socket_param.net = &lwip_desc.no_os_net; + } else { + ret = no_os_lwip_init(&app->lwip_desc, ¶m.lwip_param); + if (ret) + return ret; + + socket_param.net = &app->lwip_desc->no_os_net; + memcpy(&lwip_desc, app->lwip_desc, sizeof(lwip_desc)); + } + + is_initialized = true; + socket_param.max_buff_size = 0; + + iio_init_param->phy_type = USE_NETWORK; + iio_init_param->tcp_socket_init_param = &socket_param; + + return 0; +} +#endif + +#if defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM) +static int32_t network_setup(struct iio_init_param *iio_init_param, + struct no_os_uart_desc *uart_desc, + void *irq_desc) +{ + static struct tcp_socket_init_param socket_param; + +#ifdef LINUX_PLATFORM + socket_param.net = &linux_net; +#endif +#ifdef ADUCM_PLATFORM + int32_t status; + static struct wifi_desc *wifi; + struct wifi_init_param wifi_param = { + .irq_desc = irq_desc, + .uart_desc = uart_desc, + .uart_irq_conf = uart_desc, + .uart_irq_id = UART_IRQ_ID, + .sw_reset_en = true + }; + status = wifi_init(&wifi, &wifi_param); + if (status < 0) + return status; + + status = wifi_connect(wifi, WIFI_SSID, WIFI_PWD); + if (status < 0) + return status; + + char buff[100]; + wifi_get_ip(wifi, buff, 100); + printf("iiod ip is: %s\n", buff); + + wifi_get_network_interface(wifi, &socket_param.net); +#endif + + socket_param.max_buff_size = 0; + iio_init_param->phy_type = USE_NETWORK; + iio_init_param->tcp_socket_init_param = &socket_param; + + return 0; +} +#endif + +static int32_t uart_setup(struct no_os_uart_desc **uart_desc, + struct no_os_uart_init_param *uart_init_par) +{ +#if defined(LINUX_PLATFORM) || defined(NO_OS_LWIP_NETWORKING) + *uart_desc = NULL; + return 0; +#endif + struct no_os_uart_init_param luart_par = { + .device_id = uart_init_par->device_id, + /* TODO: remove this ifdef when asynchrounous rx is implemented on every platform. */ +#if defined(STM32_PLATFORM) || defined(MAXIM_PLATFORM) || defined(ADUCM_PLATFORM) || defined(PICO_PLATFORM) + .irq_id = uart_init_par->irq_id, + .asynchronous_rx = true, +#endif + .baud_rate = UART_BAUDRATE_DEFAULT, + .size = NO_OS_UART_CS_8, + .parity = NO_OS_UART_PAR_NO, + .stop = NO_OS_UART_STOP_1_BIT, + .platform_ops = uart_init_par->platform_ops, +#ifndef ADUCM_PLATFORM + .extra = uart_init_par->extra +#endif + }; + + return no_os_uart_init(uart_desc, &luart_par); +} + +#if defined(ADUCM_PLATFORM) || (defined(STM32_PLATFORM)) || defined(MAXIM_PLATFORM) +static int32_t irq_setup(struct no_os_irq_ctrl_desc **irq_desc) +{ + int32_t status; +#if defined(ADUCM_PLATFORM) + void *platform_irq_init_par = NULL; + const struct no_os_irq_platform_ops *platform_irq_ops = &aducm_irq_ops; +#elif defined(STM32_PLATFORM) + void *platform_irq_init_par = NULL; + const struct no_os_irq_platform_ops *platform_irq_ops = &stm32_irq_ops; +#elif defined(MAXIM_PLATFORM) + void *platform_irq_init_par = NULL; + const struct no_os_irq_platform_ops *platform_irq_ops = &max_irq_ops; +#endif + + struct no_os_irq_init_param irq_init_param = { + .irq_ctrl_id = INTC_DEVICE_ID, + .platform_ops = platform_irq_ops, + .extra = platform_irq_init_par + }; + + status = no_os_irq_ctrl_init(irq_desc, &irq_init_param); + if (status < 0) + return status; + + return no_os_irq_global_enable(*irq_desc); +} +#endif + +/** + * @brief Register devices for an iio application + * + * Configuration for communication is done in parameters.h + * @param app - the iio application descriptor + * @param app_init_param - the iio application initialization parameters + * @return 0 on success, negative value otherwise + */ +int iio_app_init(struct iio_app_desc **app, + struct iio_app_init_param app_init_param) +{ + struct iio_device_init *iio_init_devs = NULL; + struct iio_init_param iio_init_param; + struct no_os_uart_desc *uart_desc; + struct iio_app_desc *application; + struct iio_data_buffer *buff; + unsigned int i; + int status; + void *irq_desc = app_init_param.irq_desc; + + application = (struct iio_app_desc *)no_os_calloc(1, sizeof(*application)); + if (!application) + return -ENOMEM; + + application->post_step_callback = app_init_param.post_step_callback; + application->arg = app_init_param.arg; + +#if defined(ADUCM_PLATFORM) || defined(STM32_PLATFORM) + /* Only one irq controller can exist and be initialized in + * any of the iio_devices. */ + for (i = 0; i < app_init_param.nb_devices; i++) { + if (app_init_param.devices[i].dev_descriptor->irq_desc) { + irq_desc = (struct no_os_irq_ctrl_desc *) + app_init_param.devices[i].dev_descriptor->irq_desc; + break; + } + } + + if (!irq_desc) { + status = irq_setup((struct no_os_irq_ctrl_desc **)&irq_desc); + if (status < 0) + return status; + } +#endif + + status = uart_setup(&uart_desc, &app_init_param.uart_init_params); + if (status < 0) + goto error_uart; + + status = print_uart_hello_message(&uart_desc, + &app_init_param.uart_init_params); + if (status < 0) + goto error; + + application->uart_desc = uart_desc; +#if defined(NO_OS_LWIP_NETWORKING) + status = lwip_network_setup(application, app_init_param, &iio_init_param); + if (status) + goto error; +#elif defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM) + status = network_setup(&iio_init_param, uart_desc, application->irq_desc); + if (status < 0) + goto error; +#else + iio_init_param.phy_type = USE_UART; + iio_init_param.uart_desc = uart_desc; +#endif + + iio_init_devs = no_os_calloc(app_init_param.nb_devices, sizeof(*iio_init_devs)); + if (!iio_init_devs) { + status = -ENOMEM; + goto error; + } + + for (i = 0; i < app_init_param.nb_devices; ++i) { + /* + * iio_app_device is from iio_app.h and we don't want to include + * this in iio.h. + * At the moment iio_device_init has the same parameters but + * it will change. + * When changes are done in iio. iio_app_device may be removed + *iio_init_param and use iio_device_init instead. + * This way faster changes can be done without changing all + * project for each change. + */ + iio_init_devs[i].name = app_init_param.devices[i].name; + iio_init_devs[i].dev = app_init_param.devices[i].dev; + iio_init_devs[i].dev_descriptor = app_init_param.devices[i].dev_descriptor; + iio_init_devs[i].trigger_id = app_init_param.devices[i].default_trigger_id; + buff = app_init_param.devices[i].read_buff ? + app_init_param.devices[i].read_buff : + app_init_param.devices[i].write_buff; + if (buff) { + iio_init_devs[i].raw_buf = buff->buff; + iio_init_devs[i].raw_buf_len = buff->size; + } else { + iio_init_devs[i].raw_buf = NULL; + iio_init_devs[i].raw_buf_len = 0; + } + } + + iio_init_param.devs = iio_init_devs; + iio_init_param.nb_devs = app_init_param.nb_devices; + iio_init_param.trigs = app_init_param.trigs; + iio_init_param.nb_trigs = app_init_param.nb_trigs; + iio_init_param.ctx_attrs = app_init_param.ctx_attrs; + iio_init_param.nb_ctx_attr = app_init_param.nb_ctx_attr; + + status = iio_init(&application->iio_desc, &iio_init_param); + if (status < 0) + goto error; + + no_os_free(iio_init_devs); + + *app = application; + + return 0; +error_uart: + /** We might have to reinit UART, settings might have changed for IIO */ + uart_setup(&uart_desc, &app_init_param.uart_init_params); +error: + no_os_free(iio_init_devs); + + no_os_free(application); + + print_uart_error_message(&uart_desc, &app_init_param.uart_init_params, status); + no_os_uart_remove(uart_desc); + + return status; +} + +/** + * @brief Start an IIO application + * + * Configuration for communication is done through iio_app_init_param + * @param app - the iio application parameters + * @return 0 on success, negative value otherwise + */ +int iio_app_run(struct iio_app_desc *app) +{ + int status; + + do { + status = iio_step(app->iio_desc); + if (status && status != -EAGAIN && status != -ENOTCONN + && status != -NO_OS_EOVERRUN) + return status; + if (app->post_step_callback) { + status = app->post_step_callback(app->arg); + if (status) + return status; + } + } while (true); +} + +/** + * @brief Remove resources allocated by the IIO application + * + * Configuration for communication is done through iio_app_init_param + * @param app - the iio application parameters + * @return 0 on success, negative value otherwise + */ +int iio_app_remove(struct iio_app_desc *app) +{ + int ret; + +#if defined(ADUCM_PLATFORM) || (defined(XILINX_PLATFORM) && !defined(PLATFORM_MB)) || defined(STM32_PLATFORM) + ret = no_os_irq_ctrl_remove(app->irq_desc); + if (ret) + return ret; +#endif + + if (app->uart_desc) { + ret = no_os_uart_remove(app->uart_desc); + if (ret) + return ret; + } + + ret = iio_remove(app->iio_desc); + if (ret) + return ret; + + no_os_free(app); + + return 0; +} + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.h new file mode 100644 index 0000000..6c11132 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.h @@ -0,0 +1,138 @@ +/***************************************************************************//** + * @file iio_app.h + * @brief Header file of iio_app + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2013(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef IIO_APP +#define IIO_APP + +#include "iio.h" +#include "no_os_irq.h" +#include "no_os_uart.h" +#include "no_os_error.h" +#include "no_os_delay.h" + +#if defined(NO_OS_LWIP_NETWORKING) +#include "lwip_socket.h" +#endif + +#define IIO_APP_DEVICE(_name, _dev, _dev_descriptor, _read_buff, _write_buff, _default_trigger_id) {\ + .name = _name,\ + .dev = _dev,\ + .dev_descriptor = _dev_descriptor,\ + .read_buff = _read_buff,\ + .write_buff = _write_buff,\ + .default_trigger_id = _default_trigger_id\ +} + +#define IIO_APP_TRIGGER(_name, _trig, _trig_descriptor) {\ + .name = _name,\ + .trig = _trig,\ + .descriptor = _trig_descriptor,\ +} + +struct iio_data_buffer { + uint32_t size; + void *buff; +}; + +struct iio_app_device { + char *name; + void *dev; + struct iio_device *dev_descriptor; + struct iio_data_buffer *read_buff; + struct iio_data_buffer *write_buff; + char *default_trigger_id; +}; + +/** + * @struct iio_app_desc + * @brief IIO application descriptor. + */ +struct iio_app_desc { + /** UART descriptor to be used */ + struct no_os_uart_desc *uart_desc; + /** IRQ descriptor to be used */ + void *irq_desc; + /** IIO descriptor to be returned */ + struct iio_desc *iio_desc; + /** Function to be called each step */ + int (*post_step_callback)(void *arg); + /** Function parameteres */ + void *arg; + +#ifdef NO_OS_LWIP_NETWORKING + struct lwip_network_desc *lwip_desc; +#endif +}; + +/** + * @struct iio_app_init_param + * @brief IIO application descriptor initialization parameters. + */ +struct iio_app_init_param { + /** Array of context attribute name/value pairs */ + struct iio_ctx_attr *ctx_attrs; + /** Number of context attributes in the array above */ + uint32_t nb_ctx_attr; + /** Array of IIO devices */ + struct iio_app_device *devices; + /** Number of devices */ + uint32_t nb_devices; + /** IIO triggers to be used */ + struct iio_trigger_init *trigs; + /** Number of triggers to be used */ + int32_t nb_trigs; + /** UART init params */ + struct no_os_uart_init_param uart_init_params; + /** IRQ descriptor to be used */ + void *irq_desc; + /** Function to be called each step */ + int (*post_step_callback)(void *arg); + /** Function parameteres */ + void *arg; + +#ifdef NO_OS_LWIP_NETWORKING + struct lwip_network_param lwip_param; +#endif +}; + +/** Register devices for an IIO application */ +int iio_app_init(struct iio_app_desc **app, + struct iio_app_init_param app_init_param); + +/** Start an IIO application */ +int iio_app_run(struct iio_app_desc *app); + +/** Remove resources allocated by the IIO application */ +int iio_app_remove(struct iio_app_desc *app); + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.c new file mode 100644 index 0000000..e4796cd --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.c @@ -0,0 +1,227 @@ +/***************************************************************************//** + * @file iio_trigger.c + * @brief Implementation of generic iio trigger. + * @author RBolboac (ramona.bolboaca@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include "no_os_error.h" +#include "no_os_alloc.h" +#include "iio.h" +#include "iio_trigger.h" + +#ifndef LINUX_PLATFORM +/** + * @brief Initialize hardware trigger. + * + * @param iio_trig - The iio trigger structure. + * @param init_param - The structure that contains the trigger initial params. + * + * @return ret - Result of the initialization procedure. + */ +int iio_hw_trig_init(struct iio_hw_trig **iio_trig, + struct iio_hw_trig_init_param *init_param) +{ + struct iio_hw_trig *trig_desc; + int ret; + + if (!init_param->name) + return -EINVAL; + + trig_desc = (struct iio_hw_trig*)no_os_calloc(1, sizeof(*trig_desc)); + if (!trig_desc) + return -ENOMEM; + + trig_desc->iio_desc = init_param->iio_desc; + strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE); + trig_desc->irq_ctrl = init_param->irq_ctrl; + trig_desc->irq_id = init_param->irq_id; + trig_desc->irq_trig_lvl = init_param->irq_trig_lvl; + + struct no_os_callback_desc irq_cb = { + .callback = iio_hw_trig_handler, + .ctx = trig_desc, + .event = init_param->cb_info.event, + .handle = init_param->cb_info.handle, + .peripheral = init_param->cb_info.peripheral + }; + + ret = no_os_irq_register_callback(trig_desc->irq_ctrl, + trig_desc->irq_id, &irq_cb); + if (ret) + goto error; + + if (init_param->cb_info.event == NO_OS_EVT_GPIO) { + ret = no_os_irq_trigger_level_set(trig_desc->irq_ctrl, + trig_desc->irq_id, trig_desc->irq_trig_lvl); + if (ret) + goto error; + } + + *iio_trig = trig_desc; + + return 0; +error: + no_os_free(trig_desc); + return ret; +} + +/** + * @brief Enable system interrupt which is linked to the given trigger. + * + * @param trig - Trigger structure. + * + * @return ret - Result of the enable procedure. +*/ +int iio_trig_enable(void *trig) +{ + if (!trig) + return -EINVAL; + + struct iio_hw_trig *desc = trig; + + return no_os_irq_enable(desc->irq_ctrl, desc->irq_id); +} + +/** + * @brief Disable system interrupt which is linked to the given trigger. + * + * @param trig - Trigger structure. + * + * @return ret - Result of the disable procedure. +*/ +int iio_trig_disable(void *trig) +{ + if (!trig) + return -EINVAL; + + struct iio_hw_trig *desc = trig; + + return no_os_irq_disable(desc->irq_ctrl, desc->irq_id); +} + +/** + * @brief Trigger interrupt handler. This function will be called when a system + * interrupt is asserted for the configured trigger. + * + * @param trig - Trigger structure which is linked to this handler. +*/ +void iio_hw_trig_handler(void *trig) +{ + if (!trig) + return; + + struct iio_hw_trig *desc = trig; + + iio_process_trigger_type(desc->iio_desc, desc->name); +} + +/** + * @brief Free the resources allocated by iio_hw_trig_init(). + * + * @param trig - The trigger structure. + * + * @return ret - Result of the remove procedure. +*/ +int iio_hw_trig_remove(struct iio_hw_trig *trig) +{ + if (trig) + no_os_free(trig); + + return 0; +} +#endif + +/** + * @brief Initialize software trigger. + * + * @param iio_trig - The iio trigger structure. + * @param init_param - The structure that contains the sw trigger initial params. + * + * @return ret - Result of the initialization procedure. +*/ +int iio_sw_trig_init(struct iio_sw_trig **iio_trig, + struct iio_sw_trig_init_param *init_param) +{ + struct iio_sw_trig *trig_desc; + + if (!init_param->iio_desc || !init_param->name) + return -EINVAL; + + trig_desc = (struct iio_sw_trig*)no_os_calloc(1, sizeof(*trig_desc)); + if (!trig_desc) + return -ENOMEM; + + trig_desc->iio_desc = init_param->iio_desc; + strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE); + + *iio_trig = trig_desc; + + return 0; +} + +/** + * @brief Handles the write request for trigger_now attribute. + * + * @param trig - The iio trigger structure. + * @param buf - Command buffer to be filled with the data to be written. + * @param len - Length of the received command buffer in bytes. + * @param channel - Command channel info (is NULL). + * @param priv - Command attribute id. + * + * @return ret - Result of the sw trigger handler procedure. +*/ +int iio_sw_trig_handler(void *trig, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + if (!trig) + return -EINVAL; + + struct iio_sw_trig *desc = trig; + + return iio_process_trigger_type(desc->iio_desc, desc->name); +} + +/** + * @brief Free the resources allocated by iio_sw_trig_init(). + * + * @param trig - The trigger structure. + * + * @return ret - Result of the remove procedure. +*/ +int iio_sw_trig_remove(struct iio_sw_trig *trig) +{ + if (trig) + no_os_free(trig); + + return 0; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.h new file mode 100644 index 0000000..115a0a2 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.h @@ -0,0 +1,138 @@ +/***************************************************************************//** + * @file iio_trigger.h + * @brief Header file for iio_trigger. + * @author RBolboac(ramona.bolboaca@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef IIO_TRIGGER_H_ +#define IIO_TRIGGER_H_ + +#include "iio.h" +#include "iio_types.h" +#include "no_os_irq.h" + +#define TRIG_MAX_NAME_SIZE 20 + +/** + * @struct iio_hw_trig + * @brief IIO hardware trigger structure + */ +struct iio_hw_trig { + /** IIO descriptor */ + struct iio_desc *iio_desc; + /** Interrupt descriptor to be linked with the trigger */ + struct no_os_irq_ctrl_desc *irq_ctrl; + /** Interrupt id to be linked with the trigger */ + uint32_t irq_id; + /** Interrupt trigger level */ + enum no_os_irq_trig_level irq_trig_lvl; + /** Device trigger name */ + char name[TRIG_MAX_NAME_SIZE + 1]; +}; + +/** + * @struct iio_hw_trig_cb_info + * @brief Hardware trigger callback extra information structure + */ +struct iio_hw_trig_cb_info { + /** Platform specific event that triggers the calling of the callback. */ + enum no_os_irq_event event; + /** Interrupt source peripheral specifier. */ + enum no_os_irq_peripheral peripheral; + /** This will be used to store HAL specific descriptors */ + void *handle; +}; + +/** + * @struct iio_hw_trig_init_param + * @brief IIO hardware trigger initialization structure + */ +struct iio_hw_trig_init_param { + /** IIO descriptor */ + struct iio_desc *iio_desc; + /** Interrupt descriptor to be linked with the trigger */ + struct no_os_irq_ctrl_desc *irq_ctrl; + /** Interrupt id to be linked with the trigger */ + uint32_t irq_id; + /** Interrupt trigger level */ + enum no_os_irq_trig_level irq_trig_lvl; + /** Additional interrupt callback information */ + struct iio_hw_trig_cb_info cb_info; + /** Device trigger name */ + const char *name; +}; + +/** + * @struct iio_sw_trig + * @brief IIO software trigger structure + */ +struct iio_sw_trig { + /** IIO descriptor */ + struct iio_desc *iio_desc; + /** Device trigger name */ + char name[TRIG_MAX_NAME_SIZE + 1]; +}; + +/** + * @struct iio_sw_trig_init_param + * @brief IIO software trigger initialization structure + */ +struct iio_sw_trig_init_param { + /** IIO descriptor */ + struct iio_desc *iio_desc; + /** Device trigger name */ + const char *name; +}; + +#ifndef LINUX_PLATFORM +/** API to initialize a hardware trigger */ +int iio_hw_trig_init(struct iio_hw_trig **iio_trig, + struct iio_hw_trig_init_param *init_param); +/** API to enable a hardware trigger */ +int iio_trig_enable(void *trig); +/** API to disable a hardware trigger */ +int iio_trig_disable(void *trig); +/** API for hardware trigger handler */ +void iio_hw_trig_handler(void *trig); +/** API to remove a hardware trigger */ +int iio_hw_trig_remove(struct iio_hw_trig *trig); +#endif + +/** API to initialize a software trigger */ +int iio_sw_trig_init(struct iio_sw_trig **iio_trig, + struct iio_sw_trig_init_param *init_param); +/** API for software trigger handler */ +int iio_sw_trig_handler(void *trig, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); +/** API to remove a software trigger */ +int iio_trig_remove(struct iio_sw_trig *trig); + +#endif /* IIO_TRIGGER_H_ */ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_types.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_types.h new file mode 100644 index 0000000..712b281 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_types.h @@ -0,0 +1,280 @@ +/***************************************************************************//** + * @file iio_types.h + * @brief Header file for iio_types + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2013(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef IIO_TYPES_H_ +#define IIO_TYPES_H_ + +#include +#include +#include "no_os_circular_buffer.h" + +enum iio_val { + IIO_VAL_INT = 1, + IIO_VAL_INT_PLUS_MICRO, + IIO_VAL_INT_PLUS_NANO, + IIO_VAL_INT_PLUS_MICRO_DB, + IIO_VAL_INT_MULTIPLE, + IIO_VAL_FRACTIONAL = 10, + IIO_VAL_FRACTIONAL_LOG2, + IIO_VAL_CHAR +}; + +/** + * @struct iio_chan_type + * @brief IIO channel types + */ +enum iio_chan_type { + IIO_VOLTAGE, + IIO_CURRENT, + IIO_ALTVOLTAGE, + IIO_ANGL_VEL, + IIO_TEMP, + IIO_CAPACITANCE, + IIO_ACCEL, + IIO_RESISTANCE, + IIO_MAGN, + IIO_INCLI, + IIO_VELOCITY, + IIO_ANGL, + IIO_ROT, + IIO_COUNT, + IIO_DELTA_ANGL, + IIO_DELTA_VELOCITY, + IIO_WEIGHT, +}; + +/** + * @struct iio_modifier + * @brief IIO channel modifier + */ +enum iio_modifier { + IIO_NO_MOD, + IIO_MOD_X, + IIO_MOD_Y, + IIO_MOD_Z, + IIO_MOD_TEMP_AMBIENT, + IIO_MOD_PITCH, + IIO_MOD_YAW, + IIO_MOD_ROLL, +}; + +/** + * @struct iio_ch_info + * @brief Structure holding channel attributess. + */ +struct iio_ch_info { + /** Channel number. TODO: refactor out the ch_ prefix. */ + int16_t ch_num; + /** Channel direction: input/output. TODO: refactor out the ch_ prefix. */ + bool ch_out; + /** Channel type */ + enum iio_chan_type type; + /** Differential channel indicator */ + bool differential; + /** Driver specific identifier. */ + uint32_t address; +}; + +#define END_ATTRIBUTES_ARRAY {.name = NULL} + +enum iio_attribute_shared { + IIO_SEPARATE, + IIO_SHARED_BY_TYPE, + IIO_SHARED_BY_DIR, + IIO_SHARED_BY_ALL, +}; + +/** + * @struct iio_attribute + * @brief Structure holding pointers to show and store functions. + */ +struct iio_attribute { + /** Attribute name */ + const char *name; + /** Attribute id */ + intptr_t priv; + /** Whether this attribute is shared by all channels of the same type, or direction + * or simply by all channels. If left uninitialized, the sharedness defaults to + * separate. + */ + enum iio_attribute_shared shared; + /** Show function pointer */ + int (*show)(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, intptr_t priv); + /** Store function pointer */ + int (*store)(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, intptr_t priv); +}; + +/** + * @struct iio_channel + * @brief Struct describing the scan type + */ +struct scan_type { + /** 's' or 'u' to specify signed or unsigned */ + char sign; + /** Number of valid bits of data */ + uint8_t realbits; + /** Realbits + padding */ + uint8_t storagebits; + /** Shift right by this before masking out realbits. */ + uint8_t shift; + /** True if big endian, false if little endian */ + bool is_big_endian; +}; + +/** + * @struct iio_channel + * @brief Structure holding attributes of a channel. + */ +struct iio_channel { + /** Channel name */ + const char *name; + /** Chanel type */ + enum iio_chan_type ch_type; + /** Channel number when the same channel type */ + int channel; + /** If modified is set, this provides the modifier. E.g. IIO_MOD_X + * for angular rate when applied to channel2 will make make the + * IIO_ANGL_VEL have anglvel_x which corresponds to the x-axis. */ + int channel2; + /** Driver specific identifier. */ + unsigned long address; + /** Index to give ordering in scans when read from a buffer. */ + int scan_index; + /** */ + struct scan_type *scan_type; + /** Array of attributes. Last one should have its name set to NULL */ + struct iio_attribute *attributes; + /** if true, the channel is an output channel */ + bool ch_out; + /** Set if channel has a modifier. Use channel2 property to + * select the modifier to use.*/ + bool modified; + /** Specify if channel has a numerical index. If not set, channel + * number will be suppressed. */ + bool indexed; + /* Set if the channel is differential. */ + bool diferential; +}; + +enum iio_buffer_direction { + IIO_DIRECTION_INPUT, + IIO_DIRECTION_OUTPUT +}; + +struct iio_cyclic_buffer_info { + bool is_cyclic; + uint32_t buff_index; +}; + +struct iio_buffer { + /* Mask with active channels */ + uint32_t active_mask; + /* Size in bytes */ + uint32_t size; + /* Number of bytes per sample * number of active channels */ + uint32_t bytes_per_scan; + /* Number of requested samples */ + uint32_t samples; + /* Buffer direction */ + enum iio_buffer_direction dir; + /* Buffer where data is stored */ + struct no_os_circular_buffer *buf; + /* Stores cyclic buffer specific information */ + struct iio_cyclic_buffer_info cyclic_info; +}; + +struct iio_device_data { + void *dev; + struct iio_buffer *buffer; +}; + +struct iio_trigger { + /** If true the trigger handler will be called in interrupt context + * If false the handler will be called from iio_step */ + bool is_synchronous; + /** Array of attributes. Last one should have its name set to NULL */ + struct iio_attribute *attributes; + /** Called when needs to be enabled */ + int (*enable)(void *trig); + /** Called when needs to be disabled */ + int (*disable)(void *trig); +}; + +/** + * @struct iio_device + * @brief Structure holding channels and attributes of a device. + */ +struct iio_device { + /** Structure for existing initialized irq controllers. Has to be + * set to NULL if there isn't any irq controller initialized. */ + struct no_os_irq_ctrl_desc *irq_desc; + /** Device number of channels */ + uint16_t num_ch; + /** List of channels */ + struct iio_channel *channels; + /** Array of attributes. Last one should have its name set to NULL */ + struct iio_attribute *attributes; + /** Array of attributes. Last one should have its name set to NULL */ + struct iio_attribute *debug_attributes; + /** Array of attributes. Last one should have its name set to NULL */ + struct iio_attribute *buffer_attributes; + /* Numbers of bytes will be: + * samples * (storage_size_of_first_active_ch / 8) * nb_active_channels + * DEPRECATED. + */ + int32_t (*read_dev)(void *dev, void *buff, uint32_t nb_samples); + /* Numbers of bytes will be: + * samples * (storage_size_of_first_active_ch / 8) * nb_active_channels + * DEPRECATED. + */ + int32_t (*write_dev)(void *dev, void *buff, uint32_t nb_samples); + + /* Bufer callbacks */ + /** Called before enabling buffer */ + int32_t (*pre_enable)(void *dev, uint32_t mask); + /** Called after disabling buffer */ + int32_t (*post_disable)(void *dev); + /** Called when buffer ready to transfer. Write/read to/from dev */ + int32_t (*submit)(struct iio_device_data *dev); + /** Called after a trigger signal has been received by iio */ + int32_t (*trigger_handler)(struct iio_device_data *dev); + + /* Read device register */ + int32_t (*debug_reg_read)(void *dev, uint32_t reg, uint32_t *readval); + /* Write device register */ + int32_t (*debug_reg_write)(void *dev, uint32_t reg, uint32_t writeval); + +}; + +#endif /* IIO_TYPES_H_ */ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.c new file mode 100644 index 0000000..892bd90 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.c @@ -0,0 +1,927 @@ +/***************************************************************************//** + * @file iiod.c + * @brief Nonblocking implementation of iiod. + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "iiod.h" +#include "iiod_private.h" + +#include "no_os_error.h" +#include "no_os_util.h" + +#define SET_DUMMY_IF_NULL(func, dummy) ((func) ? (func) : (dummy)) + +static char delim[] = " \r\n"; + + +static const char *attr_types_strs[] = { + [IIO_ATTR_TYPE_DEBUG] = "DEBUG", + [IIO_ATTR_TYPE_BUFFER] = "BUFFER", + [IIO_ATTR_TYPE_CH_OUT] = "OUTPUT", + [IIO_ATTR_TYPE_CH_IN] = "INPUT" +}; + +static struct iiod_str cmds[] = { + [IIOD_CMD_HELP] = IIOD_STR("HELP"), + [IIOD_CMD_EXIT] = IIOD_STR("EXIT"), + [IIOD_CMD_PRINT] = IIOD_STR("PRINT"), + [IIOD_CMD_VERSION] = IIOD_STR("VERSION"), + [IIOD_CMD_TIMEOUT] = IIOD_STR("TIMEOUT"), + [IIOD_CMD_OPEN] = IIOD_STR("OPEN"), + [IIOD_CMD_CLOSE] = IIOD_STR("CLOSE"), + [IIOD_CMD_READ] = IIOD_STR("READ"), + [IIOD_CMD_WRITE] = IIOD_STR("WRITE"), + [IIOD_CMD_READBUF] = IIOD_STR("READBUF"), + [IIOD_CMD_WRITEBUF] = IIOD_STR("WRITEBUF"), + [IIOD_CMD_GETTRIG] = IIOD_STR("GETTRIG"), + [IIOD_CMD_SETTRIG] = IIOD_STR("SETTRIG"), + [IIOD_CMD_SET] = IIOD_STR("SET") +}; +static const uint32_t priority_array[] = { + /* Order not tested, just personal expectation. Function can + * be improved, this improvement is chosen for simplicity */ + IIOD_CMD_READBUF, + IIOD_CMD_WRITEBUF, + IIOD_CMD_READ, + IIOD_CMD_WRITE, + IIOD_CMD_OPEN, + IIOD_CMD_CLOSE, + IIOD_CMD_PRINT, + IIOD_CMD_EXIT, + IIOD_CMD_TIMEOUT, + IIOD_CMD_VERSION, + IIOD_CMD_GETTRIG, + IIOD_CMD_SETTRIG, + IIOD_CMD_HELP, + IIOD_CMD_SET +}; + +static_assert(NO_OS_ARRAY_SIZE(cmds) == NO_OS_ARRAY_SIZE(priority_array), + "Arrays must have the same size"); + +/* Set res->cmd to corresponding cmd and return the processed length of buf */ +static int32_t parse_cmd(const char *token, struct comand_desc *res) +{ + uint32_t i; + struct iiod_str *cmd; + + if (!token) + return -EINVAL; + + for (i = 0; i < NO_OS_ARRAY_SIZE(cmds); ++i) { + cmd = &cmds[priority_array[i]]; + if (strcmp(token, cmd->str) == 0) { + res->cmd = priority_array[i]; + + return 0; + } + } + + return -EINVAL; +} + +static int32_t parse_num(const char *token, uint32_t *res, uint32_t base) +{ + char *end_ptr; + + *res = strtoul(token, &end_ptr, base); + if (*res == 0 && *end_ptr != '\0') + return -EINVAL; + + return 0; +} + +static int32_t iiod_parse_open(const char *token, struct comand_desc *res, + char **ctx) +{ + int32_t ret; + + if (!token) + return -EINVAL; + + ret = parse_num(token, &res->sample_count, 10); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + token = strtok_r(NULL, delim, ctx); + if (!token) + return -EINVAL; + + ret = parse_num(token, &res->mask, 16); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + res->cyclic = 0; + token = strtok_r(NULL, delim, ctx); + if (token) { + if (strcmp(token, "CYCLIC") == 0) + res->cyclic = 1; + else + return -EINVAL; + } + + return 0; +} + +static int32_t iiod_parse_set(const char *token, struct comand_desc *res, + char **ctx) +{ + if (!token) + return -EINVAL; + + if (strcmp(token, "BUFFERS_COUNT")) + return -EINVAL; + + token = strtok_r(NULL, delim, ctx); + if (!token) + return -EINVAL; + + return parse_num(token, &res->count, 10); +} + +static int32_t iiod_parse_rw_attr(const char *token, struct comand_desc *res, + char **ctx) +{ + int32_t i; + + res->type = IIO_ATTR_TYPE_DEVICE; + if (token) { + for (i = 0; i < IIO_ATTR_TYPE_DEVICE; ++i) { + if (strcmp(token, attr_types_strs[i]) == 0) { + token = strtok_r(NULL, delim, ctx); + res->type = i; + break; + } + } + } + + if (res->type == IIO_ATTR_TYPE_CH_IN || + res->type == IIO_ATTR_TYPE_CH_OUT) { + if (!token) + return -EINVAL; + strncpy(res->channel, token, sizeof(res->channel)); + token = strtok_r(NULL, delim, ctx); + } + + if (res->cmd == IIOD_CMD_WRITE) { + if (!token) + return -EINVAL; + + if (*token >= '0' && *token <= '9') { + memset(res->attr, 0, sizeof(res->attr)); + + return parse_num(token, &res->bytes_count, 10); + } + + strncpy(res->attr, token, sizeof(res->attr)); + token = strtok_r(NULL, delim, ctx); + if (!token) + return -EINVAL; + + return parse_num(token, &res->bytes_count, 10); + } + + if (token) + strncpy(res->attr, token, sizeof(res->attr)); + else + memset(res->attr, 0, sizeof(res->attr)); + + return 0; +} + +int32_t iiod_parse_line(char *buf, struct comand_desc *res, char **ctx) +{ + int32_t ret; + char *token; + + token = strtok_r(buf, delim, ctx); + ret = parse_cmd(token, res); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + token = strtok_r(NULL, delim, ctx); + /* Commands without device */ + switch (res->cmd) { + case IIOD_CMD_HELP: + case IIOD_CMD_EXIT: + case IIOD_CMD_PRINT: + case IIOD_CMD_VERSION: + return 0; + case IIOD_CMD_TIMEOUT: + return parse_num(token, &res->timeout, 10); + default: + break; + } + + strncpy(res->device, token, sizeof(res->device)); + token = strtok_r(NULL, delim, ctx); + switch (res->cmd) { + case IIOD_CMD_CLOSE: + case IIOD_CMD_GETTRIG: + return 0; + case IIOD_CMD_OPEN: + return iiod_parse_open(token, res, ctx); + case IIOD_CMD_READ: + case IIOD_CMD_WRITE: + return iiod_parse_rw_attr(token, res, ctx); + case IIOD_CMD_READBUF: + case IIOD_CMD_WRITEBUF: + return parse_num(token, &res->bytes_count, 10); + case IIOD_CMD_SETTRIG: + if (token) + strncpy(res->trigger, token, sizeof(res->trigger)); + else + memset(res->trigger, 0, sizeof(res->trigger)); + + return 0; + case IIOD_CMD_SET: + return iiod_parse_set(token, res, ctx); + default: + break; + } + + return -EINVAL; +} + +static int dummy_open(struct iiod_ctx *ctx, const char *device, + uint32_t samples, uint32_t mask, bool cyclic) +{ + return -EINVAL; +} + +static int dummy_close(struct iiod_ctx *ctx, const char *device) +{ + return -EINVAL; +} + +static int dummy_rw_attr(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len) +{ + return -EINVAL; +} + +static int dummy_rd_data(struct iiod_ctx *ctx, const char *device, char *buf, + uint32_t bytes) +{ + return -EINVAL; +} + +static int dummy_wr_data(struct iiod_ctx *ctx, const char *device, + const char *trig, uint32_t bytes) +{ + return -EINVAL; +} + +static int dummy_set_timeout(struct iiod_ctx *ctx, uint32_t timeout) +{ + return -EINVAL; +} + +static int dummy_set_buffers_count(struct iiod_ctx *ctx, const char *device, + uint32_t buffers_count) +{ + return -EINVAL; +} + +int32_t iiod_copy_ops(struct iiod_ops *ops, struct iiod_ops *new_ops) +{ + if (!new_ops->recv || !new_ops->send) + return -EINVAL; + + ops->recv = new_ops->recv; + ops->send = new_ops->send; + + ops->open = SET_DUMMY_IF_NULL(new_ops->open, dummy_open); + ops->close = SET_DUMMY_IF_NULL(new_ops->close, dummy_close); + ops->read_buffer = SET_DUMMY_IF_NULL(new_ops->read_buffer, dummy_rd_data); + ops->write_buffer = SET_DUMMY_IF_NULL(new_ops->write_buffer, dummy_wr_data); + ops->read_attr = SET_DUMMY_IF_NULL(new_ops->read_attr, dummy_rw_attr); + ops->write_attr = SET_DUMMY_IF_NULL(new_ops->write_attr, dummy_rw_attr); + ops->get_trigger = SET_DUMMY_IF_NULL(new_ops->get_trigger, dummy_rd_data); + ops->set_trigger = SET_DUMMY_IF_NULL(new_ops->set_trigger, dummy_wr_data); + ops->set_timeout = SET_DUMMY_IF_NULL(new_ops->set_timeout, dummy_set_timeout); + ops->set_buffers_count = SET_DUMMY_IF_NULL(new_ops->set_buffers_count, + dummy_set_buffers_count); + ops->refill_buffer = SET_DUMMY_IF_NULL(new_ops->refill_buffer, + dummy_close); + ops->push_buffer = SET_DUMMY_IF_NULL(new_ops->push_buffer, + dummy_close); + + return 0; +} + +int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param) +{ + struct iiod_desc *ldesc; + int32_t ret; + + if (!desc || !param || !param->ops) + return -EINVAL; + + ldesc = (struct iiod_desc *)calloc(1, sizeof(*ldesc)); + if (!ldesc) + return -ENOMEM; + + ret = iiod_copy_ops(&ldesc->ops, param->ops); + if (NO_OS_IS_ERR_VALUE(ret)) { + free(ldesc); + + return ret; + } + + ldesc->xml = param->xml; + ldesc->xml_len = param->xml_len; + ldesc->app_instance = param->instance; + ldesc->phy_type = param->phy_type; + + *desc = ldesc; + + return 0; +} + +void iiod_remove(struct iiod_desc *desc) +{ + free(desc); +} + +static void conn_clean_state(struct iiod_conn_priv *conn) +{ + memset(&conn->cmd_data, 0, sizeof(conn->cmd_data)); + memset(&conn->res, 0, sizeof(conn->res)); + memset(&conn->nb_buf, 0, sizeof(conn->nb_buf)); + + conn->res.buf.buf = NULL; + conn->res.buf.idx = 0; + conn->parser_idx = 0; + conn->state = IIOD_READING_LINE; +} + +int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data, + uint32_t *new_conn_id) +{ + uint32_t i; + struct iiod_conn_priv *conn; + + if (!desc || !new_conn_id) + return -EINVAL; + + for (i = 0; i < IIOD_MAX_CONNECTIONS; ++i) + if (!desc->conns[i].used) { + conn = &desc->conns[i]; + memset(conn, 0, sizeof(*conn)); + conn->used = 1; + conn->conn = data->conn; + /* + * TODO in future: + * think of using other buffer (e.g. ciruclar_buffer) + * to somehow implement zero copy + */ + conn->payload_buf = data->buf; + conn->payload_buf_len = data->len; + *new_conn_id = i; + + return 0; + } + + return -EBUSY; +} + +int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id, + struct iiod_conn_data *data) +{ + if (!desc || conn_id > IIOD_MAX_CONNECTIONS || + !desc->conns[conn_id].used) + return -EINVAL; + struct iiod_conn_priv *conn; + conn = &desc->conns[conn_id]; + data->conn = conn->conn; + data->len = conn->payload_buf_len; + data->buf = conn->payload_buf; + conn->used = 0; + + return 0; +} + +static int32_t call_op(struct iiod_ops *ops, struct comand_desc *data, + struct iiod_ctx *ctx) +{ + switch (data->cmd) { + case IIOD_CMD_HELP: + return -EINVAL; + case IIOD_CMD_TIMEOUT: + return ops->set_timeout(ctx, data->timeout); + case IIOD_CMD_OPEN: + return ops->open(ctx, data->device, data->sample_count, + data->mask, data->cyclic); + case IIOD_CMD_CLOSE: + return ops->close(ctx, data->device); + case IIOD_CMD_SETTRIG: + return ops->set_trigger(ctx, data->device, data->trigger, + strlen(data->trigger)); + case IIOD_CMD_SET: + return ops->set_buffers_count(ctx, data->device, data->count); + default: + break; + } + + return -EINVAL; +} + +/* + * Unload data from buf without blocking. + * When done will return 0, if there is still data to be sent it will return + * -EAGIAN. On error, an negative error code is returned + */ +static int32_t rw_iiod_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn, + struct iiod_buff *buf, uint8_t flags) +{ + struct iiod_ctx ctx = IIOD_CTX(desc, conn); + uint8_t *tmp_buf; + int32_t ret; + int32_t len; + + len = buf->len - buf->idx; + if (len) { + tmp_buf = (uint8_t *)buf->buf + buf->idx; + if (flags & IIOD_WR) + ret = desc->ops.send(&ctx, tmp_buf, len); + else + ret = desc->ops.recv(&ctx, tmp_buf, len); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + buf->idx += ret; + if (ret < len) + return -EAGAIN; + } + + if (flags & IIOD_ENDL) { + ret = desc->ops.send(&ctx, (uint8_t *)"\n", 1); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + if (ret != 1) + return -EAGAIN; + } + + return 0; +} + +static int32_t do_read_buff_delayed(struct iiod_desc *desc, + struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx = IIOD_CTX(desc, conn); + uint32_t max_to_read; + int32_t ret, len; + + conn->nb_buf.buf = conn->payload_buf; + len = no_os_min(conn->payload_buf_len, conn->cmd_data.bytes_count); + max_to_read = len - conn->nb_buf.len; + ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device, + conn->nb_buf.buf + conn->nb_buf.len, max_to_read); + if (ret < 0) + return ret; + + conn->nb_buf.len += ret; + + if (conn->nb_buf.len < conn->cmd_data.bytes_count) + return -EAGAIN; + + ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR); + if (ret < 0) + return ret; + + conn->nb_buf.len = 0; + conn->nb_buf.idx = 0; + + return 0; +} + +static int32_t do_read_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx; + int32_t ret, len; + + /* + * When using the network backend wait for a whole buffer to be filled + * before sending in order to reduce the ammount of network traffic. + */ + if (desc->phy_type == USE_NETWORK) + return do_read_buff_delayed(desc, conn); + + ctx = (struct iiod_ctx)IIOD_CTX(desc, conn); + if (conn->nb_buf.len == 0) { + conn->nb_buf.buf = conn->payload_buf; + len = no_os_min(conn->payload_buf_len, + conn->cmd_data.bytes_count); + /* Read from dev */ + ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device, + conn->nb_buf.buf, len); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + len = ret; + conn->nb_buf.len = len; + conn->nb_buf.idx = 0; + } + if (conn->nb_buf.idx < conn->nb_buf.len) { + /* Write on conn */ + ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + conn->cmd_data.bytes_count -= conn->nb_buf.len; + conn->nb_buf.len = 0; + if (conn->cmd_data.bytes_count) + return -EAGAIN; + } + + return 0; +} + +static int32_t do_write_buff(struct iiod_desc *desc, + struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx = IIOD_CTX(desc, conn); + int32_t ret, len; + + if (conn->nb_buf.len == 0) { + conn->nb_buf.buf = conn->payload_buf; + len = no_os_min(conn->payload_buf_len, + conn->cmd_data.bytes_count); + conn->nb_buf.len = len; + conn->nb_buf.idx = 0; + } + if (conn->nb_buf.idx < conn->nb_buf.len) { + /* Read from conn */ + ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + } + /* Write to dev */ + ret = desc->ops.write_buffer(&ctx, conn->cmd_data.device, + conn->nb_buf.buf, conn->nb_buf.len); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + conn->cmd_data.bytes_count -= conn->nb_buf.len; + conn->nb_buf.len = 0; + if (conn->cmd_data.bytes_count) + return -EAGAIN; + + return 0; +} + +static int32_t iiod_run_cmd(struct iiod_desc *desc, + struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx = IIOD_CTX(desc, conn); + struct comand_desc *data = &conn->cmd_data; + struct iiod_attr attr = { + .type = data->type, + .name = data->attr, + .channel = data->channel + }; + int32_t ret; + + switch (data->cmd) { + case IIOD_CMD_HELP: + case IIOD_CMD_TIMEOUT: + case IIOD_CMD_OPEN: + case IIOD_CMD_CLOSE: + case IIOD_CMD_SETTRIG: + case IIOD_CMD_SET: + if (data->cmd == IIOD_CMD_OPEN) { + conn->mask = data->mask; + if (data->cyclic) + conn->is_cyclic_buffer = true; + } + if (data->cmd == IIOD_CMD_CLOSE) + /* Set is_cyclic_buffer to false every time the device is closed */ + conn->is_cyclic_buffer = false; + conn->res.val = call_op(&desc->ops, data, &ctx); + conn->res.write_val = 1; + break; + case IIOD_CMD_EXIT: + conn->res.val = 0; + conn->res.write_val = 1; + + return -ENOTCONN; + case IIOD_CMD_PRINT: + conn->res.val = desc->xml_len; + conn->res.write_val = 1; + conn->res.buf.buf = desc->xml; + conn->res.buf.len = desc->xml_len; + break; + case IIOD_CMD_VERSION: + conn->res.buf.buf = IIOD_VERSION; + conn->res.buf.len = IIOD_VERSION_LEN; + break; + case IIOD_CMD_READ: + case IIOD_CMD_GETTRIG: + if (data->cmd == IIOD_CMD_READ) + ret = desc->ops.read_attr(&ctx, data->device, &attr, + conn->payload_buf, + conn->payload_buf_len); + else + ret = desc->ops.get_trigger(&ctx, data->device, + conn->payload_buf, + conn->payload_buf_len); + conn->res.val = ret; + conn->res.write_val = 1; + if (!NO_OS_IS_ERR_VALUE(ret)) { + conn->res.buf.buf = conn->payload_buf; + conn->res.buf.len = ret; + } + break; + case IIOD_CMD_WRITE: + conn->payload_buf[data->bytes_count] = '\0'; + ret = desc->ops.write_attr(&ctx, data->device, &attr, + conn->payload_buf, + data->bytes_count); + conn->nb_buf.len = 0; + conn->res.val = ret; + conn->res.write_val = 1; + break; + case IIOD_CMD_READBUF: + conn->res.write_val = 1; + ret = desc->ops.refill_buffer(&ctx, data->device); + if (NO_OS_IS_ERR_VALUE(ret)) { + conn->res.val = ret; + break; + } + conn->res.val = data->bytes_count; + ret = snprintf(conn->buf_mask, 10, "%08"PRIx32, conn->mask); + conn->res.buf.buf = conn->buf_mask; + conn->res.buf.len = ret; + break; + case IIOD_CMD_WRITEBUF: + conn->res.val = data->bytes_count; + conn->res.write_val = 1; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int32_t iiod_read_line(struct iiod_desc *desc, + struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx = { + .instance = desc->app_instance, + .conn = conn->conn + }; + int32_t ret; + char *ch; + + while (conn->parser_idx < IIOD_PARSER_MAX_BUF_SIZE - 1) { + ch = conn->parser_buf + conn->parser_idx; + ret = desc->ops.recv(&ctx, (uint8_t *)ch, 1); + if (ret == -EAGAIN || ret == 0) + return -EAGAIN; + + if (NO_OS_IS_ERR_VALUE(ret)) + goto end; + + if (conn->parser_idx == 0 && (*ch == '\n' || *ch == '\r')) + continue ; + + ++conn->parser_idx; + if (*ch == '\n') { + conn->parser_buf[conn->parser_idx] = '\0'; + ret = 0; + goto end; + } + } + + ret = -EIO; +end: + conn->parser_idx = 0; + return ret; +} + +/* + * Function will return SUCCESS when a state was processed. + * If a state is still in processing state, it will return -EAGAIN. + * If other error occur. E.g. Connection errors, they are returned and + * the connection must be cleaned up. + */ +static int32_t iiod_run_state(struct iiod_desc *desc, + struct iiod_conn_priv *conn) +{ + struct iiod_ctx ctx = { + .instance = desc->app_instance, + .conn = conn->conn + }; + int32_t ret; + + switch (conn->state) { + case IIOD_READING_LINE: + /* Read input data until \n. I/O Calls */ + ret = iiod_read_line(desc, conn); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + /* Fill struct comand_desc with data from line. No I/O */ + ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data, + &conn->strtok_ctx); + if (NO_OS_IS_ERR_VALUE(ret)) { + /* Parsing line failed */ + conn->res.write_val = 1; + conn->res.val = ret; + conn->state = IIOD_WRITING_CMD_RESULT; + } else if (conn->cmd_data.cmd == IIOD_CMD_WRITE) { + /* Special case. Attribute needs to be read */ + conn->nb_buf.buf = conn->payload_buf; + conn->nb_buf.len = conn->cmd_data.bytes_count; + conn->nb_buf.idx = 0; + conn->state = IIOD_READING_WRITE_DATA; + } else { + conn->state = IIOD_RUNNING_CMD; + } + + return 0; + case IIOD_RUNNING_CMD: + /* Execute or call necessary ops depending on cmd. No I/O */ + ret = iiod_run_cmd(desc, conn); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + conn->state = IIOD_WRITING_CMD_RESULT; + + return 0; + case IIOD_WRITING_CMD_RESULT: + /* Write result or the length of data to be sent*/ + if (conn->res.write_val) { + if (conn->nb_buf.len == 0) { + conn->nb_buf.buf = conn->parser_buf; + ret = sprintf(conn->nb_buf.buf, "%"PRIi32, + conn->res.val); + conn->nb_buf.len = ret; + conn->nb_buf.idx = 0; + } + /* Non-blocking. Will enter here until val is sent */ + if (conn->nb_buf.idx < conn->nb_buf.len) { + ret = rw_iiod_buff(desc, conn, &conn->nb_buf, + IIOD_WR | IIOD_ENDL); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + } + } + /* Send buf from result. Non blocking */ + if (conn->res.buf.buf && + conn->res.buf.idx < conn->res.buf.len) { + ret = rw_iiod_buff(desc, conn, &conn->res.buf, + IIOD_WR | IIOD_ENDL); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + } + + if (conn->cmd_data.cmd != IIOD_CMD_READBUF && + conn->cmd_data.cmd != IIOD_CMD_WRITEBUF) { + if (conn->is_cyclic_buffer && conn->cmd_data.cmd != IIOD_CMD_OPEN) + conn->state = IIOD_PUSH_CYCLIC_BUFFER; + else + conn->state = IIOD_LINE_DONE; + } else { + /* Preapre for IIOD_RW_BUF state */ + memset(&conn->nb_buf, 0, sizeof(conn->nb_buf)); + conn->state = IIOD_RW_BUF; + } + + return 0; + case IIOD_RW_BUF: + /* IIOD_CMD_READBUF and IIOD_CMD_WRITEBUF special case */ + /* Non blocking read/write until all data is processed */ + if (conn->cmd_data.cmd == IIOD_CMD_READBUF) + ret = do_read_buff(desc, conn); + else { + ret = do_write_buff(desc, conn); + if (ret == 0) { + conn->res.write_val = 1; + ret = desc->ops.push_buffer(&ctx, + conn->cmd_data.device); + if (NO_OS_IS_ERR_VALUE(ret)) { + conn->res.val = ret; + conn->state = IIOD_LINE_DONE; + + return 0; + } + memset(&conn->res.buf, 0, sizeof(conn->res.buf)); + conn->res.val = conn->cmd_data.bytes_count; + conn->cmd_data.cmd = IIOD_CMD_PRINT; + conn->state = IIOD_WRITING_CMD_RESULT; + + return 0; + } + } + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + conn->state = IIOD_LINE_DONE; + + return 0; + case IIOD_READING_WRITE_DATA: + /* Read attribute */ + ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + conn->state = IIOD_RUNNING_CMD; + + return 0; + case IIOD_PUSH_CYCLIC_BUFFER: + /* Push puffer to IIO application */ + ret = desc->ops.push_buffer(&ctx, + conn->cmd_data.device); + /* If an error was encountered, close connection */ + if (NO_OS_IS_ERR_VALUE(ret)) { + conn->res.val = ret; + desc->ops.close(&ctx, conn->cmd_data.device); + conn->state = IIOD_LINE_DONE; + conn->is_cyclic_buffer = false; + return 0; + } + + /* Read data from the client to verify whether a close command has been sent */ + ret = iiod_read_line(desc, conn); + if (NO_OS_IS_ERR_VALUE(ret)) + return 0; + + /* Fill struct comand_desc with data from line */ + ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data, + &conn->strtok_ctx); + if (!NO_OS_IS_ERR_VALUE(ret) && conn->cmd_data.cmd == IIOD_CMD_CLOSE) { + /* Exit this state only if a close command is received + All other commands will be ignored. + */ + conn->nb_buf.len = 0; + conn->state = IIOD_RUNNING_CMD; + conn->is_cyclic_buffer = false; + } + return 0; + + default: + /* Should never get here */ + return -EINVAL; + } +} + +int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id) +{ + struct iiod_conn_priv *conn; + int32_t ret; + + if (!desc || conn_id > IIOD_MAX_CONNECTIONS || + !desc->conns[conn_id].used) + return -EINVAL; + + conn = &desc->conns[conn_id]; + do { + ret = iiod_run_state(desc, conn); + if (ret == -EAGAIN) + return ret; + if (NO_OS_IS_ERR_VALUE(ret) || conn->state == IIOD_LINE_DONE) + break; + //The loop will continue because the state was changed. + } while (true); + + conn_clean_state(conn); + + return ret; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.h new file mode 100644 index 0000000..dce63cf --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.h @@ -0,0 +1,192 @@ +/***************************************************************************//** + * @file iiod.h + * @brief Header file of iiod + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef IIOD_H +#define IIOD_H + +#include +#include + +#include "iio.h" + +/* Maximum nomber of iiod connections to allocate simultaneously */ +#define IIOD_MAX_CONNECTIONS 10 +#define IIOD_VERSION "1.1.0000000" +#define IIOD_VERSION_LEN (sizeof(IIOD_VERSION) - 1) + +#define MAX_DEV_ID 64 +#define MAX_TRIG_ID 64 +#define MAX_CHN_ID 64 +#define MAX_ATTR_NAME 256 + +enum iio_attr_type { + IIO_ATTR_TYPE_DEBUG, + IIO_ATTR_TYPE_BUFFER, + IIO_ATTR_TYPE_CH_OUT, + IIO_ATTR_TYPE_CH_IN, + IIO_ATTR_TYPE_DEVICE, +}; + +struct iiod_attr { + enum iio_attr_type type; + /* + * Attribute name. + * If empty (""), all attributes of the specified iio_attr_type must + * be read/wrote + */ + const char *name; + const char *channel; +}; + +struct iiod_ctx { + /* Value specified in iiod_init_param.instance in iiod_init */ + void *instance; + /* Value specified in iiod_conn_data.conn in iiod_conn_add */ + void *conn; +}; + +struct iiod_conn_data { + /* Value to be used in iiod_ctx */ + void *conn; + /* Buffer to store attributes or buffer data for a connection. */ + char *buf; + /* Size of the provided buffer. It must fit the max attribute size */ + uint32_t len; +}; + +/* Functions should return a negative error code on failure */ +struct iiod_ops { + /* + * I/O operations + * Send and recv are used to send or receive data to/from a connection. + * They should send/receive the at maximum len bytes. + * They must return the number of bytes sent/received. + * They can return 0 or -EAGAIN when no data was processed. + * They can do not block. They will be called again if there is still + * data to be sent/recevied + */ + int (*send)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len); + int (*recv)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len); + + /* + * This is the equivalent of libiio iio_device_create_buffer. + * Called in order to create a buffer to read or write data. + * read_buffer or write_buffer will follow with a maximum of samples + * (depending on the internal buffer). + * All calls with the same ctx will refer to this buffer until close is + * called. + */ + int (*open)(struct iiod_ctx *ctx, const char *device, uint32_t samples, + uint32_t mask, bool cyclic); + /* Equivalent of iio_buffer_destroy */ + int (*close)(struct iiod_ctx *ctx, const char *device); + + /* Read data from opened buffer */ + int (*read_buffer)(struct iiod_ctx *ctx, const char *device, char *buf, + uint32_t bytes); + /* Called to notify that buffer must be refiiled */ + int (*refill_buffer)(struct iiod_ctx *ctx, const char *device); + + /* Write data to opened buffer */ + int (*write_buffer)(struct iiod_ctx *ctx, const char *device, + const char *buf, uint32_t bytes); + /* Called to notify that buffer must be pushed to hardware */ + int (*push_buffer)(struct iiod_ctx *ctx, const char *device); + + /* + * Attribute has to be read in buf and return the number of bytes + * written. + */ + int (*read_attr)(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len); + /* Attribute buf is filled with the attribute value. */ + int (*write_attr)(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len); + /* Simular with read_attr but trigger must be filled */ + int (*get_trigger)(struct iiod_ctx *ctx, const char *device, + char *trigger, uint32_t len); + /* + * Simular with write_attr but trigger name is in trigger. + * If trigger is equals to "". Trigger must be removed. + */ + int (*set_trigger)(struct iiod_ctx *ctx, const char *device, + const char *trigger, uint32_t len); + + /* I don't know what this should be used for :) */ + int (*set_timeout)(struct iiod_ctx *ctx, uint32_t timeout); + + /* I don't know what this should be used for :) */ + int (*set_buffers_count)(struct iiod_ctx *ctx, const char *device, + uint32_t buffers_count); +}; + +/* + * Internal structure. + * It is created in iiod_init and must be passed to all fucntions + */ +struct iiod_desc; + +/* Parameter to initialize iiod_desc */ +struct iiod_init_param { + struct iiod_ops *ops; + /* Value to be send in each iiod_ctx from iiod_ops functions */ + void *instance; + /* + * Xml description of the context and devices. It should exist until + * iiod_remove is called + */ + char *xml; + /* Size of xml in bytes */ + uint32_t xml_len; + /* Backend used by IIOD */ + enum physical_link_type phy_type; +}; + +/* Initialize desc. */ +int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param); +/* Remove desc resources */ +void iiod_remove(struct iiod_desc *desc); + +/* + * Notify iiod about a new connection in order to store context for it. + * new_conn_id is set in order to reference the connection in iiod_conn_step + */ +int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data, + uint32_t *new_conn_id); +/* Remove conn_id from iiod. Provided data is returned in data */ +int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id, + struct iiod_conn_data *data); +/* Advance in the state machine of a connection. Will not block */ +int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id); + +#endif //IIOD_H diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod_private.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod_private.h new file mode 100644 index 0000000..ee1591f --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod_private.h @@ -0,0 +1,178 @@ +/***************************************************************************//** + * @file iiod_private.h + * @brief Private header file of iiod + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef IIOD_PRIVATE_H +#define IIOD_PRIVATE_H + +#include "iio.h" + +#define IIOD_WR 0x1 +#define IIOD_ENDL 0x2 +#define IIOD_RD 0x4 +#define IIOD_PARSER_MAX_BUF_SIZE 128 + +#define IIOD_STR(cmd) {(cmd), sizeof(cmd) - 1} + +#define IIOD_CTX(desc, conn) {.instance = (desc)->app_instance,\ + .conn = (conn)->conn} + + +/* Used to store a string and its size */ +struct iiod_str { + char *str; + uint32_t len; +}; + +/* + * Commads are the ones documented int the link: + * https://wiki.analog.com/resources/tools-software/linux-software/libiio_internals#the_network_backend_and_iio_daemon + */ +enum iiod_cmd { + IIOD_CMD_HELP, + IIOD_CMD_EXIT, + IIOD_CMD_PRINT, + IIOD_CMD_VERSION, + IIOD_CMD_TIMEOUT, + IIOD_CMD_OPEN, + IIOD_CMD_CLOSE, + IIOD_CMD_READ, + IIOD_CMD_WRITE, + IIOD_CMD_READBUF, + IIOD_CMD_WRITEBUF, + IIOD_CMD_GETTRIG, + IIOD_CMD_SETTRIG, + IIOD_CMD_SET +}; + +/* + * Structure to be filled after a command is parsed. + * Depending of cmd some fields are set or not + */ +struct comand_desc { + enum iiod_cmd cmd; + uint32_t mask; + uint32_t timeout; + uint32_t sample_count; + uint32_t bytes_count; + uint32_t count; + bool cyclic; + char device[MAX_DEV_ID]; + char channel[MAX_CHN_ID]; + char attr[MAX_ATTR_NAME]; + char trigger[MAX_TRIG_ID]; + enum iio_attr_type type; +}; + +/* Used to store buffer indexes for non blocking transfers */ +struct iiod_buff { + char *buf; + uint32_t idx; + uint32_t len; +}; + +/* Result after executing a command. */ +struct iiod_run_cmd_result { + uint32_t val; + /* If set. Val needs to be sent */ + bool write_val; + /* If buf.len != 0 buf has to be sent */ + struct iiod_buff buf; +}; + +/* Internal structure to handle a connection state */ +struct iiod_conn_priv { + /* User instance of the connection to be sent in iiod_ctx */ + void *conn; + /* Unset when can be used from the connection pool */ + bool used; + + /* Command data after parsed */ + struct comand_desc cmd_data; + /* Result of an executed cmd */ + struct iiod_run_cmd_result res; + /* IIOD States */ + enum { + /* Reading line until \n */ + IIOD_READING_LINE, + /* Execut cmd without I/O operations */ + IIOD_RUNNING_CMD, + /* Write result of executed cmd */ + IIOD_WRITING_CMD_RESULT, + /* I/O operations for READBUF and WRITEBUF cmds */ + IIOD_RW_BUF, + /* I/O operations for WRITE cmd */ + IIOD_READING_WRITE_DATA, + /* Set when a operation is finalized */ + IIOD_LINE_DONE, + /* Pushing cyclic buffer until IIO device is closed */ + IIOD_PUSH_CYCLIC_BUFFER, + } state; + + /* Buffer to store received line */ + char parser_buf[IIOD_PARSER_MAX_BUF_SIZE]; + /* Index in parser_buf. For nonblocking operation */ + uint32_t parser_idx; + /* Buffer to store raw data (attributes or buffer data).*/ + char *payload_buf; + /* Length of payload_buf_len */ + uint32_t payload_buf_len; + /* Used in nonbloking transfers to save indexes */ + struct iiod_buff nb_buf; + + /* Mask of current opened buffer */ + uint32_t mask; + /* Buffer to store mask as a string */ + char buf_mask[10]; + /* Context for strtok_r function */ + char *strtok_ctx; + /* True if the device was open with cyclic buffer flag */ + bool is_cyclic_buffer; +}; + +/* Private iiod information */ +struct iiod_desc { + /* Pool of iiod connections */ + struct iiod_conn_priv conns[IIOD_MAX_CONNECTIONS]; + /* Application operations */ + struct iiod_ops ops; + /* Application instance */ + void *app_instance; + /* Address of xml */ + char *xml; + /* XML length in bytes */ + uint32_t xml_len; + /* Backend used by IIOD */ + enum physical_link_type phy_type; +}; + +#endif //IIOD_PRIVATE_H diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/jesd204.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/jesd204.h new file mode 100644 index 0000000..a23b1c1 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/jesd204.h @@ -0,0 +1,295 @@ +/** + * The JESD204 framework + * + * Copyright (c) 2022 Analog Devices Inc. + */ +#ifndef _JESD204_H_ +#define _JESD204_H_ + +#include +#include +#include + +struct jesd204_dev; + +enum jesd204_subclass { + JESD204_SUBCLASS_0, + JESD204_SUBCLASS_1, + JESD204_SUBCLASS_2, +}; + +enum jesd204_version { + JESD204_VERSION_A, + JESD204_VERSION_B, + JESD204_VERSION_C, +}; + +/* JESD204C Supported encoding scheme */ +enum jesd204_encoder { + JESD204_ENCODER_UNKNOWN, + JESD204_ENCODER_8B10B, + JESD204_ENCODER_64B66B, + JESD204_ENCODER_64B80B, + + JESD204_ENCODER_MAX +}; + +enum jesd204_sysref_mode { + JESD204_SYSREF_DISABLED, + JESD204_SYSREF_CONTINUOUS, + JESD204_SYSREF_ONESHOT, +}; + +enum jesd204_state_change_result { + JESD204_STATE_CHANGE_ERROR = -1, + JESD204_STATE_CHANGE_DEFER = 0, + JESD204_STATE_CHANGE_DONE, +}; + +#define JESD204_LINKS_ALL ((unsigned int)(-1)) + +#define JESD204_LMFC_OFFSET_UNINITIALIZED ((uint16_t)-1) + +/** @struct jesd204_sysref + * @brief JESD204 parameters for SYSREF + * @param mode: SYSREF mode (see jesd204_sysref_mode) + * @param capture_falling_edge: true if it should capture falling edge + * @param valid_falling_edge: true if falling edge should be valid + * @param lmfc_offset: offset for LMFC + */ +struct jesd204_sysref { + enum jesd204_sysref_mode mode; + uint8_t capture_falling_edge; + uint8_t valid_falling_edge; + uint16_t lmfc_offset; +}; + +/** + * @struct jesd204_link + * @brief JESD204 link configuration settings + * @param link_id: JESD204 link ID provided via DT configuration + * @param error: error code for this JESD204 link + * @param is_transmit: true if this link is transmit (digital to analog) + * @param sample_rate: sample rate for the link + * @param sample_rate_div: optional sample rate divider for the link + * final rate = sample_rate / sample_rate_div + * @param num_lanes: number of JESD204 lanes (L) + * @param num_converters: number of converters per link (M) + * @param octets_per_frame: number of octets per frame (F) + * @param frames_per_multiframe: number of frames per frame (K) + * @param num_of_multiblocks_in_emb: number of multiblocks in extended multiblock (E) (JESD204C) + * @param bits_per_sample: number of bits per sample (N') + * @param converter_resolution: converter resolution (N) + * @param jesd_version: JESD204 version (A, B or C) (JESDV) + * @param jesd_encoder: JESD204C encoder (8B10B, 64B66B, 64B80B) + * @param subclass: JESD204 subclass (0,1 or 2) (SUBCLASSV) + * @param device_id: device ID (DID) + * @param bank_id: bank ID (BID) + * @param scrambling: true if scrambling enabled (SCR) + * @param high_density: true if high-density format is used (HD) + * @param ctrl_words_per_frame_clk: number of control words per frame clock + * period (CF) + * @param ctrl_bits_per_sample: number of control bits per sample (CS) + * @param samples_per_conv_frame: number of samples per converter per frame + * cycle (S) + * @param lane_ids: array of lane IDs (LID); note that this is an + * array the size of num_lanes + * @param sysref: JESD204 sysref config, see jesd204_sysref + * @param dac_adj_resolution_steps: number of adjustment resolution steps to adjust + * DAC LMFC (ADJCNT) - Subclass 2 only + * @param dac_adj_direction: direction to adjust DAC LMFC (ADJDIR) + * Subclass 2 only + * @param dac_phase_adj: true to do phase adjustment request to DAC + * Subclass 2 only + */ +struct jesd204_link { + uint32_t link_id; + int error; + + uint64_t sample_rate; + uint32_t sample_rate_div; + + bool is_transmit; + + uint8_t num_lanes; + uint8_t num_converters; + uint8_t octets_per_frame; + uint16_t frames_per_multiframe; + uint8_t num_of_multiblocks_in_emb; /* E */ + + uint8_t bits_per_sample; + + uint8_t converter_resolution; + uint8_t jesd_version; + uint8_t jesd_encoder; + uint8_t subclass; + + uint8_t device_id; + uint8_t bank_id; + + uint8_t scrambling; + uint8_t high_density; + + uint8_t ctrl_words_per_frame_clk; + uint8_t ctrl_bits_per_sample; + uint8_t samples_per_conv_frame; + + uint8_t *lane_ids; + + struct jesd204_sysref sysref; + + /* Subclass 2 only */ + uint8_t dac_adj_resolution_steps; + uint8_t dac_adj_direction; + uint8_t dac_phase_adj; +}; + +enum jesd204_state_op_reason { + JESD204_STATE_OP_REASON_INIT, + JESD204_STATE_OP_REASON_UNINIT, +}; + +static inline const char *jesd204_state_op_reason_str(enum + jesd204_state_op_reason reason) +{ + switch (reason) { + case JESD204_STATE_OP_REASON_INIT: + return "initialization"; + case JESD204_STATE_OP_REASON_UNINIT: + return "uninitialization"; + default: + return "unknown"; + } +} + +typedef int (*jesd204_sysref_cb)(struct jesd204_dev *jdev); + +typedef int (*jesd204_dev_cb)(struct jesd204_dev *jdev, + enum jesd204_state_op_reason reason); + +typedef int (*jesd204_link_cb)(struct jesd204_dev *jdev, + enum jesd204_state_op_reason, + struct jesd204_link *lnk); + +enum jesd204_state_op_mode { + JESD204_STATE_OP_MODE_PER_LINK, + JESD204_STATE_OP_MODE_PER_DEVICE, +}; + +/** + * @struct jesd204_state_op + * @brief JESD204 device per-state op + * @param mode: mode for this state op, depending on this per_device or per_link is called + * @param per_device: op called for each JESD204 **device** during a transition + * @param per_link op called for each JESD204 **link** individually during a transition + * // FIXME: maybe pass 'struct jesd204_sysref' for post_state_sysref, to make this configurable? we'll see later + * // FIXME: for now, the device should also be a top-level device, in case of multi-chip setups + * @param post_state_sysref: true if a SYSREF should be issued after the state change + */ +struct jesd204_state_op { + enum jesd204_state_op_mode mode; + jesd204_dev_cb per_device; + jesd204_link_cb per_link; + bool post_state_sysref; +}; + +enum jesd204_dev_op { + JESD204_OP_DEVICE_INIT, + JESD204_OP_LINK_INIT, + JESD204_OP_LINK_SUPPORTED, + JESD204_OP_LINK_PRE_SETUP, + JESD204_OP_CLK_SYNC_STAGE1, + JESD204_OP_CLK_SYNC_STAGE2, + JESD204_OP_CLK_SYNC_STAGE3, + JESD204_OP_LINK_SETUP, + JESD204_OP_OPT_SETUP_STAGE1, + JESD204_OP_OPT_SETUP_STAGE2, + JESD204_OP_OPT_SETUP_STAGE3, + JESD204_OP_OPT_SETUP_STAGE4, + JESD204_OP_OPT_SETUP_STAGE5, + JESD204_OP_CLOCKS_ENABLE, + JESD204_OP_LINK_ENABLE, + JESD204_OP_LINK_RUNNING, + JESD204_OP_OPT_POST_RUNNING_STAGE, + + __JESD204_MAX_OPS, +}; + +/** + * @struct jesd204_dev_data + * @brief JESD204 device initialization data + * @param sysref_cb: SYSREF callback, if this device/driver supports it + * @param sizeof_priv: amount of data to allocate for private information + * @param max_num_links: maximum number of JESD204 links this device can support + * @param num_retries: number of retries in case of error (only for top-level device) + * @param state_ops: ops for each state transition of type @struct jesd204_state_op + */ +struct jesd204_dev_data { + jesd204_sysref_cb sysref_cb; + size_t sizeof_priv; + unsigned int max_num_links; + unsigned int num_retries; + struct jesd204_state_op state_ops[__JESD204_MAX_OPS]; +}; + +/* no-OS specific */ +#define JESD204_MAX_TOPOLOGY_LINKS 16 + +/* no-OS specific */ +struct jesd204_topology_dev { + struct jesd204_dev *jdev; + bool is_top_device; + bool is_sysref_provider; + unsigned int link_ids[JESD204_MAX_TOPOLOGY_LINKS]; + unsigned int links_number; +}; + +/* no-OS specific */ +struct jesd204_topology { + struct jesd204_dev_top *dev_top; + struct jesd204_topology_dev *devs; + unsigned int devs_number; +}; + +/* no-OS specific */ +int jesd204_dev_register(struct jesd204_dev **jdev, + const struct jesd204_dev_data *dev_data); + +/* no-OS specific */ +int jesd204_dev_unregister(struct jesd204_dev *jdev); + +/* no-OS specific */ +int jesd204_topology_init(struct jesd204_topology **topology, + struct jesd204_topology_dev *devs, + unsigned int devs_number); + +/* no-OS specific */ +int jesd204_topology_remove(struct jesd204_topology *topology); + +/* no-OS specific */ +int jesd204_fsm_start(struct jesd204_topology *topology, unsigned int link_idx); + +/* no-OS specific */ +int jesd204_fsm_stop(struct jesd204_topology *topology, unsigned int link_idx); + +void *jesd204_dev_priv(struct jesd204_dev *jdev); + +int jesd204_link_get_lmfc_lemc_rate(struct jesd204_link *lnk, + unsigned long *rate_hz); + +int jesd204_link_get_rate_khz(struct jesd204_link *lnk, + unsigned long *lane_rate_khz); + +int jesd204_link_get_device_clock(struct jesd204_link *lnk, + unsigned long *device_clock); + +int jesd204_sysref_async(struct jesd204_dev *jdev); + +int jesd204_sysref_async_force(struct jesd204_dev *jdev); + +bool jesd204_dev_is_top(struct jesd204_dev *jdev); + +void jesd204_copy_link_params(struct jesd204_link *dst, + const struct jesd204_link *src); + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_ain.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_ain.h new file mode 100644 index 0000000..bdecf43 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_ain.h @@ -0,0 +1,70 @@ +/***************************************************************************//** + * @file no_os_ain.h + * @author PMallick (Pratyush.Mallick@analog.com) +******************************************************************************** + * Copyright (c) 2021-22 Analog Devices, Inc. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef NO_OS_AIN_H +#define NO_OS_AIN_H + +#include + + +/** + * @struct ain_init_param + * @brief Structure holding parameters for analog input initialization + */ +struct no_os_ain_init_param { + /* Analog input reference voltage */ + float vref; + /* Analog extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct ain_desc + * @brief Structure holding analog input descriptor + */ +struct no_os_ain_desc { + /* Analog input reference voltage */ + float vref; + /* Analog extra parameters (device specific) */ + void *extra; +}; + +/* Read analog input voltage */ +int32_t no_os_ain_get_voltage(struct no_os_ain_desc *desc, float *value); + +/* Initialize the analog input peripheral*/ +int32_t no_os_ain_init(struct no_os_ain_desc **desc, + const struct no_os_ain_init_param *param); + +/* Free the resources allocated by no_os_ain_init() */ +int32_t no_os_ain_remove(struct no_os_ain_desc *desc); + +#endif // end of NO_OS_AIN_H diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.c new file mode 100644 index 0000000..cf5a12c --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.c @@ -0,0 +1,67 @@ +/******************************************************************************* + * @file util/no_os_alloc.c + * @brief Implementation of no-OS memory allocation functions. + * @author GMois (george.mois@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include "no_os_alloc.h" + +/** + * @brief Allocate memory and return a pointer to it. + * @param size - Size of the memory block, in bytes. + * @return Pointer to the allocated memory, or NULL if the request fails. + */ +__attribute__((weak)) void *no_os_malloc(size_t size) +{ + return malloc(size); +} + +/** + * @brief Allocate memory and return a pointer to it, set memory to 0. + * @param nitems - Number of elements to be allocated. + * @param size - Size of elements. + * @return Pointer to the allocated memory, or NULL if the request fails. + */ +__attribute__((weak)) void *no_os_calloc(size_t nitems, size_t size) +{ + return calloc(nitems, size); +} + +/** + * @brief Deallocate memory previously allocated by a call to no_os_calloc + * or no_os_malloc. + * @param ptr - Pointer to a memory block previously allocated by a call + * to no_os_calloc or no_os_malloc. + * @return None. + */ +__attribute__((weak)) void no_os_free(void *ptr) +{ + free(ptr); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.h new file mode 100644 index 0000000..51f6567 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_alloc.h @@ -0,0 +1,49 @@ +/******************************************************************************* + * @file no_os_alloc.h + * @brief Header file of memory allocator. + * @author GMois (george.mois@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_ALLOC_H_ +#define _NO_OS_ALLOC_H_ + +#include +#include + +/* Allocate memory and return a pointer to it */ +void *no_os_malloc(size_t size); + +/* Allocate memory and return a pointer to it, set memory to 0 */ +void *no_os_calloc(size_t nitems, size_t size); + +/* Deallocate memory previously allocated by a call to no_os_calloc or + * no_os_malloc */ +void no_os_free(void *ptr); + +#endif // _NO_OS_ALLOC_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_aout.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_aout.h new file mode 100644 index 0000000..95a22f7 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_aout.h @@ -0,0 +1,78 @@ +/***************************************************************************//** + * @file no_os_aout.h + * @author PMallick (Pratyush.Mallick@analog.com) +******************************************************************************** + * Copyright (c) 2021-22 Analog Devices, Inc. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef NO_OS_AOUT_H +#define NO_OS_AOUT_H + +#include + + +/** + * @struct aout_init_param + * @brief Structure holding the parameters for analog output initialization + */ +struct no_os_aout_init_param { + /* Min output range of DAC in volts */ + float aout_min_v; + /* Max output range of DAC in volts */ + float aout_max_v; + /* Analog output reference voltage */ + float vref; + /* Analog extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct aout_desc + * @brief Structure holding analog output descriptor + */ +struct no_os_aout_desc { + /* Min output value of DAC in volts */ + float aout_min_v; + /* Max output value of DAC in volts */ + float aout_max_v; + /* Analog output reference voltage */ + float vref; + /* Analog extra parameters (device specific) */ + void *extra; +}; + +/* Write analog output voltage */ +int32_t no_os_aout_set_voltage(struct no_os_aout_desc *desc, float value); + +/* Initialize the analog output peripheral */ +int32_t no_so_aout_init(struct no_os_aout_desc **desc, + const struct no_os_aout_init_param *param); + +/* Free the resources allocated by no_os_aout_init() */ +int32_t no_os_aout_remove(struct no_os_aout_desc *desc); + +#endif // end of NO_OS_AOUT_H diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_axi_io.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_axi_io.h new file mode 100644 index 0000000..c346559 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_axi_io.h @@ -0,0 +1,45 @@ +/***************************************************************************//** + * @file no_os_axi_io.h + * @brief Header file of AXI IO. + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_AXI_IO_H_ +#define _NO_OS_AXI_IO_H_ + +#include + +/* AXI IO Read data */ +int32_t no_os_axi_io_read(uint32_t base, uint32_t offset, uint32_t *data); + +/* AXI IO Write data */ +int32_t no_os_axi_io_write(uint32_t base, uint32_t offset, uint32_t data); + +#endif // _NO_OS_AXI_IO_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.c new file mode 100644 index 0000000..008aff8 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.c @@ -0,0 +1,390 @@ +/***************************************************************************//** + * @file no_os_circular_buffer.c + * @brief Circular buffer implementation + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include +#include "no_os_circular_buffer.h" +#include "no_os_error.h" +#include "no_os_util.h" +#include "no_os_alloc.h" + +int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buff, + uint32_t size) +{ + if (!desc) + return -EINVAL; + + memset(desc, 0, sizeof(*desc)); + desc->size = size; + desc->buff = buff; + + return 0; +} + +/** + * @brief Create circular buffer structure. + * + * @note Circular buffer implementation is thread safe for one write + * and one reader. + * If multiple writer or multiple readers access the circular buffer then + * function that updates the structure should be called inside a critical + * critical section. + * + * @param desc - Where to store the circular buffer reference + * @param buff_size - Buffer size + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t buff_size) +{ + struct no_os_circular_buffer *ldesc; + + if (!desc || !buff_size) + return -EINVAL; + + ldesc = (struct no_os_circular_buffer*)no_os_calloc(1, sizeof(*ldesc)); + if (!ldesc) + return -ENOMEM; + + *desc = ldesc; + + ldesc->size = buff_size; + ldesc->buff = no_os_calloc(1, buff_size); + if (!ldesc->buff) { + no_os_free(ldesc); + return -ENOMEM; + } + + return 0; +} + +/** + * @brief Free the resources allocated for the circular buffer structure. + * @param desc - Circular buffer reference + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_cb_remove(struct no_os_circular_buffer *desc) +{ + if (!desc) + return -1; + + if (desc->buff) + no_os_free(desc->buff); + no_os_free(desc); + + return 0; +} + +/** + * @brief Get the number of elements in the buffer. + * @param desc - Circular buffer reference + * @param size - Where to store size of data available to read + * @return + * - 0 - No errors + * - -EINVAL - Wrong parameters used + * - -NO_OS_EOVERRUN - A buffer overrun occurred + */ +int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size) +{ + uint32_t nb_spins; + + if (!desc || !size) + return -EINVAL; + + if (desc->write.spin_count > desc->read.spin_count) + nb_spins = desc->write.spin_count - desc->read.spin_count; + else + /* Integer overflow on desc->write.spin_count */ + nb_spins = UINT32_MAX - desc->read.spin_count + + desc->write.spin_count + 1; + + if (nb_spins > 0) + *size = desc->size + desc->write.idx - desc->read.idx; + else + *size = desc->write.idx - desc->read.idx; + + if (*size > desc->size) { + *size = desc->size; + return -NO_OS_EOVERRUN; + } + + return 0; +} + +/* + * Functionality described at no_os_cb_prepare_async_write/read having the is_read + * parameter to specifiy if it is a read or write operation. + */ +static int32_t no_os_cb_prepare_async_operation(struct no_os_circular_buffer + *desc, + uint32_t requested_size, + void **buff, + uint32_t *raw_size_available, + bool is_read) +{ + struct no_os_cb_ptr *ptr; + uint32_t available_size; + int32_t ret; + + if (!desc || !buff || !raw_size_available) + return -EINVAL; + + ret = 0; + /* Select if read or write index will be updated */ + ptr = is_read ? &desc->read : &desc->write; + + /* Only one transaction type possible at a single time */ + if (ptr->async_started) + return -EBUSY; + + if (is_read) { + ret = no_os_cb_size(desc, &available_size); + if (ret == -NO_OS_EOVERRUN) { + /* Update read index */ + desc->read.spin_count = desc->write.spin_count - 1; +#ifndef IIO_IGNORE_BUFF_OVERRUN_ERR + desc->read.idx = desc->write.idx; +#endif + } + if (!available_size) + /* No data to read */ + return 0; + + /* We can only read available data */ + requested_size = no_os_min(requested_size, available_size); + if (!requested_size) + return -EAGAIN; + } + + /* Size to end of buffer */ + ptr->async_size = no_os_min(requested_size, desc->size - ptr->idx); + + *raw_size_available = ptr->async_size; + + /* Convert index to address in the buffer */ + *buff = (void *)(desc->buff + ptr->idx); + + ptr->async_started = true; + + return ret; +} + +/* + * Functionality described at no_os_cb_end_async_write/read having the is_read + * parameter to specifiy if it is a read or write operation. + */ +static int32_t no_os_cb_end_async_operation(struct no_os_circular_buffer *desc, + bool is_read) +{ + struct no_os_cb_ptr *ptr; + uint32_t new_val; + + + if (!desc) + return -EINVAL; + + /* Select if read or write index will be updated */ + ptr = is_read ? &desc->read : &desc->write; + + /* Transaction not started */ + if (!ptr->async_started) + return -1; + + /* Update pointer value */ + new_val = ptr->idx + ptr->async_size; + if (new_val >= desc->size) { + ptr->spin_count++; + new_val %= desc->size; + } + ptr->idx = new_val; + ptr->async_size = 0; + ptr->async_started = false; + + return 0; +} + +/* + * Functionality described at cb_write/read having the is_read + * parameter to specifiy if it is a read or write operation. + */ +static int32_t no_os_cb_operation(struct no_os_circular_buffer *desc, + void *data, uint32_t size, + bool is_read) +{ + uint8_t *buff; + uint32_t available_size = 0; + int32_t ret; + uint32_t i; + bool sticky_overrun; + + if (!desc || !data || !size) + return -EINVAL; + + sticky_overrun = 0; + i = 0; + while (i < size) { + do { + ret = no_os_cb_prepare_async_operation(desc, size - i, + (void **)&buff, + &available_size, + is_read); + } while (ret == -EBUSY || ret == -EAGAIN); + if (ret == -NO_OS_EOVERRUN) + sticky_overrun = true; + + /* If no data is available return error */ + if (!available_size) + return -1; + + if (is_read) + memcpy((uint8_t *)data + i, buff, available_size); + else + memcpy(buff, (uint8_t *)data + i, available_size); + + no_os_cb_end_async_operation(desc, is_read); + + i += available_size; + } + + if (sticky_overrun) + return -NO_OS_EOVERRUN; + + return 0; +} + +/** + * @brief Prepare asynchronous write. + * + * Get the inside raw buffer to be used in DMA transactions. + * + * @param desc - Circular buffer reference + * @param size_to_write - Number of bytes needed to write to the buffer. + * @param write_buff - Address where to store the buffer where to write to. + * @param size_avilable - no_os_min(size_to_write, size until end of allocated buffer) + * @return + * - 0 - No errors + * - -EINVAL - Wrong parameters used + * - -EBUSY - Asynchronous transaction already started + */ +int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc, + uint32_t size_to_write, + void **write_buff, + uint32_t *size_avilable) +{ + return no_os_cb_prepare_async_operation(desc, size_to_write, write_buff, + size_avilable, 0); +} + +/** + * @brief Prepare asynchronous read. + * + * Get the inside raw buffer to be used in DMA transactions. + * + * @param desc - Circular buffer reference + * @param size_to_read - Number of bytes needed to write to the buffer. + * @param read_buff - Address where to store the buffer where data will be read. + * @param size_avilable - no_os_min(size_to_read, size until end of allocated buffer) + * @return + * - 0 - No errors + * - -EAGAIN - No data available at this moment + * - -EINVAL - Wrong parameters used + * - -EBUSY - Asynchronous transaction already started + * - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten + */ +int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc, + uint32_t size_to_read, + void **read_buff, + uint32_t *size_avilable) +{ + return no_os_cb_prepare_async_operation(desc, size_to_read, read_buff, + size_avilable, 1); +} + +/** + * \defgroup end_async_group End Ashyncronous functions + * @brief End asynchronous transaction. + * + * @param desc - Circular buffer reference + * @return + * - 0 - No errors + * - -1 - Asynchronous transaction not started + * - -EINVAL - Wrong parameters used + * @{ + */ +int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc) +{ + return no_os_cb_end_async_operation(desc, 0); +} + +int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc) +{ + + return no_os_cb_end_async_operation(desc, 1); +} +/** @} */ + +/** + * @brief Write data to the buffer (Blocking). + * @param desc - Circular buffer reference + * @param data - Buffer from where data is copied to the circular buffer + * @param size - Size to write + * @return + * - 0 - No errors + * - -EINVAL - Wrong parameters used + */ +int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data, + uint32_t size) +{ + return no_os_cb_operation(desc, (void *)data, size, 0); +} + +/** + * @brief Read data from the buffer (Blocking). + * @param desc - Circular buffer reference + * @param data - Buffer where to data is copied from the circular buffer + * @param size - Size to read + * @return + * - 0 - No errors + * - -EINVAL - Wrong parameters used + * - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten + */ +int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data, + uint32_t size) +{ + return no_os_cb_operation(desc, data, size, 1); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.h new file mode 100644 index 0000000..f5bec93 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_circular_buffer.h @@ -0,0 +1,94 @@ +/***************************************************************************//** + * @file no_os_circular_buffer.h + * @brief Circular buffer library header + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_CIRCULAR_BUFFER_H_ +#define _NO_OS_CIRCULAR_BUFFER_H_ + +#include + +/** + * @struct no_os_cb_ptr + * @brief Circular buffer pointer + */ +struct no_os_cb_ptr { + /** Index of data in the buffer */ + uint32_t idx; + /** Counts the number of times idx exceeds the liniar buffer */ + uint32_t spin_count; + /** Set if async transaction is active */ + bool async_started; + /** Number of bytes to update after an async transaction is finished */ + uint32_t async_size; +}; + +/** + * @struct no_os_circular_buffer + * @brief Circular buffer descriptor + */ +struct no_os_circular_buffer { + /** Size of the buffer in bytes */ + uint32_t size; + /** Address of the buffer */ + int8_t *buff; + /** Write pointer */ + struct no_os_cb_ptr write; + /** Read pointer */ + struct no_os_cb_ptr read; +}; + +int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t size); +/* Configure cb structure with given parameters without memory allocation */ +int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buf, + uint32_t size); +int32_t no_os_cb_remove(struct no_os_circular_buffer *desc); +int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size); + +int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data, + uint32_t nb_elements); +int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data, + uint32_t nb_elements); + +int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc, + uint32_t raw_size_to_write, + void **write_buff, + uint32_t *raw_size_avilable); +int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc); + +int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc, + uint32_t raw_size_to_read, + void **read_buff, + uint32_t *raw_size_avilable); +int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc); + +#endif //_NO_OS_CIRCULAR_BUFFER_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.c new file mode 100644 index 0000000..8c80d34 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.c @@ -0,0 +1,193 @@ +/***************************************************************************//** + * @file no_os_clk.c + * @brief Implementation of Clock Driver. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ +#include "no_os_alloc.h" +#include "no_os_error.h" +#include "no_os_clk.h" + +/******************************************************************************/ +/************************** Functions Implementation **************************/ +/******************************************************************************/ +/** + * Initialize clock. + * @param desc - CLK descriptor. + * @param param - The structure that contains CLK parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_clk_init(struct no_os_clk_desc **desc, + const struct no_os_clk_init_param *param) +{ + struct no_os_clk_desc *clk; + int ret; + + if (!desc || !param || !param->platform_ops) + return -EINVAL; + + clk = (struct no_os_clk_desc *)no_os_calloc(1, sizeof(*clk)); + if (!clk) + return -ENOMEM; + + clk->name = param->name; + clk->hw_ch_num = param->hw_ch_num; + clk->dev_desc = param->dev_desc; + clk->platform_ops = param->platform_ops; + + if (param->platform_ops->init) { + ret = param->platform_ops->init(desc, param); + if (ret) + goto error; + } + + *desc = clk; + + return 0; + +error: + no_os_free(clk); + + return ret; +} + +/** + * @brief Free the resources allocated by no_os_clk_init(). + * @param desc - The clock descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_clk_remove(struct no_os_clk_desc *desc) +{ + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (desc->platform_ops->remove) { + ret = desc->platform_ops->remove(desc); + if (ret) + return ret; + } + + no_os_free(desc); + + return 0; +} + +/** + * Start the clock. + * @param clk - The clock descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_clk_enable(struct no_os_clk_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->clk_enable) + return -ENOSYS; + + return desc->platform_ops->clk_enable(desc); +} + +/** + * Stop the clock. + * @param clk - The clock descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_clk_disable(struct no_os_clk_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->clk_disable) + return -ENOSYS; + + return desc->platform_ops->clk_disable(desc); +} + +/** + * Get the current frequency of the clock. + * @param clk - The clock descriptor. + * @param rate - The current frequency. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc, + uint64_t *rate) +{ + if (!desc || !desc->platform_ops || !rate) + return -EINVAL; + + if (!desc->platform_ops->clk_recalc_rate) + return -ENOSYS; + + return desc->platform_ops->clk_recalc_rate(desc, rate); +} + +/** + * Round the desired frequency to a rate that the clock can actually output. + * @param clk - The clock descriptor. + * @param rate - The desired frequency. + * @param rounded_rate - The rounded frequency. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc, + uint64_t rate, + uint64_t *rounded_rate) +{ + if (!desc || !desc->platform_ops || !rounded_rate) + return -EINVAL; + + if (!desc->platform_ops->clk_round_rate) + return -ENOSYS; + + return desc->platform_ops->clk_round_rate(desc, rate, rounded_rate); +} + +/** + * Change the frequency of the clock. + * @param clk - The clock descriptor. + * @param rate - The desired frequency. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc, + uint64_t rate) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->clk_set_rate) + return -ENOSYS; + + return desc->platform_ops->clk_set_rate(desc, rate); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.h new file mode 100644 index 0000000..9a6ba9d --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.h @@ -0,0 +1,128 @@ +/***************************************************************************//** + * @file no_os_clk.h + * @brief Header file of Clock Driver. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_CLK_H_ +#define _NO_OS_CLK_H_ + +#include + +struct no_os_clk_init_param { + /** Device name */ + const char *name; + /** Channel number */ + uint8_t hw_ch_num; + /** CLK function pointers */ + const struct no_os_clk_platform_ops *platform_ops; + /** CLK hardware device descriptor */ + void *dev_desc; +}; + +struct no_os_clk_hw { + void *dev; + int32_t (*dev_clk_enable)(); + int32_t (*dev_clk_disable)(); + int32_t (*dev_clk_recalc_rate)(); + int32_t (*dev_clk_set_rate)(); + int32_t (*dev_clk_round_rate)(); +}; + +struct no_os_clk { + struct no_os_clk_hw *hw; + uint32_t hw_ch_num; + const char *name; + const struct no_os_clk_desc *clk_desc; +}; + +/** + * @struct no_os_clk_desc + * @brief Structure holding CLK descriptor. + */ +typedef struct no_os_clk_desc { + /** Device name */ + const char *name; + /** Channel number */ + uint8_t hw_ch_num; + /** CLK function pointers */ + const struct no_os_clk_platform_ops *platform_ops; + /** CLK hardware device descriptor */ + void *dev_desc; +} no_os_clk_desc; + +/** + * @struct no_os_clk_platform_ops + * @brief Structure holding CLK function pointers that point to the platform + * specific function + */ +struct no_os_clk_platform_ops { + /** Initialize CLK function pointer. */ + int (*init)(struct no_os_clk_desc **, const struct no_os_clk_init_param *); + /** Start CLK function pointer. */ + int (*clk_enable)(struct no_os_clk_desc *); + /** Stop CLK function pointer. */ + int (*clk_disable)(struct no_os_clk_desc *); + /** Get the current frequency of CLK function pointer. */ + int (*clk_recalc_rate)(struct no_os_clk_desc *, uint64_t *); + /* Round the desired frequency to a rate that CLK can actually output. */ + int (*clk_round_rate)(struct no_os_clk_desc *, uint64_t, uint64_t *); + /* Change CLK frequency function pointer. */ + int (*clk_set_rate)(struct no_os_clk_desc *, uint64_t); + /** CLK remove function pointer */ + int (*remove)(struct no_os_clk_desc *); +}; + +/* Initialize CLK ops. */ +int32_t no_os_clk_init(struct no_os_clk_desc **desc, + const struct no_os_clk_init_param *param); + +/* Free the resources allocated by no_os_clk_init(). */ +int32_t no_os_clk_remove(struct no_os_clk_desc *desc); + +/* Start the clock. */ +int32_t no_os_clk_enable(struct no_os_clk_desc *desc); + +/* Stop the clock. */ +int32_t no_os_clk_disable(struct no_os_clk_desc *desc); + +/* Get the current frequency of the clock. */ +int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc, + uint64_t *rate); + +/* Round the desired frequency to a rate that the clock can actually output. */ +int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc, + uint64_t rate, + uint64_t *rounded_rate); + +/* Change the frequency of the clock. */ +int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc, + uint64_t rate); + +#endif // _NO_OS_CLK_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc.h new file mode 100644 index 0000000..f90ceb2 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc.h @@ -0,0 +1,40 @@ +/***************************************************************************//** + * @file no_os_crc.h + * @brief Generic header file for all CRC computation algorithms. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_CRC_H_ +#define _NO_OS_CRC_H_ + +#include "no_os_crc8.h" +#include "no_os_crc16.h" +#include "no_os_crc24.h" + +#endif // _NO_OS_CRC_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.c new file mode 100644 index 0000000..db12788 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.c @@ -0,0 +1,97 @@ +/***************************************************************************//** + * @file no_os_crc16.c + * @brief Source file of CRC-16 computation. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "no_os_crc16.h" + +/***************************************************************************//** + * @brief Creates the CRC-16 lookup table for a given polynomial. + * + * @param table - Pointer to a CRC-16 lookup table to write to. + * @param polynomial - Msb-first representation of desired polynomial. + * + * Polynomials in CRC algorithms are typically represented as shown below. + * + * poly = x^16 + x^14 + x^13 + x^12 + x^10 + x^8 + x^6 + x^4 + x^3 + + * x^1 + 1 + * + * Using msb-first direction, x^15 maps to the msb. + * + * msb first: poly = (1)0111010101011011 = 0x755B + * ^ + * + * @return None. +*******************************************************************************/ +void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial) +{ + if (!table) + return; + + for (int16_t n = 0; n < NO_OS_CRC16_TABLE_SIZE; n++) { + uint16_t currByte = (uint16_t)(n << 8); + for (uint8_t bit = 0; bit < 8; bit++) { + if ((currByte & 0x8000) != 0) { + currByte <<= 1; + currByte ^= polynomial; + } else { + currByte <<= 1; + } + } + table[n] = currByte; + } +} + +/***************************************************************************//** + * @brief Computes the CRC-16 over a buffer of data. + * + * @param table - Pointer to a CRC-16 lookup table for the desired polynomial. + * @param pdata - Pointer to data buffer. + * @param nbytes - Number of bytes to compute the CRC-16 over. + * @param crc - Initial value for the CRC-16 computation. Can be used to + * cascade calls to this function by providing a previous + * output of this function as the crc parameter. + * + * @return crc - Computed CRC-16 value. +*******************************************************************************/ +uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata, + size_t nbytes, + uint16_t crc) +{ + unsigned int idx; + + while (nbytes--) { + idx = ((crc >> 8) ^ *pdata) & 0xff; + crc = (table[idx] ^ (crc << 8)) & 0xffff; + pdata++; + } + + return crc; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.h new file mode 100644 index 0000000..a168e4d --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc16.h @@ -0,0 +1,49 @@ +/***************************************************************************//** + * @file no_os_crc16.h + * @brief Header file of CRC-16 computation. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_CRC16_H_ +#define _NO_OS_CRC16_H_ + +#include +#include + +#define NO_OS_CRC16_TABLE_SIZE 256 + +#define NO_OS_DECLARE_CRC16_TABLE(_table) \ + static uint16_t _table[NO_OS_CRC16_TABLE_SIZE] + +void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial); +uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata, + size_t nbytes, + uint16_t crc); + +#endif // _NO_OS_CRC16_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.c new file mode 100644 index 0000000..dbeeae0 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.c @@ -0,0 +1,98 @@ +/***************************************************************************//** + * @file no_os_crc24.c + * @brief Source file of CRC-24 computation. + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "no_os_crc24.h" + +/***************************************************************************//** + * @brief Creates the CRC-24 lookup table for a given polynomial. + * + * @param table - Pointer to a CRC-24 lookup table to write to. + * @param polynomial - msb-first representation of desired polynomial. + * + * Polynomials in CRC algorithms are typically represented as shown below. + * + * poly = x^24 + x^22 + x^20 + x^19 + x^18 + x^16 + x^14 + x^13 + x^11 + + * x^10 + x^8 + x^7 + x^6 + x^3 + x^1 + 1 + * + * Using msb-first direction, x^24 maps to the msb. + * + * msb first: poly = (1)010111010110110111001011 = 5D6DCB + * ^ + * + * @return None. +*******************************************************************************/ +void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial) +{ + if (!table) + return; + + for (int16_t n = 0; n < NO_OS_CRC24_TABLE_SIZE; n++) { + uint32_t currByte = (uint32_t)(n << 16); + for (uint8_t bit = 0; bit < 8; bit++) { + if ((currByte & 0x800000) != 0) { + currByte &= 0x7FFFFF; + currByte <<= 1; + currByte ^= polynomial; + } else { + currByte <<= 1; + } + } + table[n] = currByte; + } +} + +/***************************************************************************//** + * @brief Computes the CRC-24 over a buffer of data. + * + * @param table - Pointer to a CRC-24 lookup table for the desired polynomial. + * @param pdata - Pointer to data buffer. + * @param nbytes - Number of bytes to compute the CRC-24 over. + * @param crc - Initial value for the CRC-24 computation. Can be used to + * cascade calls to this function by providing a previous + * output of this function as the crc parameter. + * + * @return crc - Computed CRC-24 value. +*******************************************************************************/ +uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata, + size_t nbytes, + uint32_t crc) +{ + unsigned int idx; + + while (nbytes--) { + idx = ((crc >> 16) ^ *pdata) & 0xff; + crc = (table[idx] ^ (crc << 8)) & 0xffffff; + pdata++; + } + + return (crc & 0xffffff); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.h new file mode 100644 index 0000000..854a2ef --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc24.h @@ -0,0 +1,49 @@ +/***************************************************************************//** + * @file no_os_crc24.h + * @brief Header file of CRC-24 computation. + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_CRC24_H_ +#define _NO_OS_CRC24_H_ + +#include +#include + +#define NO_OS_CRC24_TABLE_SIZE 256 + +#define NO_OS_DECLARE_CRC24_TABLE(_table) \ + static uint32_t _table[NO_OS_CRC24_TABLE_SIZE] + +void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial); +uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata, + size_t nbytes, + uint32_t crc); + +#endif // _NO_OS_CRC24_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.c new file mode 100644 index 0000000..3a8d15c --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.c @@ -0,0 +1,94 @@ +/***************************************************************************//** + * @file no_os_crc8.c + * @brief Source file of CRC-8 computation. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "no_os_crc8.h" + +/***************************************************************************//** + * @brief Creates the CRC-8 lookup table for a given polynomial. + * + * @param table - Pointer to a CRC-8 lookup table to write to. + * @param polynomial - msb-first representation of desired polynomial. + * + * Polynomials in CRC algorithms are typically represented as shown below. + * + * poly = x^8 + x^2 + x^1 + 1 + * + * Using msb-first direction, x^7 maps to the msb. + * + * msb first: poly = (1)00000111 = 0x07 + * + * @return None. +*******************************************************************************/ +void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial) +{ + if (!table) + return; + + for (int16_t n = 0; n < NO_OS_CRC8_TABLE_SIZE; n++) { + uint8_t currByte = (uint8_t)n; + for (uint8_t bit = 0; bit < 8; bit++) { + if ((currByte & 0x80) != 0) { + currByte <<= 1; + currByte ^= polynomial; + } else { + currByte <<= 1; + } + } + table[n] = currByte; + } +} + +/***************************************************************************//** + * @brief Computes the CRC-8 over a buffer of data. + * + * @param table - Pointer to a CRC-8 lookup table for the desired polynomial. + * @param pdata - Pointer to 8-bit data buffer. + * @param nbytes - Number of bytes to compute the CRC-8 over. + * @param crc - Initial value for the CRC-8 computation. Can be used to + * cascade calls to this function by providing a previous + * output of this function as the crc parameter. + * + * @return crc - Computed CRC-8 value. +*******************************************************************************/ +uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes, + uint8_t crc) +{ + unsigned int idx; + + while (nbytes--) { + idx = (crc ^ *pdata); + crc = (table[idx]) & 0xff; + pdata++; + } + + return crc; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.h new file mode 100644 index 0000000..b2eadfd --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_crc8.h @@ -0,0 +1,48 @@ +/***************************************************************************//** + * @file no_os_crc8.h + * @brief Header file of CRC-8 computation. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_CRC8_H_ +#define _NO_OS_CRC8_H_ + +#include +#include + +#define NO_OS_CRC8_TABLE_SIZE 256 + +#define NO_OS_DECLARE_CRC8_TABLE(_table) \ + static uint8_t _table[NO_OS_CRC8_TABLE_SIZE] + +void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial); +uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes, + uint8_t crc); + +#endif // _NO_OS_CRC8_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_delay.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_delay.h new file mode 100644 index 0000000..d287f14 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_delay.h @@ -0,0 +1,56 @@ +/***************************************************************************//** + * @file no_os_delay.h + * @brief Header file of Delay functions + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_DELAY_H_ +#define _NO_OS_DELAY_H_ + +#include + +/** + * @struct no_os_time + * @brief Structure holding time data (seconds, microseconds). + */ +struct no_os_time { + unsigned int s, us; +}; + +/* Generate microseconds delay. */ +void no_os_udelay(uint32_t usecs); + +/* Generate miliseconds delay. */ +void no_os_mdelay(uint32_t msecs); + +/* Get current time */ +struct no_os_time no_os_get_time(void); + +#endif // _NO_OS_DELAY_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.c new file mode 100644 index 0000000..7e46a96 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.c @@ -0,0 +1,449 @@ +/***************************************************************************//** + * @file no_os_dma.c + * @brief Platform independent implementation for the DMA API. + * @author Ciprian Regus (ciprian.regus@analog.com) +******************************************************************************** + * Copyright 2024(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include +#include "no_os_dma.h" +#include +#include "no_os_error.h" +#include "no_os_mutex.h" +#include "no_os_irq.h" +#include "no_os_alloc.h" +#include "no_os_list.h" + +/** + * @brief Default handler for cycling though the channel's list of transfers + * @param context - structure which stores the state of the current channel + * and DMA controller state. + */ +static void default_sg_callback(void *context) +{ + struct no_os_dma_default_handler_data *data = context; + struct no_os_dma_xfer_desc *next_xfer; + struct no_os_dma_xfer_desc *old_xfer; + uint32_t list_size; + int ret; + + /* Handle the next transfer from the SG list */ + ret = no_os_list_get_first(data->channel->sg_list, (void **)&old_xfer); + if (ret) { + /* + * This should only happen if the list descriptor is NULL. + * The case in which there is no transfer left in the list should + * have been handled in the previous interrupt. + */ + no_os_dma_xfer_abort(data->desc, data->channel); + return; + } + + no_os_list_read_first(data->channel->sg_list, (void **)&next_xfer); + no_os_list_get_size(data->channel->sg_list, &list_size); + if (old_xfer->xfer_complete_cb) + old_xfer->xfer_complete_cb(old_xfer, next_xfer, + old_xfer->xfer_complete_ctx); + + if (!list_size) { + no_os_irq_disable(data->desc->irq_ctrl, data->channel->irq_num); + data->channel->free = true; + return; + } + + data->desc->platform_ops->dma_config_xfer(data->channel, next_xfer); + + no_os_dma_xfer_start(data->desc, data->channel); +} + +/** + * @brief Initialize the DMA controller. + * @param desc - Structure containing the state of the DMA controller + * @param param - Initialization parameter for the DMA controller. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_init(struct no_os_dma_desc **desc, + struct no_os_dma_init_param *param) +{ + int ret; + uint32_t i, j; + void *mutex; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->dma_init) + return -ENOSYS; + + no_os_mutex_init(&mutex); + + no_os_mutex_lock(mutex); + ret = param->platform_ops->dma_init(desc, param); + if (ret) + goto unlock; + + no_os_mutex_init(&(*desc)->mutex); + + (*desc)->platform_ops = param->platform_ops; + + for (i = 0; i < param->num_ch; i++) { + ret = no_os_list_init(&(*desc)->channels[i].sg_list, NO_OS_LIST_QUEUE, NULL); + if (ret) + goto list_err; + + no_os_mutex_init(&(*desc)->channels[i].mutex); + } + + (*desc)->ref++; + no_os_mutex_unlock(mutex); + + return 0; + +list_err: + for (j = 0; j < i; j++) + no_os_list_remove((*desc)->channels[i].sg_list); + + no_os_dma_remove(*desc); +unlock: + no_os_mutex_unlock(mutex); + + return ret; +} + +/** + * @brief Remove resources allocated for the DMA controller. + * @param desc - Structure containing the state of the DMA controller + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_remove(struct no_os_dma_desc *desc) +{ + uint32_t i; + int ret; + + if (!desc) + return -EINVAL; + + if (!desc->ref) + return 0; + + for (i = 0; i < desc->num_ch; i++) { + ret = no_os_list_remove(desc->channels->sg_list); + if (ret) + return ret; + + no_os_mutex_remove(desc->channels[i].mutex); + if (desc->irq_ctrl && desc->channels[i].cb_desc.handle) { + no_os_irq_unregister_callback(desc->irq_ctrl, + desc->channels[i].irq_num, + &desc->channels[i].cb_desc); + } + + } + no_os_mutex_remove(desc->mutex); + + ret = desc->platform_ops->dma_remove(desc); + if (ret) + return ret; + + desc->ref--; + + return 0; +} + +/** + * @brief Get a free DMA channel. + * @param desc - Structure containing the state of the DMA controller. + * @param channel - Reference to the acquired channel. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_acquire_channel(struct no_os_dma_desc *desc, + struct no_os_dma_ch **channel) +{ + uint32_t ch_num; + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->dma_acquire_ch) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + + ret = desc->platform_ops->dma_acquire_ch(desc, &ch_num); + if (ret) + goto unlock; + + *channel = &desc->channels[ch_num]; + +unlock: + no_os_mutex_unlock(desc->mutex); + + return ret; +} + +/** + * @brief Free DMA channel. + * @param desc - Structure containing the state of the DMA controller. + * @param channel - Reference to the currently acquired channel. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_release_channel(struct no_os_dma_desc *desc, + struct no_os_dma_ch *channel) +{ + int ret; + + if (!desc || !desc->platform_ops || !channel) + return -EINVAL; + + if (!desc->platform_ops->dma_release_ch) + return -ENOSYS; + + no_os_mutex_lock(channel->mutex); + ret = desc->platform_ops->dma_release_ch(desc, channel->id); + no_os_mutex_unlock(channel->mutex); + + return ret; +} + +/** + * @brief Acquire a channel and configure the list of transfers. + * @param desc - Structure containing the state of the DMA controller + * @param xfer - Array of DMA transfers. + * @param len - The number of transfers in the xfer list. + * @param ch - Previously acquired channel, for which the transfer will be configured. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_config_xfer(struct no_os_dma_desc *desc, + struct no_os_dma_xfer_desc *xfer, + uint32_t len, struct no_os_dma_ch *ch) +{ + uint32_t i; + int ret; + void *discard; + struct no_os_callback_desc *sg_callback; + + if (!desc || !xfer || !len || !ch) + return -EINVAL; + + no_os_mutex_lock(ch->mutex); + + /* + * Add the transfers to the channel's SG list. It's safe to do so, since + * there are no ongoing transfers on this channel. + */ + for (i = 0; i < len; i++) + no_os_list_add_last(ch->sg_list, &xfer[i]); + + if (desc->irq_ctrl) { + sg_callback = &ch->cb_desc; + sg_callback->ctx = &ch->irq_ctx; + sg_callback->handle = (void *)ch->id; + sg_callback->peripheral = xfer[0].periph; + ch->irq_ctx.desc = desc; + ch->irq_ctx.channel = ch; + + switch (xfer[0].xfer_type) { + case MEM_TO_DEV: + case MEM_TO_MEM: + sg_callback->event = NO_OS_EVT_DMA_TX_COMPLETE; + break; + case DEV_TO_MEM: + sg_callback->event = NO_OS_EVT_DMA_RX_COMPLETE; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = desc->platform_ops->dma_config_xfer(ch, xfer); + if (ret) + goto err; + + if (desc->sg_handler) + sg_callback->callback = desc->sg_handler; + else + sg_callback->callback = default_sg_callback; + + ret = no_os_irq_register_callback(desc->irq_ctrl, + ch->irq_num, + sg_callback); + if (ret) + goto err; + + no_os_irq_set_priority(desc->irq_ctrl, ch->irq_num, xfer[0].irq_priority); + } + + no_os_mutex_unlock(ch->mutex); + return 0; +err: + for (i = 0; i < len; i++) + no_os_list_get_first(ch->sg_list, &discard); + no_os_mutex_unlock(ch->mutex); + + return ret; +} + +/** + * @brief Lock a DMA channel, so it won't be acquired even if it's free. + * @param ch - Reference to the DMA channel + * @return 0 in case of success, -EINVAL if a NULL channel reference is provided. + */ +int no_os_dma_chan_lock(struct no_os_dma_ch *ch) +{ + no_os_mutex_lock(ch->mutex); + + if (!ch) + return -EINVAL; + + ch->sync_lock = true; + + no_os_mutex_unlock(ch->mutex); + + return 0; +} + +/** + * @brief Unlock a DMA channel, marking it available for acquisition. + * @param ch - Reference to the DMA channel + * @return 0 in case of success, -EINVAL if a NULL channel reference is provided. + */ +int no_os_dma_chan_unlock(struct no_os_dma_ch *ch) +{ + no_os_mutex_lock(ch->mutex); + + if (!ch) + return -EINVAL; + + ch->sync_lock = false; + + no_os_mutex_unlock(ch->mutex); + + return 0; +} + +/** + * @brief Acquire a channel and configure the list of transfers. + * @param desc - Structure containing the state of the DMA controller + * @param ch - Index for the channel we want to start the transfer on. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_xfer_start(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch) +{ + int ret; + + if (!desc || !desc->platform_ops || !ch) + return -EINVAL; + + if (!desc->platform_ops->dma_xfer_start) + return -ENOSYS; + + no_os_mutex_lock(ch->mutex); + + if (desc->irq_ctrl) + no_os_irq_enable(desc->irq_ctrl, ch->irq_num); + + ret = desc->platform_ops->dma_xfer_start(desc, ch); + + no_os_mutex_unlock(ch->mutex); + + return ret; +} + +/** + * @brief Abort the ongoing and any other future transfers scheduled for a channel. + * @param desc - Structure containing the state of the DMA controller + * @param ch - Index for the channel we want to abort the transfer. + * @return 0 in case of success, negative error code otherwise. + */ +int no_os_dma_xfer_abort(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch) +{ + void *discard; + int ret; + + if (!desc || !desc->platform_ops || !ch) + return -EINVAL; + + if (!desc->platform_ops->dma_xfer_abort) + return -ENOSYS; + + no_os_mutex_lock(ch->mutex); + + if (desc->irq_ctrl) + no_os_irq_disable(desc->irq_ctrl, ch->irq_num); + + do { + ret = no_os_list_get_first(ch->sg_list, &discard); + } while (!ret); + + ret = desc->platform_ops->dma_xfer_abort(desc, ch); + + no_os_mutex_unlock(ch->mutex); + + return ret; +} + +/** + * @brief Get the state of a DMA channel (free or not). + * @param desc - Reference to the DMA controller. + * @param ch - Reference to the DMA channel. + * @return true if a channel is free, false otherwise. + */ +bool no_os_dma_is_completed(struct no_os_dma_desc *desc, + struct no_os_dma_ch *ch) +{ + (void)desc; + + if (!ch) + return -EINVAL; + + return ch->free; +} + +/** + * @brief Whether or not there is a transfer in progress on a specific channel. + * @param desc - Reference to the DMA controller. + * @param ch - Reference to the DMA channel. + * @return true if a channel is free, false otherwise. + */ +bool no_os_dma_in_progress(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch) +{ + int ret; + + if (!desc || !desc->platform_ops || !ch) + return -EINVAL; + + if (!desc->platform_ops->dma_ch_in_progress) + return -ENOSYS; + + no_os_mutex_lock(ch->mutex); + ret = desc->platform_ops->dma_ch_in_progress(desc, ch); + no_os_mutex_unlock(ch->mutex); + + return ret; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.h new file mode 100644 index 0000000..912c47a --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.h @@ -0,0 +1,265 @@ +/***************************************************************************//** + * @file no_os_dma.h + * @brief Platform independent function definitions and data types + * for the DMA API. + * @author Ciprian Regus (ciprian.regus@analog.com) +******************************************************************************** + * Copyright 2024(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_DMA_H_ +#define _NO_OS_DMA_H_ + +#include +#include +#include + +#include "no_os_list.h" +#include "no_os_irq.h" +#include "no_os_mutex.h" + +/** + * @enum no_os_dma_xfer_type + * @brief Supported transfer directions + */ +enum no_os_dma_xfer_type { + MEM_TO_MEM, + MEM_TO_DEV, + DEV_TO_MEM, +}; + +/** + * @struct no_os_dma_default_handler_data + * @brief IRQ parameter for the default inter transfer handler + */ +struct no_os_dma_default_handler_data { + struct no_os_dma_desc *desc; + struct no_os_dma_ch *channel; + void *extra; +}; + +struct no_os_dma_platform_ops; + +/** + * @struct no_os_dma_xfer_desc + * @brief It's used to setup a generic DMA transfer. + */ +struct no_os_dma_xfer_desc { + /** Source address for the data */ + uint8_t *src; + /** Destination address for the data */ + uint8_t *dst; + /** Transfer length in bytes */ + uint32_t length; + /** Transfer direction */ + enum no_os_dma_xfer_type xfer_type; + + /** This function will be called once the transfer completes. */ + void (*xfer_complete_cb)(struct no_os_dma_xfer_desc *, + struct no_os_dma_xfer_desc *, + void *); + /** + * Parameter for the transfer complete callback. This data should + * be valid at least until the callback is invoked. + */ + void *xfer_complete_ctx; + /** Transfer complete interrupt priority level */ + uint32_t irq_priority; + + /** + * Peripheral which originated the transfer. Will be used to add + * the callback to the proper event list. + */ + enum no_os_irq_peripheral periph; + + /** User or platform defined data */ + void *extra; +}; + +/** + * @struct no_os_dma_ch + * @brief Describes the state of a DMA channel. + */ +struct no_os_dma_ch { + /** Channel number */ + uint32_t id; + /** Whether or not there is a transfer in progress on this channel */ + bool free; + /** List of transfers for this channel */ + struct no_os_list_desc *sg_list; + /** Channel specific interrupt line number */ + uint32_t irq_num; + /** irq callback */ + struct no_os_callback_desc cb_desc; + /** IRQ parameter for the default inter transfer handler */ + struct no_os_dma_default_handler_data irq_ctx; + void *extra; + + /** Used to synchronize channel specific operations */ + void *mutex; + + /** + * Mark the channel as locked, in order to prevent it from being acquired + * even if it's free. Used as a synchronization mechanism between channels. + */ + bool sync_lock; +}; + +/** + * @struct no_os_dma_desc + * @brief Describes the state of the DMA controller. + */ +struct no_os_dma_desc { + /** Unique id of a DMA controller */ + uint32_t id; + /** The number of channels associated with the controller */ + uint32_t num_ch; + /** References to channels associated with the controller */ + struct no_os_dma_ch *channels; + /** Platform specific DMA functions */ + struct no_os_dma_platform_ops *platform_ops; + /** + * Interrupt controller configured by the platform specific DMA functions. + * May be left uninitialized,Start resulting in the interrupt handler not being + * called once a transfer completes. As such, the user (or platform code) has + * to provide the cycling mechanism. + */ + struct no_os_irq_ctrl_desc *irq_ctrl; + /** Platform specific data */ + void *extra; + /** Reference counter */ + uint32_t ref; + /** Used to synchronize DMA controller specific operations */ + void *mutex; + + /** + * Interrupt handler function called when a transfer is completed. + * It's used to configure the DMA controller for the next transfer in + * a channel's list. + */ + void (*sg_handler)(void *); +}; + +/** + * @struct no_os_dma_init_param + * @brief Initialization parameter for the DMA controller + */ +struct no_os_dma_init_param { + /** Unique id of a DMA controller */ + uint32_t id; + /** The number of channels associated with the controller */ + uint32_t num_ch; + /** Platform specific DMA functions */ + struct no_os_dma_platform_ops *platform_ops; + /** Platform specific data */ + void *extra; + + /** + * Optional custom scatter gather callback. May be set to NULL in + * order to use the default one. + */ + void (*sg_handler)(void *); + /** + * Optional custom parameter for the scatter gather callback. Only takes + * effect if the handler is also provided. + */ + void *ctx; +}; + +/** Initialize a DMA controller. */ +int no_os_dma_init(struct no_os_dma_desc **, + struct no_os_dma_init_param *); + +/** Free the resources allocated by the DMA layer. Disables the DMA controller. */ +int no_os_dma_remove(struct no_os_dma_desc *); + +/** Acquire a channel and add the transfers to it's SG list. */ +int no_os_dma_config_xfer(struct no_os_dma_desc *, + struct no_os_dma_xfer_desc *, + uint32_t, + struct no_os_dma_ch *); + +/** Prevent a channel from being acquired, even if it's free. */ +int no_os_dma_chan_lock(struct no_os_dma_ch *); + +/** Allow a channel to be acquired, in case it's free. */ +int no_os_dma_chan_unlock(struct no_os_dma_ch *); + +/** Start the DMA transactions for a specific channel. */ +int no_os_dma_xfer_start(struct no_os_dma_desc *, struct no_os_dma_ch *); + +/** + * Stop the DMA transactions for a specific channel and remove the transfers + * from the SG list. + */ +int no_os_dma_xfer_abort(struct no_os_dma_desc *, struct no_os_dma_ch *); + +/** + * Check whether a transfer is complete. By default, it requires the interrupt + * handler to set the free flag for the channel. + */ +bool no_os_dma_is_completed(struct no_os_dma_desc *, struct no_os_dma_ch *); + +/** Whether or not a specific channel has an ongoing transfer. */ +bool no_os_dma_in_progress(struct no_os_dma_desc *, struct no_os_dma_ch *); + +/** Get a free DMA channel. */ +int no_os_dma_acquire_channel(struct no_os_dma_desc *, struct no_os_dma_ch **); + +/** Free a DMA channel. */ +int no_os_dma_release_channel(struct no_os_dma_desc *, struct no_os_dma_ch *); + +/** + * @struct no_os_irq_platform_ops + * @brief Structure holding IRQ function pointers that point to the platform + * specific function + */ +struct no_os_dma_platform_ops { + /** Initialize platform specific resources for the DMA controller. */ + int (*dma_init)(struct no_os_dma_desc **, struct no_os_dma_init_param *); + /** Remove resources allocated for the DMA controller. */ + int (*dma_remove)(struct no_os_dma_desc *desc); + /** Get a free channel and set it as busy. */ + int (*dma_acquire_ch)(struct no_os_dma_desc *, uint32_t *); + int (*dma_release_ch)(struct no_os_dma_desc *, uint32_t); + /** Configure platform specific settings required for the current DMA transfer */ + int (*dma_config_xfer)(struct no_os_dma_ch *, + struct no_os_dma_xfer_desc *); + /** Signal the DMA controller to start the transfer. */ + int (*dma_xfer_start)(struct no_os_dma_desc *, struct no_os_dma_ch *); + /** Signal the DMA controller to stop the transfer. */ + int (*dma_xfer_abort)(struct no_os_dma_desc *, struct no_os_dma_ch *); + /** Whether or not a specific channel has an ongoing or future transfer configured */ + bool (*dma_ch_is_completed)(struct no_os_dma_desc *, struct no_os_dma_ch *); + /** + * Whether or not a specific channel has an ongoing transfer. + * This returns true between transfers. + */ + bool (*dma_ch_in_progress)(struct no_os_dma_desc *, struct no_os_dma_ch *); +}; + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.c new file mode 100644 index 0000000..d6536ed --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.c @@ -0,0 +1,119 @@ +/***************************************************************************//** + * @file no_os_eeprom.c + * @brief Implementation of the EEPROM APIs + * @author Mahesh Phalke (mahesh.phalke@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include "no_os_eeprom.h" +#include "no_os_error.h" + +/** + * @brief Initialize the EEPROM + * @param desc - EEPROM descriptor + * @param param - EEPROM init parameters + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc, + const struct no_os_eeprom_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_eeprom_init() + * @param desc - EEPROM descriptor + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->remove) + return -ENOSYS; + + return desc->platform_ops->remove(desc); +} + +/** + * @brief Write the EEPROM data + * @param desc - EEPROM descriptor + * @param address - EEPROM address/location to write + * @param data - EEPROM data (pointer) + * @param bytes - Number of data bytes to write + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address, + uint8_t *data, uint16_t bytes) +{ + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->write) + return -ENOSYS; + + return desc->platform_ops->write(desc, address, data, bytes); +} + +/** + * @brief Read the EEPROM data + * @param desc - EEPROM descriptor + * @param address - EEPROM address/location to read + * @param data - EEPROM data (pointer) + * @param bytes - Number of data bytes to read + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address, + uint8_t *data, uint16_t bytes) +{ + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->read) + return -ENOSYS; + + return desc->platform_ops->read(desc, address, data, bytes); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.h new file mode 100644 index 0000000..37bb679 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_eeprom.h @@ -0,0 +1,99 @@ +/***************************************************************************//** + * @file no_os_eeprom.h + * @brief Header file for EEPROM APIs + * @author Mahesh Phalke (mahesh.phalke@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_EEPROM_H_ +#define _NO_OS_EEPROM_H_ + +#include + + +/* Forward declaration of structure */ +struct no_os_eeprom_platform_ops; + +/** + * @struct no_os_eeprom_init_param + * @brief Structure holding the parameters for EEPROM initialization + */ +struct no_os_eeprom_init_param { + /** Device ID */ + uint32_t device_id; + const struct no_os_eeprom_platform_ops *platform_ops; + /** EEPROM extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_eeprom_desc + * @brief Structure holding the EEPROM descriptor + */ +struct no_os_eeprom_desc { + /** Device ID */ + uint32_t device_id; + const struct no_os_eeprom_platform_ops *platform_ops; + /** EEPROM extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_eeprom_platform_ops + * @brief Structure holding the EEPROM function pointers that point to the + * platform specific function + */ +struct no_os_eeprom_platform_ops { + /** EEPROM initialization function pointer */ + int32_t (*init)(struct no_os_eeprom_desc **, + const struct no_os_eeprom_init_param *); + /** EEPROM data write function pointer */ + int32_t (*write)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t); + /** EEPROM data read function pointer */ + int32_t (*read)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t); + /** EEPROM remove function pointer */ + int32_t (*remove)(struct no_os_eeprom_desc *); +}; + +/* Initialize the EEPROM */ +int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc, + const struct no_os_eeprom_init_param *param); + +/* Write into EEPROM */ +int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address, + uint8_t *data, uint16_t bytes); + +/* Read from EEPROM */ +int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address, + uint8_t *data, uint16_t bytes); + +/* Free the resources allocated by no_os_eeprom_init() */ +int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc); + +#endif // _NO_OS_EEPROM_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_error.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_error.h new file mode 100644 index 0000000..3aa0c81 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_error.h @@ -0,0 +1,48 @@ +/***************************************************************************//** + * @file no_os_error.h + * @brief Error codes definition + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_ERROR_H_ +#define _NO_OS_ERROR_H_ + +#include + +#ifndef __NO_OS_ELASTERROR +#define __NO_OS_ELASTERROR 2000 +#endif + +#define NO_OS_EOVERRUN (__NO_OS_ELASTERROR + 1) /* Circular buffer overrun */ + + +#define NO_OS_IS_ERR_VALUE(x) ((x) < 0) + +#endif // _NO_OS_ERROR_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.c new file mode 100644 index 0000000..060d6f8 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.c @@ -0,0 +1,126 @@ +/***************************************************************************//** + * @file no_os_fifo.c + * @brief Implementation of fifo. + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include "no_os_fifo.h" +#include "no_os_error.h" +#include "no_os_alloc.h" + +/** + * @brief Create new fifo element + * @param buff - Data to be saved in fifo. + * @param len - Length of the data. + * @return fifo element in case of success, NULL otherwise + */ +static struct no_os_fifo_element * fifo_new_element(char *buff, uint32_t len) +{ + struct no_os_fifo_element *q = no_os_calloc(1, + sizeof(struct no_os_fifo_element)); + if (!q) + return NULL; + + q->len = len; + q->data = no_os_calloc(1, len); + if (!(q->data)) { + no_os_free(q); + return NULL; + } + memcpy(q->data, buff, len); + + return q; +} + +/** + * @brief Get last element in fifo + * @param p_fifo - pointer to fifo + * @return fifo last element if exists, NULL otherwise + */ +static struct no_os_fifo_element *no_os_fifo_get_last(struct no_os_fifo_element + *p_fifo) +{ + if (p_fifo == NULL) + return NULL; + while (p_fifo->next) { + p_fifo = p_fifo->next; + } + + return p_fifo; +} + +/** + * @brief Insert element to fifo, in the last position. + * @param p_fifo - Pointer to fifo. + * @param buff - Data to be saved in fifo. + * @param len - Length of the data. + * @return 0 in case of success, -1 otherwise + */ +int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff, + uint32_t len) +{ + struct no_os_fifo_element *p, *q; + + if (len <= 0) + return -1; + + q = fifo_new_element(buff, len); + if (!q) + return -1; + + if (!(*p_fifo)) { + *p_fifo = q; + } else { + p = no_os_fifo_get_last(*p_fifo); + p->next = q; + } + + return 0; +} + +/** + * @brief Remove fifo head + * @param p_fifo - Pointer to fifo. + * @return next element in fifo if exists, NULL otherwise. + */ +struct no_os_fifo_element * no_os_fifo_remove(struct no_os_fifo_element *p_fifo) +{ + struct no_os_fifo_element *p = p_fifo; + + if (p_fifo != NULL) { + p_fifo = p_fifo->next; + no_os_free(p->data); + no_os_free(p); + } + + return p_fifo; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.h new file mode 100644 index 0000000..8a15659 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.h @@ -0,0 +1,58 @@ +/***************************************************************************//** + * @file no_os_fifo.h + * @brief Header file of fifo + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_FIFO_H_ +#define _NO_OS_FIFO_H_ + +#include + +/** + * @struct no_os_fifo_element + * @brief Structure holding the fifo element parameters. + */ +struct no_os_fifo_element { + /** next FIFO element */ + struct no_os_fifo_element *next; + /** FIFO data pointer */ + char *data; + /** FIFO length */ + uint32_t len; +}; + +/* Insert element to fifo tail. */ +int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff, + uint32_t len); + +/* Remove fifo head. */ +struct no_os_fifo_element *no_os_fifo_remove(struct no_os_fifo_element *p_fifo); + +#endif // _NO_OS_FIFO_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_flash.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_flash.h new file mode 100644 index 0000000..0f3a725 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_flash.h @@ -0,0 +1,96 @@ +/***************************************************************************//** + * @file no_os_flash.h + * @brief Header file for flash controller driver. + * @author Andrei Drimbarean (andrei.drimbarean@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_FLASH_H_ +#define _NO_OS_FLASH_H_ + +#include + +/** + * @struct no_os_flash_dev + * @brief Flash controller device structure + */ +struct no_os_flash_dev { + /** Flash Device ID */ + uint8_t id; + /** Size of flash memory in bytes */ + uint32_t flash_size; + /** Size of flash page in bytes */ + uint32_t page_size; + /** Flash extra parameters */ + void *extra; +}; + +/** + * @struct no_os_flash_init_param + * @brief Flash controller initialization structure + */ +struct no_os_flash_init_param { + /** Flash Device ID */ + uint8_t id; + /** Size of flash memory in bytes */ + uint32_t flash_size; + /** Size of flash page in bytes */ + uint32_t flash_page_size; + /** Flash extra parameters */ + void *extra; +}; + +/** Initialize flash controller. */ +int32_t no_os_flash_init(struct no_os_flash_dev **device, + struct no_os_flash_init_param *init_param); + +/** Free memory allocated by no_os_flash_init(). */ +int32_t no_os_flash_remove(struct no_os_flash_dev *dev); + +/** Erase a flash page. */ +int32_t no_os_flash_clear_page(struct no_os_flash_dev *dev, int32_t page_no); + +/** Write a flash page. */ +int32_t no_os_flash_write_page(struct no_os_flash_dev *dev, int32_t page_no, + uint32_t *data); + +/** Read a flash page. */ +int32_t flash_read_page(struct no_os_flash_dev *dev, int32_t page_no, + uint32_t *data); + +/** Write data in flash memory. */ +int32_t no_os_flash_write(struct no_os_flash_dev *dev, uint32_t flash_addr, + uint32_t *array, uint32_t array_size); + +/** Read data from the flash memory. */ +int32_t no_os_flash_read(struct no_os_flash_dev *dev, uint32_t flash_addr, + uint32_t *array, + uint32_t size); + +#endif // _NO_OS_FLASH_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_font_8x8.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_font_8x8.c new file mode 100644 index 0000000..d7fde18 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_font_8x8.c @@ -0,0 +1,166 @@ +/***************************************************************************//** + * @file no_os_font_8x8.c + * @brief Font style for 8x8 characters. + * @author Andrei Porumb (andrei.porumb@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include + +/* ASCII to bitmap */ +const uint8_t no_os_chr_8x8[128][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00}, + {0x64, 0x3c, 0x26, 0x64, 0x3c, 0x26, 0x24, 0x00}, + {0x26, 0x49, 0x49, 0x7f, 0x49, 0x49, 0x32, 0x00}, + {0x42, 0x25, 0x12, 0x08, 0x24, 0x52, 0x21, 0x00}, + {0x20, 0x50, 0x4e, 0x55, 0x22, 0x58, 0x28, 0x00}, + {0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, 0x00}, + {0x00, 0x15, 0x15, 0x0e, 0x0e, 0x15, 0x15, 0x00}, + {0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x50, 0x30, 0x00, 0x00, 0x00}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}, + {0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00}, + {0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00}, + {0x00, 0x00, 0x41, 0x7f, 0x40, 0x00, 0x00, 0x00}, + {0x00, 0x42, 0x61, 0x51, 0x49, 0x6e, 0x00, 0x00}, + {0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00}, + {0x00, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x00}, + {0x00, 0x27, 0x49, 0x49, 0x49, 0x71, 0x00, 0x00}, + {0x00, 0x3c, 0x4a, 0x49, 0x48, 0x70, 0x00, 0x00}, + {0x00, 0x43, 0x21, 0x11, 0x0d, 0x03, 0x00, 0x00}, + {0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00}, + {0x00, 0x06, 0x09, 0x49, 0x29, 0x1e, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x52, 0x30, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x08, 0x14, 0x14, 0x22, 0x00, 0x00}, + {0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00}, + {0x00, 0x00, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00}, + {0x00, 0x02, 0x01, 0x59, 0x05, 0x02, 0x00, 0x00}, + {0x3e, 0x41, 0x5d, 0x55, 0x4d, 0x51, 0x2e, 0x00}, + {0x40, 0x7c, 0x4a, 0x09, 0x4a, 0x7c, 0x40, 0x00}, + {0x41, 0x7f, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00}, + {0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x00}, + {0x41, 0x7f, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00}, + {0x41, 0x7f, 0x49, 0x49, 0x5d, 0x41, 0x63, 0x00}, + {0x41, 0x7f, 0x49, 0x09, 0x1d, 0x01, 0x03, 0x00}, + {0x1c, 0x22, 0x41, 0x49, 0x49, 0x3a, 0x08, 0x00}, + {0x41, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x41, 0x00}, + {0x00, 0x41, 0x41, 0x7F, 0x41, 0x41, 0x00, 0x00}, + {0x30, 0x40, 0x41, 0x41, 0x3F, 0x01, 0x01, 0x00}, + {0x41, 0x7f, 0x08, 0x0c, 0x12, 0x61, 0x41, 0x00}, + {0x41, 0x7f, 0x41, 0x40, 0x40, 0x40, 0x60, 0x00}, + {0x41, 0x7f, 0x42, 0x0c, 0x42, 0x7f, 0x41, 0x00}, + {0x41, 0x7f, 0x42, 0x0c, 0x11, 0x7f, 0x01, 0x00}, + {0x1c, 0x22, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00}, + {0x41, 0x7f, 0x49, 0x09, 0x09, 0x09, 0x06, 0x00}, + {0x0c, 0x12, 0x21, 0x21, 0x61, 0x52, 0x4c, 0x00}, + {0x41, 0x7f, 0x09, 0x09, 0x19, 0x69, 0x46, 0x00}, + {0x66, 0x49, 0x49, 0x49, 0x49, 0x49, 0x33, 0x00}, + {0x03, 0x01, 0x41, 0x7f, 0x41, 0x01, 0x03, 0x00}, + {0x01, 0x3f, 0x41, 0x40, 0x41, 0x3f, 0x01, 0x00}, + {0x01, 0x0f, 0x31, 0x40, 0x31, 0x0f, 0x01, 0x00}, + {0x01, 0x1f, 0x61, 0x14, 0x61, 0x1f, 0x01, 0x00}, + {0x41, 0x41, 0x36, 0x08, 0x36, 0x41, 0x41, 0x00}, + {0x01, 0x03, 0x44, 0x78, 0x44, 0x03, 0x01, 0x00}, + {0x43, 0x61, 0x51, 0x49, 0x45, 0x43, 0x61, 0x00}, + {0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x00}, + {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00}, + {0x00, 0x00, 0x41, 0x41, 0x7f, 0x00, 0x00, 0x00}, + {0x00, 0x04, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00}, + {0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x34, 0x4a, 0x4a, 0x4a, 0x3c, 0x40, 0x00}, + {0x00, 0x41, 0x3f, 0x48, 0x48, 0x48, 0x30, 0x00}, + {0x00, 0x3c, 0x42, 0x42, 0x42, 0x24, 0x00, 0x00}, + {0x00, 0x30, 0x48, 0x48, 0x49, 0x3f, 0x40, 0x00}, + {0x00, 0x3c, 0x4a, 0x4a, 0x4a, 0x2c, 0x00, 0x00}, + {0x00, 0x00, 0x48, 0x7e, 0x49, 0x09, 0x00, 0x00}, + {0x00, 0x26, 0x49, 0x49, 0x49, 0x3f, 0x01, 0x00}, + {0x41, 0x7f, 0x48, 0x04, 0x44, 0x78, 0x40, 0x00}, + {0x00, 0x00, 0x44, 0x7d, 0x40, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x40, 0x44, 0x3d, 0x00, 0x00, 0x00}, + {0x41, 0x7f, 0x10, 0x18, 0x24, 0x42, 0x42, 0x00}, + {0x00, 0x40, 0x41, 0x7f, 0x40, 0x40, 0x00, 0x00}, + {0x42, 0x7e, 0x02, 0x7c, 0x02, 0x7e, 0x40, 0x00}, + {0x42, 0x7e, 0x44, 0x02, 0x42, 0x7c, 0x40, 0x00}, + {0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00}, + {0x00, 0x41, 0x7f, 0x49, 0x09, 0x09, 0x06, 0x00}, + {0x00, 0x06, 0x09, 0x09, 0x49, 0x7f, 0x41, 0x00}, + {0x00, 0x42, 0x7e, 0x44, 0x02, 0x02, 0x04, 0x00}, + {0x00, 0x64, 0x4a, 0x4a, 0x4a, 0x36, 0x00, 0x00}, + {0x00, 0x04, 0x3f, 0x44, 0x44, 0x20, 0x00, 0x00}, + {0x00, 0x02, 0x3e, 0x40, 0x40, 0x22, 0x7e, 0x40}, + {0x02, 0x0e, 0x32, 0x40, 0x32, 0x0e, 0x02, 0x00}, + {0x02, 0x1e, 0x62, 0x18, 0x62, 0x1e, 0x02, 0x00}, + {0x42, 0x62, 0x14, 0x08, 0x14, 0x62, 0x42, 0x00}, + {0x01, 0x43, 0x45, 0x38, 0x05, 0x03, 0x01, 0x00}, + {0x00, 0x46, 0x62, 0x52, 0x4a, 0x46, 0x62, 0x00}, + {0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x00}, + {0x00, 0x18, 0x08, 0x08, 0x10, 0x10, 0x18, 0x00}, + {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55} +}; diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.c new file mode 100644 index 0000000..46c944e --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.c @@ -0,0 +1,231 @@ +/***************************************************************************//** + * @file no_os_gpio.c + * @brief Implementation of the GPIO Interface + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_gpio.h" +#include +#include "no_os_error.h" + +/** + * @brief Obtain the GPIO decriptor. + * @param desc - The GPIO descriptor. + * @param param - GPIO Initialization parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_get(struct no_os_gpio_desc **desc, + const struct no_os_gpio_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->gpio_ops_get) + return -ENOSYS; + + ret = param->platform_ops->gpio_ops_get(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Get the value of an optional GPIO. + * @param desc - The GPIO descriptor. + * @param param - GPIO Initialization parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc, + const struct no_os_gpio_init_param *param) +{ + int32_t ret; + + if (!param || (param->number == -1)) { + *desc = NULL; + return 0; + } + + if (!param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->gpio_ops_get_optional) + return -ENOSYS; + + ret = param->platform_ops->gpio_ops_get_optional(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + return 0; +} +/** + * @brief Free the resources allocated by no_os_gpio_get(). + * @param desc - The GPIO descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_remove) + return -ENOSYS; + + return desc->platform_ops->gpio_ops_remove(desc); + } + + return 0; +} + +/** + * @brief Enable the input direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_direction_input) + return -ENOSYS; + + return desc->platform_ops->gpio_ops_direction_input(desc); + } + + return 0; +} + +/** + * @brief Enable the output direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: NO_OS_GPIO_HIGH + * NO_OS_GPIO_LOW + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc, + uint8_t value) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_direction_output) + return -ENOSYS; + + return desc->platform_ops-> + gpio_ops_direction_output(desc, value); + } + + return 0; +} + +/** + * @brief Get the direction of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param direction - The direction. + * Example: NO_OS_GPIO_OUT + * NO_OS_GPIO_IN + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc, + uint8_t *direction) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_get_direction) + return -ENOSYS; + + return desc->platform_ops-> + gpio_ops_get_direction(desc, direction); + } + + return 0; +} + +/** + * @brief Set the value of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: NO_OS_GPIO_HIGH + * NO_OS_GPIO_LOW + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc, + uint8_t value) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_set_value) + return -ENOSYS; + + return desc->platform_ops->gpio_ops_set_value(desc, value); + } + + return 0; +} + +/** + * @brief Get the value of the specified GPIO. + * @param desc - The GPIO descriptor. + * @param value - The value. + * Example: NO_OS_GPIO_HIGH + * NO_OS_GPIO_LOW + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc, + uint8_t *value) +{ + if (desc) { + if (!desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->gpio_ops_set_value) + return -ENOSYS; + + return desc->platform_ops->gpio_ops_get_value(desc, value); + } + + return 0; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.h new file mode 100644 index 0000000..d45c110 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.h @@ -0,0 +1,166 @@ +/***************************************************************************//** + * @file no_os_gpio.h + * @brief Header file of GPIO Interface + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_GPIO_H_ +#define _NO_OS_GPIO_H_ + +#include + +#define NO_OS_GPIO_OUT 0x01 +#define NO_OS_GPIO_IN 0x00 + +/** + * @struct no_os_gpio_platform_ops + * @brief Structure holding gpio function pointers that point to the platform + * specific function + */ +struct no_os_gpio_platform_ops ; + +/** + * @enum no_os_gpio_pull_up + * @brief Enum that holds the possible pull up/ pull down resistor configuration. + */ +enum no_os_gpio_pull_up { + NO_OS_PULL_NONE, + /** Strong pull up */ + NO_OS_PULL_UP, + /** Strong pull down */ + NO_OS_PULL_DOWN, + NO_OS_PULL_UP_WEAK, + NO_OS_PULL_DOWN_WEAK +}; + +/** + * @struct no_os_gpio_init_param + * @brief Structure holding the parameters for GPIO initialization. + */ +struct no_os_gpio_init_param { + /** Port number */ + int32_t port; + /** GPIO number */ + int32_t number; + /** Pull up/down resistor configuration */ + enum no_os_gpio_pull_up pull; + /** GPIO platform specific functions */ + const struct no_os_gpio_platform_ops *platform_ops; + /** GPIO extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_gpio_desc + * @brief Structure holding the GPIO descriptor. + */ +struct no_os_gpio_desc { + /** Port number */ + int32_t port; + /** GPIO number */ + int32_t number; + /** Pull up/down resistor configuration */ + enum no_os_gpio_pull_up pull; + /** GPIO platform specific functions */ + const struct no_os_gpio_platform_ops *platform_ops; + /** GPIO extra parameters (device specific) */ + void *extra; +}; + +/** + * @enum no_os_gpio_values + * @brief Enum that holds the possible output states of a GPIO. + */ +enum no_os_gpio_values { + /** GPIO logic low */ + NO_OS_GPIO_LOW, + /** GPIO logic high */ + NO_OS_GPIO_HIGH, + /** GPIO high impedance */ + NO_OS_GPIO_HIGH_Z +}; + +/** + * @struct no_os_gpio_platform_ops + * @brief Structure holding gpio function pointers that point to the platform + * specific function + */ +struct no_os_gpio_platform_ops { + /** gpio initialization function pointer */ + int32_t (*gpio_ops_get)(struct no_os_gpio_desc **, + const struct no_os_gpio_init_param *); + /** gpio optional descriptor function pointer */ + int32_t (*gpio_ops_get_optional)(struct no_os_gpio_desc **, + const struct no_os_gpio_init_param *); + /** gpio remove function pointer */ + int32_t (*gpio_ops_remove)(struct no_os_gpio_desc *); + /** gpio direction input function pointer */ + int32_t (*gpio_ops_direction_input)(struct no_os_gpio_desc *); + /** gpio direction output function pointer */ + int32_t (*gpio_ops_direction_output)(struct no_os_gpio_desc *, uint8_t); + /** gpio get direction function pointer */ + int32_t (*gpio_ops_get_direction)(struct no_os_gpio_desc *, uint8_t *); + /** gpio set value function pointer */ + int32_t (*gpio_ops_set_value)(struct no_os_gpio_desc *, uint8_t); + /** gpio get value function pointer */ + int32_t (*gpio_ops_get_value)(struct no_os_gpio_desc *, uint8_t *); +}; + +/* Obtain the GPIO decriptor. */ +int32_t no_os_gpio_get(struct no_os_gpio_desc **desc, + const struct no_os_gpio_init_param *param); + +/* Obtain optional GPIO descriptor. */ +int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc, + const struct no_os_gpio_init_param *param); + +/* Free the resources allocated by no_os_gpio_get(). */ +int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc); + +/* Enable the input direction of the specified GPIO. */ +int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc); + +/* Enable the output direction of the specified GPIO. */ +int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc, + uint8_t value); + +/* Get the direction of the specified GPIO. */ +int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc, + uint8_t *direction); + +/* Set the value of the specified GPIO. */ +int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc, + uint8_t value); + +/* Get the value of the specified GPIO. */ +int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc, + uint8_t *value); + +#endif // _NO_OS_GPIO_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.c new file mode 100644 index 0000000..af7e11c --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.c @@ -0,0 +1,209 @@ +/***************************************************************************//** + * @file no_os_i2c.c + * @brief Implementation of the I2C Interface + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_i2c.h" +#include +#include "no_os_error.h" +#include "no_os_mutex.h" +#include "no_os_alloc.h" + +/** + * @brief i2c_table contains the pointers towards the i2c buses +*/ +static void *i2c_table[I2C_MAX_BUS_NUMBER + 1]; + +/** + * @brief Initialize the I2C communication peripheral. + * @param desc - The I2C descriptor. + * @param param - The structure that contains the I2C parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_i2c_init(struct no_os_i2c_desc **desc, + const struct no_os_i2c_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->i2c_ops_init) + return -ENOSYS; + if (param->device_id > I2C_MAX_BUS_NUMBER) + return -EINVAL; + // Initializing BUS descriptor + if (i2c_table[param->device_id] == NULL) { + ret = no_os_i2cbus_init(param); + if (ret) + return ret; + } + // Initilize I2C descriptor + ret = param->platform_ops->i2c_ops_init(desc, param); + if (ret) + return ret; + (*desc)->bus = i2c_table[param->device_id]; + (*desc)->bus->slave_number++; + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Initialize the i2c bus communication peripheral. + * @param param - The structure that containes the i2c bus parameters + * @return 0 in case of success, error code otherwise +*/ +int32_t no_os_i2cbus_init(const struct no_os_i2c_init_param *param) +{ + struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *)no_os_calloc(1, + sizeof(struct no_os_i2cbus_desc)); + + if (!bus) + return -ENOMEM; + + no_os_mutex_init(&(bus->mutex)); + + bus->slave_number = 0; + bus->device_id = param->device_id; + bus->max_speed_hz = param->max_speed_hz; + bus->platform_ops = param->platform_ops; + bus->extra = param->extra; + + i2c_table[param->device_id] = bus; + + return 0; +} + + +/** + * @brief Free the resources allocated by no_os_i2c_init(). + * @param desc - The I2C descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_i2c_remove(struct no_os_i2c_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (desc->bus) + no_os_i2cbus_remove(desc->bus->device_id); + + if (!desc->platform_ops->i2c_ops_remove) + return -ENOSYS; + + return desc->platform_ops->i2c_ops_remove(desc); +} + +/** + * @brief Removes i2c bus instance + * @param bus_number - i2c bus number +*/ +void no_os_i2cbus_remove(uint32_t bus_number) +{ + struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *) + i2c_table[bus_number]; + + if (bus->slave_number > 0) + bus->slave_number--; + + if (bus->slave_number == 0) { + no_os_mutex_remove(bus->mutex); + + if (bus != NULL) { + no_os_free(bus); + i2c_table[bus_number] = NULL; + } + } +} + +/** + * @brief I2C Write data to slave device. + * @param desc - The I2C descriptor. + * @param data - The buffer with the transmitted/received data. + * @param bytes_number - Number of bytes to write. + * @param stop_bit - Stop conditional control. + * Example: 0 - A stop condition will not be generated. + * 1 - A stop condition will be generated. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_i2c_write(struct no_os_i2c_desc *desc, + uint8_t *data, + uint8_t bytes_number, + uint8_t stop_bit) +{ + int32_t ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i2c_ops_write) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->platform_ops->i2c_ops_write(desc, data, bytes_number, + stop_bit); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} + +/** + * @brief I2C Read data from slave device. + * @param desc - The i2c descriptor. + * @param data - The buffer with the transmitted/received data. + * @param bytes_number - Number of bytes to read. + * @param stop_bit - Stop conditional control. + * Example: 0 - A stop condition will not be generated. + * 1 - A stop condition will be generated. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_i2c_read(struct no_os_i2c_desc *desc, + uint8_t *data, + uint8_t bytes_number, + uint8_t stop_bit) +{ + int32_t ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i2c_ops_read) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->platform_ops->i2c_ops_read(desc, data, bytes_number, + stop_bit); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.h new file mode 100644 index 0000000..ca4cfba --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.h @@ -0,0 +1,146 @@ +/***************************************************************************//** + * @file no_os_i2c.h + * @brief Header file of I2C Interface + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_I2C_H_ +#define _NO_OS_I2C_H_ + +#include + +#define I2C_MAX_BUS_NUMBER 4 + +/** + * @struct no_os_i2c_platform_ops + * @brief Structure holding I2C function pointers that point to the platform + * specific function + */ +struct no_os_i2c_platform_ops ; + +/** + * @struct no_os_i2c_init_param + * @brief Structure holding the parameters for I2C initialization. + */ +struct no_os_i2c_init_param { + /** Device ID */ + uint32_t device_id; + /** I2C maximum transfer speed supported */ + uint32_t max_speed_hz; + /** Slave address */ + uint8_t slave_address; + /** I2C platform specific functions */ + const struct no_os_i2c_platform_ops *platform_ops; + /** I2C extra parameters (device specific parameters) */ + void *extra; +}; + +/** + * @struct no_os_i2cbus_desc + * @brief Structure holding I2C bus descriptor + */ +struct no_os_i2cbus_desc { + /** I2C bus mutex(lock)*/ + void* mutex; + /** I2C bus slave number*/ + uint8_t slave_number; + /** I2C bus Device ID */ + uint32_t device_id; + /** I2C bus maximum transfer speed supported */ + uint32_t max_speed_hz; + /** I2C bus platform specific functions */ + const struct no_os_i2c_platform_ops *platform_ops; + /** I2C bus extra parameters (device specific parameters) */ + void *extra; +}; + + +/** + * @struct no_os_i2c_desc + * @brief Structure holding I2C address descriptor + */ +struct no_os_i2c_desc { + /** I2C bus address*/ + struct no_os_i2cbus_desc *bus; + /** Device ID */ + uint32_t device_id; + /** I2C maximum transfer speed supported */ + uint32_t max_speed_hz; + /** Slave address */ + uint8_t slave_address; + /** I2C platform specific functions */ + const struct no_os_i2c_platform_ops *platform_ops; + /** I2C extra parameters (device specific parameters) */ + void *extra; +}; + +/** + * @struct no_os_i2c_platform_ops + * @brief Structure holding i2c function pointers that point to the platform + * specific function + */ +struct no_os_i2c_platform_ops { + /** i2c initialization function pointer */ + int32_t (*i2c_ops_init)(struct no_os_i2c_desc **, + const struct no_os_i2c_init_param *); + /** i2c write function pointer */ + int32_t (*i2c_ops_write)(struct no_os_i2c_desc *, uint8_t *, uint8_t, uint8_t); + /** i2c write function pointer */ + int32_t (*i2c_ops_read)(struct no_os_i2c_desc *, uint8_t *, uint8_t, uint8_t); + /** i2c remove function pointer */ + int32_t (*i2c_ops_remove)(struct no_os_i2c_desc *); +}; + +/* Initialize the I2C communication peripheral. */ +int32_t no_os_i2c_init(struct no_os_i2c_desc **desc, + const struct no_os_i2c_init_param *param); + +/* Free the resources allocated by no_os_i2c_init(). */ +int32_t no_os_i2c_remove(struct no_os_i2c_desc *desc); + +/* Write data to a slave device. */ +int32_t no_os_i2c_write(struct no_os_i2c_desc *desc, + uint8_t *data, + uint8_t bytes_number, + uint8_t stop_bit); + +/* Read data from a slave device. */ +int32_t no_os_i2c_read(struct no_os_i2c_desc *desc, + uint8_t *data, + uint8_t bytes_number, + uint8_t stop_bit); + +/* Initialize I2C bus descriptor*/ +int32_t no_os_i2cbus_init(const struct no_os_i2c_init_param *param); + +/* Free the resources allocated for I2C bus desc*/ +void no_os_i2cbus_remove(uint32_t bus_number); + +#endif // _NO_OS_I2C_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.c new file mode 100644 index 0000000..78e182c --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.c @@ -0,0 +1,698 @@ +/***************************************************************************//** + * @file no_os_i3c.c + * @brief Implementation of the I3C Interface + * @author Jorge Marques (jorge.marques@analog.com) +******************************************************************************** + * Copyright 2024(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include +#include "no_os_i3c.h" +#include "no_os_error.h" +#include "no_os_mutex.h" +#include "no_os_alloc.h" + +/** + * @brief i3c_table contains the pointers towards the I3C buses. +*/ +struct no_os_i3c_bus_desc *i3c_table [NO_OS_I3C_MAX_BUS_NUMBER + 1] = {NULL}; + +static enum no_os_i3c_slot_status no_os_i3c_addr_get_status( + struct no_os_i3c_bus_desc *desc, uint8_t addr); +static bool no_os_i3c_addr_is_avail(struct no_os_i3c_bus_desc *desc, + uint8_t addr); +static void no_os_i3c_addr_init(struct no_os_i3c_bus_desc *desc); + +/** + * @brief Initialize the I3C device. + * If the bus of the I3C device is not initialized, it will call to init it. + * @param desc - The I3C device descriptor. + * @param param - The structure that contains the I3C device parameters, to match PID. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_init(struct no_os_i3c_desc **desc, + const struct no_os_i3c_init_param *param) +{ + int ret; + struct no_os_i3c_desc *device_desc; + struct no_os_i3c_bus_desc **bus_desc; + struct no_os_i3c_bus_init_param *param_bus; + struct no_os_i3c_desc **it; + uint8_t i; + + if (!param->bus->device_id || + param->bus->device_id > NO_OS_I3C_MAX_BUS_NUMBER) + + return -EINVAL; + + bus_desc = &i3c_table[param->bus->device_id - 1]; + if (!*bus_desc) { + /* Initialize bus if not already */ + ret = no_os_i3c_init_bus(bus_desc, param->bus); + if (ret) + return ret; + } + + /* Initialize device */ + param_bus = param->bus; + + device_desc = (struct no_os_i3c_desc *)no_os_malloc( + sizeof(struct no_os_i3c_desc)); + if (!device_desc) + return -ENOMEM; + + /* Set is_attached flag */ + if (!param->is_i3c || param->is_static) + device_desc->is_attached = 1; + else { + for (i = 0; i < NO_OS_I3C_MAX_DEV_NUMBER; i++) { + if ((*bus_desc)->daa_candidates[i].pid == param->pid) + break; + } + + if (i == NO_OS_I3C_MAX_DEV_NUMBER) { + ret = -EFAULT; + goto error_device; + } + device_desc->is_attached = (*bus_desc)->daa_candidates[i].is_attached; + if (!device_desc->is_attached) { + ret = -EPERM; + goto error_device; + } + } + + /* Copy from init param to dev descriptor */ + device_desc->pid = param->pid; + device_desc->addr = param->addr; + device_desc->is_static = param->is_static; + device_desc->is_i3c = param->is_i3c; + device_desc->platform_ops = param_bus->platform_ops; + device_desc->bus = *bus_desc; + device_desc->event_callback = NULL; + + /* Find free slot */ + it = (*bus_desc)->devs; + while (it < (*bus_desc)->devs + NO_OS_I3C_MAX_DEV_NUMBER) { + if (!*it) + break; + it++; + }; + if (it == (*bus_desc)->devs + NO_OS_I3C_MAX_DEV_NUMBER) + goto error_device; + + *it = device_desc; + + ret = device_desc->platform_ops->i3c_ops_init(device_desc, param); + if (ret) + goto error_device; + + ret = device_desc->platform_ops->i3c_ops_is_dev_ready(device_desc); + if (ret) + goto error_device; + + *desc = device_desc; + return 0; + +error_device: + no_os_free(device_desc); + + return ret; +} + +/** + * @brief Initialize the I3C bus. + * @param desc - The I3C bus descriptor. + * @param param - The structure that contains the I3C bus parameters. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_init_bus(struct no_os_i3c_bus_desc **desc, + const struct no_os_i3c_bus_init_param *param) +{ + struct no_os_i3c_bus_desc *bus_desc; + bool has_static_i3c_addr = 0; + int ret; + int i = 0; + uint8_t data; + const struct no_os_i3c_init_param **it; + + if (!param || !param->platform_ops) + return -EINVAL; + if (!param->platform_ops->i3c_ops_init_bus || + !param->platform_ops->i3c_ops_remove_bus) + return -ENOSYS; + + bus_desc = (struct no_os_i3c_bus_desc *)no_os_calloc(1, + sizeof(struct no_os_i3c_bus_desc)); + if (!bus_desc) + return -ENOMEM; + + bus_desc->device_id = param->device_id; + bus_desc->num_devs = param->num_devs; + bus_desc->num_devs_unknown = 0; + bus_desc->async_irq = 0; + bus_desc->platform_ops = param->platform_ops; + + /* + * Execute the platform specific init routine, + * which allocate the extra features. + */ + ret = param->platform_ops->i3c_ops_init_bus(bus_desc, param); + if (ret) + goto error_bus_1; + + i3c_table[param->device_id - 1] = bus_desc; + + no_os_i3c_addr_init(bus_desc); + + /* + * Set status for addr, and + * If a device supports static addr, set it with CCC STAASA. + * If not, add to the PID-DA LUT for the DAA procedure. + */ + for (it = param->devs; it < param->devs + param->num_devs; it++) { + if (!*it) + continue; + + if (!no_os_i3c_addr_is_avail(bus_desc, (*it)->addr)) { + ret = -EINVAL; + goto error_bus_2; + } + + if ((*it)->is_i3c) { + if ((*it)->is_static) { + has_static_i3c_addr = 1; + no_os_i3c_addr_set_status(bus_desc, (*it)->addr, + NO_OS_I3C_ADDR_SLOT_I3C_DEV); + } else { + bus_desc->daa_candidates[i].pid = (*it)->pid; + bus_desc->daa_candidates[i].addr = (*it)->addr; + i++; + } + } else + no_os_i3c_addr_set_status(bus_desc, (*it)->addr, + NO_OS_I3C_ADDR_SLOT_I2C_DEV); + } + + /* Ensure other candidates fields are empty */ + memset(&bus_desc->daa_candidates[i], 0, + sizeof(struct no_os_i3c_daa_lut) * (NO_OS_I3C_MAX_DEV_NUMBER - i)); + + /* Reset fully every device on the bus */ + data = NO_OS_I3C_CCC_RSTACT_WHOLE_TARGET; + ret = no_os_i3c_send_ccc(*desc, + NO_OS_I3C_BCAST_ADDR, + NO_OS_I3C_CCC_RSTACT_BCAST, &data); + if (ret) + goto error_bus_2; + /* Set I3C devices that support static addresses to use them */ + if (has_static_i3c_addr) { + ret = no_os_i3c_send_ccc(bus_desc, NO_OS_I3C_BCAST_ADDR, NO_OS_I3C_CCC_SETAASA, + NULL); + if (ret) + goto error_bus_2; + } + + ret = no_os_i3c_do_daa(bus_desc, 1); + if (ret) + goto error_bus_2; + + no_os_mutex_init(bus_desc->mutex); + *desc = bus_desc; + + return 0; + +error_bus_2: + ret = param->platform_ops->i3c_ops_remove_bus(bus_desc); +error_bus_1: + no_os_free(bus_desc); + + return ret; +} + +/** + * @brief Free the resources allocated by no_os_i3c_init(). + * @param desc - The I3C device descriptor. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_remove(struct no_os_i3c_desc *desc) +{ + struct no_os_i3c_bus_desc *bus_desc; + struct no_os_i3c_desc **it; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_remove) + return -ENOSYS; + + bus_desc = desc->bus; + it = bus_desc->devs; + while (it < bus_desc->devs + NO_OS_I3C_MAX_DEV_NUMBER) { + if (*it == desc) + *it = NULL; + it++; + } + + /* Only error case is !desc */ + desc->platform_ops->i3c_ops_remove(desc); + no_os_free(desc); + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_i3c_init_bus. + * Must remove all devices first, if not, -EFAULT is returned. + * @param desc - The I3C bus descriptor. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_remove_bus(struct no_os_i3c_bus_desc *desc) +{ + struct no_os_i3c_desc **it; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_remove_bus) + return -ENOSYS; + + /* Verify if all devices are removed */ + for (it = desc->devs; it < desc->devs + NO_OS_I3C_MAX_DEV_NUMBER; it++) { + if (*it) + return -EFAULT; + } + + no_os_mutex_remove(desc->mutex); + + /* Only error case is !desc */ + desc->platform_ops->i3c_ops_remove_bus(desc); + + i3c_table[desc->device_id - 1] = NULL; + no_os_free(desc); + + return 0; +} + +/** + * @brief Do DAA to assign the dynamic addresses. + * @param desc - The I3C descriptor. + * @param rstdaa - Do RSTDAA CCC before the DAA. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_do_daa(struct no_os_i3c_bus_desc *desc, bool rstdaa) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_do_daa) + return -ENOSYS; + + return desc->platform_ops->i3c_ops_do_daa(desc, rstdaa); +} + +/** + * @brief Send CCC, either to a device device or broadcast to all. + * @param desc - The I3C descriptor. + * @param addr - Device address or broadcast address. + * @param ccc - CCC RnW, CCC Length, CCC ID. + * @param data - The buffer with the transmitted/received data. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_send_ccc(struct no_os_i3c_bus_desc *desc, + uint8_t addr, + uint32_t ccc, + uint8_t *data) +{ + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_send_ccc) + return -ENOSYS; + + if ((NO_OS_I3C_CCC_GET_RNW(ccc) && addr == NO_OS_I3C_BCAST_ADDR) || + ((addr == NO_OS_I3C_BCAST_ADDR) && (ccc & NO_OS_I3C_CCC_DIRECT)) || + ((addr != NO_OS_I3C_BCAST_ADDR) && !(ccc & NO_OS_I3C_CCC_DIRECT))) + return -EINVAL; + + no_os_mutex_lock(desc->mutex); + ret = desc->platform_ops->i3c_ops_send_ccc(desc, addr, NO_OS_I3C_CCC_ADDR(ccc), + NO_OS_I3C_CCC_GET_RNW(ccc), NO_OS_I3C_CCC_GET_DEF(ccc), + data, NO_OS_I3C_CCC_GET_LEN(ccc)); + no_os_mutex_unlock(desc->mutex); + + return ret; +} + +/** + * @brief Send CCC to device device. + * @param desc - The I3C descriptor. + * @param ccc - CCC RnW, CCC length, CCC id. + * @param data - The buffer with the transmitted/received data. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_send_direct_ccc(struct no_os_i3c_desc *desc, + uint32_t ccc, + uint8_t *data) +{ + if (!desc || !desc->bus) + return -EINVAL; + if (!(ccc & NO_OS_I3C_CCC_DIRECT)) + return -EINVAL; + + return no_os_i3c_send_ccc(desc->bus, desc->addr, ccc, data); +} + +/** + * @brief Write data to device device. + * @param desc - The I3C descriptor. + * @param data - The buffer with the transmitted data. + * @param size - Number of bytes to write. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_write(struct no_os_i3c_desc *desc, + uint8_t *data, + uint8_t size) +{ + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_write) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->bus->platform_ops->i3c_ops_write(desc, + data, size); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} + +/** + * @brief Read data from device device. + * @param desc - The I3C descriptor. + * @param data - The buffer with the received data. + * @param size - Number of bytes to read. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_read(struct no_os_i3c_desc *desc, + uint8_t *data, + uint8_t size) +{ + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_read) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->bus->platform_ops->i3c_ops_read(desc, + data, size); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} + +/** + * @brief Read and write the device. + * @param desc - The I3C descriptor. + * @param tx_data - The buffer with the transmitted data. + * @param tx_data_len - Number of bytes to write. + * @param rx_data - The buffer with the received data. + * @param rx_data_len - Number of bytes to read. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_i3c_write_and_read(struct no_os_i3c_desc *desc, + uint8_t *tx_data, + uint8_t tx_data_len, + uint8_t *rx_data, + uint8_t rx_data_len) +{ + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_read) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->bus->platform_ops->i3c_ops_write_and_read(desc, + tx_data, tx_data_len, rx_data, rx_data_len); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} + +/** + * @brief Configure I3C interrupts. + * @param desc - The I3C descriptor. + * @param irq - The interrupt type to enable. + * @param en - 1 to enable, 0 to disable irq type. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_i3c_conf_irq(struct no_os_i3c_bus_desc *desc, + uint8_t irq, bool en) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_conf_irq) + return -ENOSYS; + + return desc->platform_ops->i3c_ops_conf_irq(desc, irq, en); +} + +/** + * @brief Enable I3C non-blocking interrupts. + * @param desc - The I3C descriptor. + * @param en - 1 to enable, 0 to disable async callback. + * @return 0 in case of success, -EINVAL otherwise. + */ +int no_os_i3c_async_irq(struct no_os_i3c_bus_desc *desc, bool en) +{ + if (!desc) + return -EINVAL; + + desc->async_irq = en; + return 0; +} + +/** + * @brief Wait I3C interrupt. + * Set async_irq on call to false to ensure single entry point. + * @param desc - The I3C descriptor. + * @param irq - The interrupt to wait for. + * @return 0 in case of success, -EINVAL if in async mode or error codes. + */ +int no_os_i3c_wait_irq(struct no_os_i3c_bus_desc* desc, + uint8_t irq) +{ + if (!desc || desc->async_irq) + return -EINVAL; + + while (!(desc->irq_events & irq)) {} + + return no_os_i3c_call_irq(desc); +} + +/** + * @brief Non-blocking I3C interrupt. + * Since a payload is always retrieved with it, also update the no_os_i3c_ccc_info fields. + * @param desc - The I3C descriptor. + * @return 0 in case of success, error code otherwise. + */ +int no_os_i3c_call_irq(struct no_os_i3c_bus_desc* desc) +{ + struct no_os_i3c_desc **it; + int ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->i3c_ops_get_ccc_info) + return -ENOSYS; + + ret = desc->platform_ops->i3c_ops_get_ccc_info(desc, desc->irq_events); + if (ret) + return ret; + + it = desc->devs; + while (it < desc->devs + NO_OS_I3C_MAX_DEV_NUMBER) { + if (*it && (*it)->addr == desc->ccc_info.ibi_cr_addr) { + if ((*it)->event_callback) { + (*it)->event_callback((*it), desc->ccc_info.ibi_payload, + desc->ccc_info.ibi_payload_len); + } + break; + } + it++; + }; + + return ret; +} + +/** + * @brief Get a free address. + * @param desc - The I3C bus descriptor. + * @param start_addr - Start address to search from. + * @return The free address or 0 if no address is available. + */ +uint8_t no_os_i3c_addr_get_free(struct no_os_i3c_bus_desc *desc, + uint8_t start_addr) +{ + enum no_os_i3c_slot_status status; + uint8_t addr; + + for (addr = start_addr; addr < NO_OS_I3C_MAX_ADDR; addr++) { + status = no_os_i3c_addr_get_status(desc, addr); + if (status == NO_OS_I3C_ADDR_SLOT_FREE) + return addr; + } + + return 0; +} + +/** + * @brief Set status of an address. + * @param desc - The I3C bus descriptor. + * @param addr - The address to set. + * @param status - The value to write. + */ +void no_os_i3c_addr_set_status(struct no_os_i3c_bus_desc *desc, + uint8_t addr, enum no_os_i3c_slot_status status) +{ + unsigned int slot, bitpos; + unsigned int *ptr; + + if (addr > NO_OS_I3C_I2C_MAX_ADDR) + return; + + slot = NO_OS_I3C_ADDR_GET_SLOT(addr); + bitpos = NO_OS_I3C_ADDR_GET_POS(addr); + + ptr = desc->addrslots + slot; + // Unset old value + *ptr &= ~(NO_OS_I3C_ADDR_SLOT_STATUS_MASK << bitpos); + // Set new value + *ptr |= (status & NO_OS_I3C_ADDR_SLOT_STATUS_MASK) << bitpos; +} + +/** + * @brief Get status of an address. + * @param desc - The I3C bus descriptor. + * @param start_addr - Start address to search from. + * @return The free address or -ENOMEM if no available address. + */ +static enum no_os_i3c_slot_status no_os_i3c_addr_get_status( + struct no_os_i3c_bus_desc *desc, uint8_t addr) +{ + unsigned int slot, bitpos; + enum no_os_i3c_slot_status status; + + if (addr > NO_OS_I3C_I2C_MAX_ADDR) + return NO_OS_I3C_ADDR_SLOT_RSVD; + + slot = NO_OS_I3C_ADDR_GET_SLOT(addr); + bitpos = NO_OS_I3C_ADDR_GET_POS(addr); + + status = desc->addrslots[slot]; + status >>= bitpos; + + return status & NO_OS_I3C_ADDR_SLOT_STATUS_MASK; +} + +/** + * @brief Check if address is available. + * @param desc - The I3C bus descriptor. + * @param addr - Address to check. + * @return 1 if available, 0 if not. + */ +static bool no_os_i3c_addr_is_avail(struct no_os_i3c_bus_desc *desc, + uint8_t addr) +{ + enum no_os_i3c_slot_status status; + + status = no_os_i3c_addr_get_status(desc, addr); + + return status == NO_OS_I3C_ADDR_SLOT_FREE; +} + +/** + * @brief Initialize address buffer, reserving reserved addresses. + * @param desc - The I3C bus descriptor. + */ +static void no_os_i3c_addr_init(struct no_os_i3c_bus_desc *desc) +{ + /* Addresses 0 to 7 are reserved. */ + for (int i = 0; i < 8; i++) + no_os_i3c_addr_set_status(desc, i, NO_OS_I3C_ADDR_SLOT_RSVD); + + /* + * Reserve broadcast address and all addresses that might collide + * with the broadcast address when facing a single bit error. + */ + no_os_i3c_addr_set_status(desc, NO_OS_I3C_BCAST_ADDR, + NO_OS_I3C_ADDR_SLOT_RSVD); + for (int i = 0; i < 7; i++) + no_os_i3c_addr_set_status(desc, NO_OS_I3C_BCAST_ADDR ^ NO_OS_BIT(i), + NO_OS_I3C_ADDR_SLOT_RSVD); +} + +/** + * @brief Attach event callback. + * @param desc - The I3C device descriptor. + * @param callback - Method to call on event. + */ +void no_os_i3c_attach_callback(struct no_os_i3c_desc *desc, + void (*callback)(struct no_os_i3c_desc*, uint32_t, uint32_t)) +{ + desc->event_callback = callback; +} + +/** + * @brief Detach event callback. + * @param desc - The I3C device descriptor. + */ +void no_os_i3c_detach_callback(struct no_os_i3c_desc *desc) +{ + no_os_i3c_attach_callback(desc, NULL); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.h new file mode 100644 index 0000000..0593c13 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i3c.h @@ -0,0 +1,396 @@ +/***************************************************************************//** + * @file no_os_i3c.h + * @brief Header file of I3C Interface + * @author Jorge Marques (jorge.marques@analog.com) +******************************************************************************** + * Copyright 2024(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_I3C_H_ +#define _NO_OS_I3C_H_ + +#include +#include "no_os_util.h" + +#define NO_OS_I3C_MAX_BUS_NUMBER 3 +#define NO_OS_I3C_MAX_DEV_NUMBER 15 +/* I²C/I3C address are 7-bit (not considering extended 10-bit I²C) */ +#define NO_OS_I3C_I2C_MAX_ADDR 0x7F +#define NO_OS_I3C_MAX_ADDR NO_OS_I3C_I2C_MAX_ADDR +#define NO_OS_I3C_BCAST_ADDR 0x7E +/* 2-bit flags packed in addrslots */ +#define NO_OS_I3C_ADDR_FLAG_SIZE 2 +#define NO_OS_I3C_ADDR_PER_SLOT ((unsigned int)(sizeof(unsigned int)*8 / NO_OS_I3C_ADDR_FLAG_SIZE)) +#define NO_OS_I3C_ADDR_GET_SLOT(x) ((x) / NO_OS_I3C_ADDR_PER_SLOT) +#define NO_OS_I3C_ADDR_GET_POS(x) (((x) % NO_OS_I3C_ADDR_PER_SLOT) * NO_OS_I3C_ADDR_FLAG_SIZE) +#define NO_OS_I3C_ADDRSLOTS_SIZE \ + (NO_OS_I3C_I2C_MAX_ADDR / NO_OS_I3C_ADDR_PER_SLOT) + !!(NO_OS_I3C_I2C_MAX_ADDR % NO_OS_I3C_ADDR_PER_SLOT) + +/* I3C CCC (Common Command Codes) related definitions */ +#define NO_OS_I3C_CCC_BCAST 0 +#define NO_OS_I3C_CCC_DIRECT NO_OS_BIT(7) + +#define NO_OS_I3C_CCC_ID(id, type) ((id) | (type)) + +#define NO_OS_I3C_CCC_ADDR(x) ((x) & 0xFF) +#define NO_OS_I3C_CCC_GET_LEN(x) (((x) >> 8) & 0x0000FF) +#define NO_OS_I3C_CCC_SET_LEN(x) (((x) << 8) & 0x00FF00) +#define NO_OS_I3C_CCC_GET_DEF(x) (((x) >> 17) & NO_OS_BIT(0)) +#define NO_OS_I3C_CCC_SET_DEF NO_OS_BIT(17) +#define NO_OS_I3C_CCC_GET_RNW(x) (((x) >> 16) & NO_OS_BIT(0)) +#define NO_OS_I3C_CCC_SET_RNW(x) (((x) << 16) & NO_OS_BIT(16)) + +/** + * Commands valid in both broadcast and direct modes + * type: NO_OS_I3C_CCC_DIRECT, NO_OS_I3C_CCC_BCAST + */ +#define NO_OS_I3C_CCC_ENEC_DIRECT 0x80 | NO_OS_I3C_CCC_SET_LEN(1) +#define NO_OS_I3C_CCC_DISEC_DIRECT 0x81 | NO_OS_I3C_CCC_SET_LEN(1) +#define NO_OS_I3C_CCC_ENEC_BCAST 0x00 | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_DISEC_BCAST 0x01 | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_ENTAS(as, type) NO_OS_I3C_CCC_ID((0x2 + (as)), (type)) +#define NO_OS_I3C_CCC_RSTDAA(type) NO_OS_I3C_CCC_ID(0x6, (type)) +#define NO_OS_I3C_CCC_SETMWL(type) NO_OS_I3C_CCC_ID(0x9, (type)) | NO_OS_I3C_CCC_SET_LEN(2) +#define NO_OS_I3C_CCC_SETMRL(type) NO_OS_I3C_CCC_ID(0xa, (type)) | NO_OS_I3C_CCC_SET_LEN(2) +#define NO_OS_I3C_CCC_SETXTIME_BCAST 0x28 | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_SETXTIME_DIRECT 0x98 | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_RSTACT_BCAST 0x2a | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_RSTACT_DIRECT 0x9a | NO_OS_I3C_CCC_SET_DEF +#define NO_OS_I3C_CCC_RSTACT_I3C_ONLY 0x1 +#define NO_OS_I3C_CCC_RSTACT_WHOLE_TARGET 0x2 + +/* Broadcast-only commands */ +#define NO_OS_I3C_CCC_ENTDAA NO_OS_I3C_CCC_ID(0x7, NO_OS_I3C_CCC_BCAST) +#define NO_OS_I3C_CCC_DEFSLVS NO_OS_I3C_CCC_ID(0x8, NO_OS_I3C_CCC_BCAST) +#define NO_OS_I3C_CCC_ENTTM NO_OS_I3C_CCC_ID(0xb, NO_OS_I3C_CCC_BCAST) +#define NO_OS_I3C_CCC_ENTHDR(x) NO_OS_I3C_CCC_ID((0x20 + (x)), NO_OS_I3C_CCC_BCAST) +#define NO_OS_I3C_CCC_SETAASA NO_OS_I3C_CCC_ID(0x29, NO_OS_I3C_CCC_BCAST) + +/* Unicast-only commands */ +#define NO_OS_I3C_CCC_SETDASA NO_OS_I3C_CCC_ID(0x7, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_SETNEWDA NO_OS_I3C_CCC_ID(0x8, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETMWL NO_OS_I3C_CCC_ID(0xb, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETMRL NO_OS_I3C_CCC_ID(0xc, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETPID (NO_OS_I3C_CCC_ID(0xd, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(6) | NO_OS_I3C_CCC_SET_RNW(1)) +#define NO_OS_I3C_CCC_GETBCR (NO_OS_I3C_CCC_ID(0xe, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(1) | NO_OS_I3C_CCC_SET_RNW(1)) +#define NO_OS_I3C_CCC_GETDCR (NO_OS_I3C_CCC_ID(0xf, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(1) | NO_OS_I3C_CCC_SET_RNW(1)) +#define NO_OS_I3C_CCC_GETSTATUS (NO_OS_I3C_CCC_ID(0x10, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(2) | NO_OS_I3C_CCC_SET_RNW(1)) +#define NO_OS_I3C_CCC_GETACCMST NO_OS_I3C_CCC_ID(0x11, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_SETBRGTGT NO_OS_I3C_CCC_ID(0x13, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETMXDS NO_OS_I3C_CCC_ID(0x14, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETHDRCAP NO_OS_I3C_CCC_ID(0x15, NO_OS_I3C_CCC_DIRECT) +#define NO_OS_I3C_CCC_GETXTIME NO_OS_I3C_CCC_ID(0x19, NO_OS_I3C_CCC_DIRECT) + +#define NO_OS_I3C_CCC_EVENT_SIR NO_OS_BIT(0) +#define NO_OS_I3C_CCC_EVENT_MR NO_OS_BIT(1) +#define NO_OS_I3C_CCC_EVENT_HJ NO_OS_BIT(3) +/** + * List of possible IRQ events. + */ +#define NO_OS_I3C_IRQ_IBI 0x1 +#define NO_OS_I3C_IRQ_HJ 0x2 +#define NO_OS_I3C_IRQ_CR 0x4 +/** + * Extract capabilities from BCR + */ +#define NO_OS_I3C_BCR_IBI_REQUEST_CAPABLE(bcr) !!((bcr) & (1 << 1)) +#define NO_OS_I3C_BCR_IBI_PAYLOAD(bcr) !!((bcr) & (1 << 2)) +#define NO_OS_I3C_BCR_DEVICE_ROLE(bcr) (((bcr) && NO_OS_GENMASK(7,6)) >> 6) + +/** + * @enum no_os_i3c_slot_status - I3C address slot status + * + * @brief On an I3C bus, addresses are assigned dynamically, and we need to + * know which addresses are free to use and which ones are already assigned. + * + * Addresses marked as reserved are those reserved by the I3C protocol + * (broadcast address, ...). + */ +enum no_os_i3c_slot_status { + /** Address is free */ + NO_OS_I3C_ADDR_SLOT_FREE, + /** Address is reserved */ + NO_OS_I3C_ADDR_SLOT_RSVD, + /** Address is assigned to an I2C device */ + NO_OS_I3C_ADDR_SLOT_I2C_DEV, + /** Address is assigned to an I3C device */ + NO_OS_I3C_ADDR_SLOT_I3C_DEV, + /** Address slot mask */ + NO_OS_I3C_ADDR_SLOT_STATUS_MASK = 3, +}; + +/** + * @union no_os_i3c_ccc_info + */ +struct no_os_i3c_ccc_info { + /** I3C bus receive Target Address during IBI or Bus Role Request event. */ + uint32_t ibi_cr_addr; + /** I3C bus get Number of Data Payload after an IBI event. */ + uint32_t ibi_payload_len; + /** I3C bus received IBI Payload. */ + uint32_t ibi_payload; +}; + +/** + * @struct no_os_i3c_daa_lut + * @brief Stores the PID + DA information to look-up during the DAA. + * Should be used only for device initialization, since it may + * go outdated. + */ +struct no_os_i3c_daa_lut { + bool is_attached; + uint8_t addr; + uint64_t pid; +}; + +/** + * @struct no_os_i3c_platform_ops + * @brief Structure holding I3C function pointers that point to the platform + * specific function. + */ +struct no_os_i3c_platform_ops; + +/** + * @struct no_os_i3c_bus_desc + * @brief Structure holding I3C bus descriptor. + */ +struct no_os_i3c_bus_desc { + /** I3C bus mutex(lock)*/ + void* mutex; + /** Device ID*/ + uint8_t device_id; + /** Non-Expected number of devices on bus */ + uint8_t num_devs_unknown; + /** Expected number of devices on bus */ + uint8_t num_devs; + /** + * A bitmap with 2-bits per-slot to encode the address status and + * ease the DAA (Dynamic Address Assignment) procedure (see + * enum ::no_os_i3c_slot_status). + */ + unsigned int addrslots[NO_OS_I3C_ADDRSLOTS_SIZE]; + /** PID + DA LUT for DAA procedure */ + struct no_os_i3c_daa_lut daa_candidates[NO_OS_I3C_MAX_DEV_NUMBER]; + /** To store unknown devices assigned during DAA procedure */ + struct no_os_i3c_daa_lut daa_unknown[NO_OS_I3C_MAX_DEV_NUMBER]; + /** Devices descriptors */ + struct no_os_i3c_desc *devs[NO_OS_I3C_MAX_DEV_NUMBER]; + /** IRQ flags */ + uint8_t irq_events; + /** CCC info obtained after an IRQ */ + struct no_os_i3c_ccc_info ccc_info; + /** Trigger IRQ callback asyncronous (non-blocking) */ + bool async_irq; + /** I3C platform specific functions */ + const struct no_os_i3c_platform_ops *platform_ops; + /** I3C bus extra parameters */ + void *extra; +}; + +/** + * @struct no_os_i3c_bus_init_param + * @brief Structure holding the parameters for I3C initialization. + */ +struct no_os_i3c_bus_init_param { + /** Device ID */ + const uint32_t device_id; + /** I3C platform specific functions */ + const struct no_os_i3c_platform_ops *platform_ops; + /** Expected number of devices on bus */ + const uint8_t num_devs; + /** Expected devices on bus */ + const struct no_os_i3c_init_param **devs; + /** I3C extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_i3c_init_param + * @brief Structure holding the parameters for I3C initialization. + * Works like a device tree, the values are copied to no_os_i3c_desc + * during I3C initialization. + * Set is_static to 1 if the device provides a Static Address and is + * desired to use it instead of assigning a Dynamic Address during the + * DAA. + * is_i3c has higher precedence than is_static, and therefore + * is_static does not matter when is_i3c is 0. + */ +struct no_os_i3c_init_param { + /** Pointer to bus init param */ + struct no_os_i3c_bus_init_param *bus; + /** Provisioned ID */ + uint64_t pid; + /** Dynamic or static address */ + uint8_t addr; + /** Is the address static */ + bool is_static; + /** Is I3C or I2C */ + bool is_i3c; +}; + +/** + * @struct no_os_i3c_desc + * @brief Structure holding I3C device descriptor. + */ +struct no_os_i3c_desc { + /** Provisioned ID */ + uint64_t pid; + /** Dynamic or static address*/ + uint8_t addr; + /** Is I3C or I2C? */ + bool is_i3c; + /** Is attached? */ + bool is_attached; + /** Is the address static? */ + bool is_static; + /** I3C extra parameters (device specific) */ + void *extra; + /** Callback on event*/ + void (*event_callback)(struct no_os_i3c_desc*, uint32_t, uint32_t); + /** I3C platform specific functions */ + const struct no_os_i3c_platform_ops *platform_ops; + /** I3C bus */ + struct no_os_i3c_bus_desc *bus; +}; + +/** + * @struct no_os_i3c_platform_ops + * @brief Structure holding I3C function pointers that point to the platform + * specific function. + */ +struct no_os_i3c_platform_ops { + /** I3C initialization function pointer */ + int (*i3c_ops_init_bus)(struct no_os_i3c_bus_desc *, + const struct no_os_i3c_bus_init_param *); + /** I3C initialization function pointer */ + int (*i3c_ops_init)(struct no_os_i3c_desc *, + const struct no_os_i3c_init_param *); + /** I3C do daa function pointer */ + int (*i3c_ops_do_daa)(struct no_os_i3c_bus_desc *, bool); + /** I3C send ccc function pointer */ + int (*i3c_ops_send_ccc)(struct no_os_i3c_bus_desc *, uint8_t, uint8_t, + bool, bool, uint8_t *, uint8_t); + /** I3C private write function pointer */ + int (*i3c_ops_write)(struct no_os_i3c_desc *, uint8_t *, uint8_t); + /** I3C private read function pointer */ + int (*i3c_ops_read)(struct no_os_i3c_desc *, uint8_t *, uint8_t); + /** I3C private write and read function pointer */ + int (*i3c_ops_write_and_read)(struct no_os_i3c_desc *, uint8_t *, uint8_t, + uint8_t *, uint8_t); + /** I3C remove function pointer */ + int (*i3c_ops_remove_bus)(struct no_os_i3c_bus_desc *); + /** I3C remove function pointer */ + int (*i3c_ops_remove)(struct no_os_i3c_desc *); + /** I3C check is device on the bus is ready */ + int (*i3c_ops_is_dev_ready)(struct no_os_i3c_desc *); + /** I3C configure the enabled irq */ + int (*i3c_ops_conf_irq)(struct no_os_i3c_bus_desc *, + uint8_t, bool); + /** I3C fetch CCC info */ + int (*i3c_ops_get_ccc_info)(struct no_os_i3c_bus_desc *, + uint8_t); +}; + +/* Initialize the I3C device. */ +int no_os_i3c_init(struct no_os_i3c_desc **desc, + const struct no_os_i3c_init_param *param); + +/* Initialize the I3C bus. */ +int no_os_i3c_init_bus(struct no_os_i3c_bus_desc **desc, + const struct no_os_i3c_bus_init_param *param); + +/* Free the resources allocated by no_os_i3c_init. */ +int no_os_i3c_remove(struct no_os_i3c_desc *desc); + +/* Free the resources allocated by no_os_i3c_init_bus + no_os_i3c_init. */ +int no_os_i3c_remove_bus(struct no_os_i3c_bus_desc *desc); + +/* Do I3C DAA to assign the dynamic addresses. */ +int no_os_i3c_do_daa(struct no_os_i3c_bus_desc *desc, bool rstdaa); + +/* Send CCC on the bus (direct or broadcast). */ +int no_os_i3c_send_ccc(struct no_os_i3c_bus_desc *desc, + uint8_t addr, uint32_t ccc, uint8_t *data); + +/* Send CCC to a device device. */ +int no_os_i3c_send_direct_ccc(struct no_os_i3c_desc *desc, + uint32_t ccc, uint8_t *data); + +/* Write data to a device device. */ +int no_os_i3c_write(struct no_os_i3c_desc *desc, + uint8_t *data, + uint8_t size); + +/* Read data from a device device. */ +int no_os_i3c_read(struct no_os_i3c_desc *desc, + uint8_t *data, + uint8_t size); + +/* Write and read data from a device device. */ +int no_os_i3c_write_and_read(struct no_os_i3c_desc *desc, + uint8_t *tx_data, + uint8_t tx_data_len, + uint8_t *rx_data, + uint8_t rx_data_len); + +/* Configure enabled interrupt. */ +int no_os_i3c_conf_irq(struct no_os_i3c_bus_desc *desc, + uint8_t irq, bool en); + +/* Wait I3C interrupt. */ +int no_os_i3c_wait_irq(struct no_os_i3c_bus_desc* desc, + uint8_t irq); + +/* Non-blocking I3C interrupt. */ +int no_os_i3c_call_irq(struct no_os_i3c_bus_desc* desc); + +/* Enable I3C non-blocking interrupts. */ +int no_os_i3c_async_irq(struct no_os_i3c_bus_desc *desc, bool en); + +/* Get a free address. */ +uint8_t no_os_i3c_addr_get_free(struct no_os_i3c_bus_desc *desc, + uint8_t start_addr); + +/* Set status of an address. */ +void no_os_i3c_addr_set_status(struct no_os_i3c_bus_desc *desc, + uint8_t addr, enum no_os_i3c_slot_status status); + +/* Attach event callback. */ +void no_os_i3c_attach_callback(struct no_os_i3c_desc *desc, + void (*callback)(struct no_os_i3c_desc*, uint32_t, uint32_t)); + +/* Detach event callback. */ +void no_os_i3c_detach_callback(struct no_os_i3c_desc *desc); + +#endif // _NO_OS_I3C_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_init.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_init.h new file mode 100644 index 0000000..4f0d245 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_init.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * @file no_os_init.h + * @brief Header file of platform initialization. + * @author GMois (george.mois@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_INIT_H_ +#define _NO_OS_INIT_H_ + +int no_os_init(void); + +#endif // _NO_OS_INIT_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.c new file mode 100644 index 0000000..3973a30 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.c @@ -0,0 +1,265 @@ +/***************************************************************************//** + * @file no_os_irq.c + * @brief Implementation of the IRQ Interface + * @author Andrei Porumb (andrei.porumb@analog.com) +******************************************************************************** + * Copyright 2021(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include "no_os_irq.h" +#include "no_os_error.h" + +/** + * @brief Initialize the IRQ interrupts. + * @param desc - The IRQ descriptor. + * @param param - The structure that contains the IRQ parameters. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc, + const struct no_os_irq_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + + (*desc)->ref++; + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_irq_ctrl_init(). + * @param desc - The SPI descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->remove) + return -ENOSYS; + + if (--desc->ref) + return 0; + + return desc->platform_ops->remove(desc); +} + +/** + * @brief Register a callback to handle the irq events. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @param callback - Callback descriptor - platform specific type. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int no_os_irq_register_callback(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + struct no_os_callback_desc *callback) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->register_callback) + return -ENOSYS; + + return desc->platform_ops->register_callback(desc, irq_id, callback); +} + +/** + * @brief Unregisters a generic IRQ handling function. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @param callback - Callback descriptor - platform specific type. + * @return SUCCESS in case of success, FAILURE otherwise. + */ +int no_os_irq_unregister_callback(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + struct no_os_callback_desc *callback) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->unregister_callback) + return -ENOSYS; + + return desc->platform_ops->unregister_callback(desc, irq_id, callback); +} + +/** + * @brief Enable global interrupts. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_global_enable(struct no_os_irq_ctrl_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->global_enable) + return -ENOSYS; + + return desc->platform_ops->global_enable(desc); +} + +/** + * @brief Disable global interrupts. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_global_disable(struct no_os_irq_ctrl_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->global_disable) + return -ENOSYS; + + return desc->platform_ops->global_disable(desc); +} + +/** + * @brief Set interrupt trigger level. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @param trig - New trigger level for the interrupt. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_trigger_level_set(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + enum no_os_irq_trig_level trig) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->trigger_level_set) + return -ENOSYS; + + return desc->platform_ops->trigger_level_set(desc, irq_id, trig); +} + +/** + * @brief Enable specific interrupt. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_enable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->enable) + return -ENOSYS; + + return desc->platform_ops->enable(desc, irq_id); +} + +/** + * @brief Disable specific interrupt. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_irq_disable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->disable) + return -ENOSYS; + + return desc->platform_ops->disable(desc, irq_id); +} + +/** + * @brief Set the priority for an interrupt. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @param priority_level - The priority level of the interrupt. + * @return 0 in case of success, negative errno error codes. + */ +int no_os_irq_set_priority(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + uint32_t priority_level) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->set_priority) + return -ENOSYS; + + return desc->platform_ops->set_priority(desc, irq_id, priority_level); +} + +/** + * @brief Get the priority for an interrupt. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @param priority_level - The priority level of the interrupt. + * @return 0 in case of success, negative errno error codes. + */ +int no_os_irq_get_priority(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + uint32_t *priority_level) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->get_priority) + return -ENOSYS; + + return desc->platform_ops->get_priority(desc, irq_id, priority_level); +} + +/** + * @brief Clear the pending interrupt. + * @param desc - The IRQ controller descriptor. + * @param irq_id - Interrupt identifier. + * @return 0 in case of success, negative errno error codes. + */ +int no_os_irq_clear_pending(struct no_os_irq_ctrl_desc* desc, + uint32_t irq_id) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->clear_pending) + return -ENOSYS; + + return desc->platform_ops->clear_pending(desc, irq_id); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.h new file mode 100644 index 0000000..fd9a2cd --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_irq.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * @file no_os_irq.h + * @brief Header file of IRQ interface. + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_IRQ_H_ +#define _NO_OS_IRQ_H_ + +#include + +/** + * @enum no_os_irq_uart_event_e + * @brief Possible events for uart interrupt + * @todo replace this with enum no_os_irq_event + */ +enum no_os_irq_uart_event_e { + /** Write operation finalized */ + NO_OS_IRQ_WRITE_DONE, + /** Read operation finalized */ + NO_OS_IRQ_READ_DONE, + /** An error occurred */ + NO_OS_IRQ_ERROR +}; + +enum no_os_irq_event { + NO_OS_EVT_GPIO, + NO_OS_EVT_UART_TX_COMPLETE, + NO_OS_EVT_UART_RX_COMPLETE, + NO_OS_EVT_UART_ERROR, + NO_OS_EVT_RTC, + NO_OS_EVT_XINT, + NO_OS_EVT_TIM_ELAPSED, + NO_OS_EVT_TIM_PWM_PULSE_FINISHED, + NO_OS_EVT_LPTIM_PWM_PULSE_FINISHED, + NO_OS_EVT_DMA_RX_COMPLETE, + NO_OS_EVT_DMA_RX_HALF_COMPLETE, + NO_OS_EVT_DMA_TX_COMPLETE, + NO_OS_EVT_USB, +}; + +enum no_os_irq_trig_level { + NO_OS_IRQ_LEVEL_LOW, + NO_OS_IRQ_LEVEL_HIGH, + NO_OS_IRQ_EDGE_FALLING, + NO_OS_IRQ_EDGE_RISING, + NO_OS_IRQ_EDGE_BOTH +}; + +enum no_os_irq_peripheral { + NO_OS_GPIO_IRQ, + NO_OS_UART_IRQ, + NO_OS_RTC_IRQ, + NO_OS_TIM_IRQ, + NO_OS_LPTIM_IRQ, + NO_OS_TDM_DMA_IRQ, + NO_OS_TIM_DMA_IRQ, + NO_OS_SPI_DMA_IRQ, + NO_OS_DMA_IRQ, + NO_OS_USB_IRQ, +}; + +/** + * @struct no_os_irq_platform_ops + * @brief Structure holding IRQ function pointers that point to the platform + * specific function + */ +struct no_os_irq_platform_ops ; + +/** + * @struct no_os_irq_init_param + * @brief Structure holding the initial parameters for Interrupt Request. + */ +struct no_os_irq_init_param { + /** Interrupt request controller ID. */ + uint32_t irq_ctrl_id; + /** Platform specific IRQ platform ops structure. */ + const struct no_os_irq_platform_ops *platform_ops; + /** + * This is intended to store irq controller specific configurations, + * it should not be a reference to any peripheral descriptor. + */ + void *extra; +}; + +/** + * @struct irq_desc + * @brief Structure for Interrupt Request descriptor. + */ +struct no_os_irq_ctrl_desc { + /** Interrupt request controller ID. */ + uint32_t irq_ctrl_id; + /** Platform specific IRQ platform ops structure. */ + const struct no_os_irq_platform_ops *platform_ops; + /* Reference counter */ + uint32_t ref; + /** + * This is intended to store irq controller specific configurations, + * it should not be a reference to any peripheral descriptor. + */ + void *extra; +}; + +/** + * @struct no_os_callback_desc + * @brief Structure describing a callback to be registered + * @todo: remove this, use struct irq_callback instead. + */ +struct no_os_callback_desc { + /** Callback to be called when the event an event occurs. */ + void (*callback)(void *context); + /** Parameter to be passed when the callback is called */ + void *ctx; + /** Platform specific event that triggers the calling of the callback. */ + enum no_os_irq_event event; + /** Interrupt source peripheral specifier. */ + enum no_os_irq_peripheral peripheral; + /** This will be used to store HAL specific descriptors */ + void *handle; +}; + +/** + * @struct no_os_irq_platform_ops + * @brief Structure holding IRQ function pointers that point to the platform + * specific function + */ +struct no_os_irq_platform_ops { + /** Initialize a interrupt controller peripheral. */ + int (*init)(struct no_os_irq_ctrl_desc **desc, + const struct no_os_irq_init_param *param); + /** Register a callback to handle the irq events */ + int (*register_callback)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id, + struct no_os_callback_desc *callback); + /** Unregisters a generic IRQ handling function */ + int (*unregister_callback)(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + struct no_os_callback_desc *callback); + /** Global interrupt enable */ + int (*global_enable)(struct no_os_irq_ctrl_desc *desc); + /** Global interrupt disable */ + int (*global_disable)(struct no_os_irq_ctrl_desc *desc); + /** Set interrupt trigger level. */ + int (*trigger_level_set)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id, + enum no_os_irq_trig_level trig); + /** Enable specific interrupt */ + int (*enable)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id); + /** Disable specific interrupt */ + int (*disable)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id); + /** Set the priority level for a specific interrupt */ + int (*set_priority)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id, + uint32_t priority_level); + /** Get the priority level for a specific interrupt */ + int (*get_priority)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id, + uint32_t *priority_level); + /** IRQ remove function pointer */ + int (*remove)(struct no_os_irq_ctrl_desc *desc); + /** Clear pending interrupt */ + int(*clear_pending)(struct no_os_irq_ctrl_desc* desc, uint32_t irq_id); +}; + +/* Initialize a interrupt controller peripheral. */ +int no_os_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc, + const struct no_os_irq_init_param *param); + +/* Free the resources allocated by no_os_irq_ctrl_init(). */ +int no_os_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc); + +/* Register a callback to handle the irq events */ +int no_os_irq_register_callback(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + struct no_os_callback_desc *callback_desc); + +/* Unregisters a generic IRQ handling function */ +int no_os_irq_unregister_callback(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + struct no_os_callback_desc *callback_desc); + +/* Global interrupt enable */ +int no_os_irq_global_enable(struct no_os_irq_ctrl_desc *desc); + +/* Global interrupt disable */ +int no_os_irq_global_disable(struct no_os_irq_ctrl_desc *desc); + +/* Set interrupt trigger level. */ +int no_os_irq_trigger_level_set(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + enum no_os_irq_trig_level trig); + +/* Enable specific interrupt */ +int no_os_irq_enable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id); + +/* Disable specific interrupt */ +int no_os_irq_disable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id); + +/** Set the priority level for a specific interrupt */ +int no_os_irq_set_priority(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + uint32_t priority_level); + +/** Get the priority level for a specific interrupt */ +int no_os_irq_get_priority(struct no_os_irq_ctrl_desc *desc, + uint32_t irq_id, + uint32_t *priority_level); + +/* Clear the pending interrupts */ +int no_os_irq_clear_pending(struct no_os_irq_ctrl_desc* desc, + uint32_t irq_id); +#endif // _NO_OS_IRQ_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.c new file mode 100644 index 0000000..37ec2fb --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.c @@ -0,0 +1,148 @@ +/***************************************************************************//** + * @file no_os_lf256fifo.c + * @brief SPSC lock-free fifo of fixed size (256), specialized for UART. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include +#include "no_os_lf256fifo.h" +#include "no_os_alloc.h" + +/** + * @struct lf256fifo + * @brief Structure holding the fifo element parameters. + */ +struct lf256fifo { + uint8_t * data; // pointer to memory area where the buffer will be allocated + uint8_t ffilled; // the index where the data starts + uint8_t fempty; // the index where empty/non-used area starts +}; + +/** + * @brief Initialize and allocate a lock-free 256 FIFO. + * @param fifo - pointer to a fifo descriptor pointer. + * @return 0 if successful, negative error code otherwise. + */ +int lf256fifo_init(struct lf256fifo **fifo) +{ + if (fifo == NULL) + return -EINVAL; + + struct lf256fifo *b = no_os_calloc(1, sizeof(struct lf256fifo)); + if (b == NULL) + return -ENOMEM; + + b->data = no_os_calloc(1, 256); + if (b->data == NULL) { + no_os_free(b); + return -ENOMEM; + } + + *fifo = b; + + return 0; +} + +/** + * @brief Test whether fifo is full. + * @param fifo - pointer to fifo descriptor. + * @return true if fifo is full, false if not full. + */ +bool lf256fifo_is_full(struct lf256fifo *fifo) +{ + return (fifo->fempty + 1) == + fifo->ffilled; // intended overflow at 256 (data size is 256) +} + +/** +* @brief Test whether fifo is empty. +* @param fifo - pointer to fifo descriptor. +* @return true if fifo is empty, false if not empty. +*/ +bool lf256fifo_is_empty(struct lf256fifo *fifo) +{ + return fifo->fempty == fifo->ffilled; +} + +/** +* @brief Read char from fifo. +* @param fifo - pointer to fifo descriptor. +* @param c - pointer to memory where the char element is read. +* @return 0 if successful, -1 if buffer empty. +*/ +int lf256fifo_read(struct lf256fifo * fifo, uint8_t *c) +{ + if (lf256fifo_is_empty(fifo)) + return -1; // buffer empty + + *c = fifo->data[fifo->ffilled]; + fifo->ffilled++; // intended overflow at 256 (data size is 256) + + return 0; +} + +/** +* @brief Write char to fifo. +* @param fifo - pointer to fifo descriptor. +* @param c - char element to write. +* @return 0 if successful, -1 if buffer full. +*/ +int lf256fifo_write(struct lf256fifo *fifo, uint8_t c) +{ + if (lf256fifo_is_full(fifo)) + return -1; // buffer full + + fifo->data[fifo->fempty] = c; + fifo->fempty++; // intended overflow at 256 (data size is 256) + + return 0; // return success +} + +/** +* @brief Flush the fifo. +* @param fifo - pointer to fifo descriptor. +* @return void +*/ +void lf256fifo_flush(struct lf256fifo *fifo) +{ + fifo->ffilled = fifo->fempty; +} + +/** +* @brief Remove the fifo +* @param fifo - pointer to fifo descriptor. +* @return void +*/ +void lf256fifo_remove(struct lf256fifo *fifo) +{ + if (fifo && fifo->data) + no_os_free(fifo->data); +} + diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.h new file mode 100644 index 0000000..a581d8e --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_lf256fifo.h @@ -0,0 +1,53 @@ +/***************************************************************************//** + * @file no_os_lf256fifo.h + * @brief SPSC lock-free fifo of fixed size (256), specialized for UART. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef __LFFIFO_H +#define __LFFIFO_H + +#include +#include +#include + +struct lf256fifo; + +int lf256fifo_init(struct lf256fifo **); +bool lf256fifo_is_full(struct lf256fifo *); +bool lf256fifo_is_empty(struct lf256fifo *); +int lf256fifo_read(struct lf256fifo *, uint8_t *); +int lf256fifo_write(struct lf256fifo *, uint8_t); +void lf256fifo_flush(struct lf256fifo *); +void lf256fifo_remove(struct lf256fifo *fifo); + +#endif + diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.c new file mode 100644 index 0000000..8b4095b --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.c @@ -0,0 +1,871 @@ +/***************************************************************************//** + * @file no_os_list.c + * @brief List library implementation + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include "no_os_list.h" +#include "no_os_error.h" +#include "no_os_alloc.h" +#include + +/** + * @struct no_os_list_elem + * @brief Format of each element of the list + */ +struct no_os_list_elem { + /** User data */ + void *data; + /** Reference to previous element */ + struct no_os_list_elem *prev; + /** Reference to next element */ + struct no_os_list_elem *next; +}; + +/** + * @struct list_iterator + * @brief Structure used to iterate through the list + */ +struct no_os_iterator { + /** List reference */ + struct _list_desc *list; + /** Current element reference */ + struct no_os_list_elem *elem; +}; + +/** + * @struct _list_desc + * @brief List descriptor + */ +struct _list_desc { + /** Reference to first element in the list */ + struct no_os_list_elem *first; + /** Reference to last element in the list*/ + struct no_os_list_elem *last; + /** Number of elements in the list */ + uint32_t nb_elements; + /** Function used to compare elements */ + f_cmp comparator; + /** Number of current active iterators */ + uint32_t nb_iterators; + /** Internal list iterator */ + struct no_os_iterator l_it; +}; + +/** @brief Default function used to compare element in the list ( \ref f_cmp) */ +static int32_t no_os_default_comparator(void *data1, void *data2) +{ + return (int32_t)((int32_t *)data1 - (int32_t *)data2); +} + +/** + * @brief Creates a new list elements an configure its value + * @param data - To set list_elem.data + * @param prev - To set list_elem.prev + * @param next - To set list_elem.next + * @return Address of the new element or NULL if allocation fails. + */ +static inline struct no_os_list_elem *create_element(void *data, + struct no_os_list_elem *prev, + struct no_os_list_elem *next) +{ + struct no_os_list_elem *elem; + + elem = (struct no_os_list_elem *)no_os_calloc(1, sizeof(*elem)); + if (!elem) + return NULL; + elem->data = data; + elem->prev = prev; + elem->next = next; + + return (elem); +} + +/** + * @brief Updates the necesary link on the list elements to add or remove one + * @param prev - Low element + * @param elem - Middle element + * @param next - High element + */ +static inline void no_os_update_links(struct no_os_list_elem *prev, + struct no_os_list_elem *elem, + struct no_os_list_elem *next) +{ + if (prev) + prev->next = elem ? elem : next; + if (elem) { + elem->prev = prev; + elem->next = next; + } + if (next) + next->prev = elem ? elem : prev; +} + +/** + * @brief Update according to modification the list descriptor + * @param list - List reference + * @param new_first - New first element + * @param new_last - New last element + */ +static inline void no_os_update_desc(struct _list_desc *list, + struct no_os_list_elem *new_first, + struct no_os_list_elem *new_last) +{ + if (new_first == list->first) { + list->last = new_last; + if (new_first == NULL || new_last == NULL) + list->first = new_last; + } else { /* if (new_last == list->last) */ + list->first = new_first; + if (new_last == NULL || new_first == NULL) + list->last = new_first; + } +} + +/** + * @brief Set the adapter functions acording to the adapter type + * @param ad - Reference of the adapter + * @param type - Type of the adapter + */ +static inline void no_os_set_adapter(struct no_os_list_desc *ad, + enum no_os_adapter_type type) +{ + switch (type) { + case NO_OS_LIST_PRIORITY_LIST: + ad->push = no_os_list_add_find; + ad->pop = no_os_list_get_first; + ad->top_next = no_os_list_read_first; + ad->back = no_os_list_read_last; + ad->swap = no_os_list_edit_first; + break; + case NO_OS_LIST_QUEUE: + ad->push = no_os_list_add_last; + ad->pop = no_os_list_get_first; + ad->top_next = no_os_list_read_first; + ad->back = no_os_list_read_last; + ad->swap = no_os_list_edit_first; + break; + case NO_OS_LIST_DEFAULT: + case NO_OS_LIST_STACK: + default: + ad->push = no_os_list_add_last; + ad->pop = no_os_list_get_last; + ad->top_next = no_os_list_read_last; + ad->back = no_os_list_read_first; + ad->swap = no_os_list_edit_last; + break; + } +} + +/** + * @brief Create a new empty list + * @param list_desc - Where to store the reference of the new created list + * @param type - Type of adapter to use. + * @param comparator - Used to compare item when using an ordered list or when + * using the \em find functions. + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_list_init(struct no_os_list_desc **list_desc, + enum no_os_adapter_type type, + f_cmp comparator) +{ + struct no_os_list_desc *l_desc; + struct _list_desc *list; + + + if (!list_desc) + return -1; + l_desc = (struct no_os_list_desc *)no_os_calloc(1, sizeof(*l_desc)); + if (!l_desc) + return -1; + list = (struct _list_desc *)no_os_calloc(1, sizeof(*list)); + if (!list) { + no_os_free(l_desc); + return -1; + } + + *list_desc = l_desc; + l_desc->priv_desc = list; + list->comparator = comparator ? comparator : no_os_default_comparator; + + /* Configure wrapper */ + no_os_set_adapter(l_desc, type); + list->l_it.list = list; + + return 0; +} + +/** + * @brief Remove the created list. + * + * All its elements will be cleared and the data inside each will be lost. If + * not all iterators have been removed, the list will not be removed. + * @param list_desc - Reference to the list + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_list_remove(struct no_os_list_desc *list_desc) +{ + void *data; + struct _list_desc *list; + + if (!list_desc) + return -1; + + list = list_desc->priv_desc; + if (list->nb_iterators != 0) + return -1; + + /* Remove all the elements */ + while (0 == no_os_list_get_first(list_desc, &data)) + ; + no_os_free(list_desc->priv_desc); + no_os_free(list_desc); + + return 0; +} + +/** + * @brief Get the number of elements inside the list + * @param list_desc - List reference + * @param out_size - Where to store the number of elements + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_list_get_size(struct no_os_list_desc *list_desc, + uint32_t *out_size) +{ + struct _list_desc *list; + + if (!list_desc || !out_size) + return -1; + + list = list_desc->priv_desc; + *out_size = list->nb_elements; + + return 0; +} + +/** @brief Add element at the begining of the list. Refer to \ref f_add */ +int32_t no_os_list_add_first(struct no_os_list_desc *list_desc, void *data) +{ + struct no_os_list_elem *prev; + struct no_os_list_elem *next; + struct no_os_list_elem *elem; + struct _list_desc *list; + + if (!list_desc) + return -1; + + list = list_desc->priv_desc; + + prev = NULL; + next = list->first; + elem = create_element(data, prev, next); + if (!elem) + return -1; + + no_os_update_links(prev, elem, next); + + no_os_update_desc(list, elem, list->last); + + list->nb_elements++; + + return 0; +} + +/** @brief Add element at the end of the list. Refer to \ref f_add */ +int32_t no_os_list_add_last(struct no_os_list_desc *list_desc, void *data) +{ + struct no_os_list_elem *prev; + struct no_os_list_elem *next; + struct no_os_list_elem *elem; + struct _list_desc *list; + + if (!list_desc) + return -1; + list = list_desc->priv_desc; + + prev = list->last; + next = NULL; + elem = create_element(data, prev, next); + if (!elem) + return -1; + + no_os_update_links(prev, elem, next); + + no_os_update_desc(list, list->first, elem); + + list->nb_elements++; + + return 0; +} + +/** @brief Add element at the specified idx. Refer to \ref f_add */ +int32_t no_os_list_add_idx(struct no_os_list_desc *list_desc, void *data, + uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc) + return -1; + list = list_desc->priv_desc; + + /* If there are no elements the creation of an iterator will fail */ + if (list->nb_elements == 0 || idx == 0) + return no_os_list_add_first(list_desc, data); + if (list->nb_elements == idx) + return no_os_list_add_last(list_desc, data); + + list->l_it.elem = list->first; + if (0 != no_os_iterator_move(&(list->l_it), idx)) + return -1; + + return no_os_iterator_insert(&(list->l_it), data, 0); +} + +/** @brief Add element in ascending order. Refer to \ref f_add */ +int32_t no_os_list_add_find(struct no_os_list_desc *list_desc, void *data) +{ + struct no_os_list_elem *elem; + struct _list_desc *list; + + if (!list_desc) + return -1; + list = list_desc->priv_desc; + + + /* Based on place iterator */ + elem = list->first; + while (elem) { + if (0 < list->comparator(elem->data, data)) + break; + elem = elem->next; + } + if (elem == NULL) { + list->l_it.elem = list->last; + return no_os_iterator_insert(&(list->l_it), data, 1); + } else { + list->l_it.elem = elem; + return no_os_iterator_insert(&(list->l_it), data, 0); + } + +} + +/** @brief Edit the first element of the list. Refer to \ref f_edit */ +int32_t no_os_list_edit_first(struct no_os_list_desc *list_desc, void *new_data) +{ + struct _list_desc *list; + + if (!list_desc) + return -1; + + list = list_desc->priv_desc; + list->first->data = new_data; + + return 0; +} + +/** @brief Edit the last element of the list. Refer to \ref f_edit */ +int32_t no_os_list_edit_last(struct no_os_list_desc *list_desc, void *new_data) +{ + struct _list_desc *list; + + if (!list_desc) + return -1; + + list = list_desc->priv_desc; + list->last->data = new_data; + + return 0; +} + +/** @brief Edit the element at the specified idx. Refer to \ref f_edit */ +int32_t no_os_list_edit_idx(struct no_os_list_desc *list_desc, void *new_data, + uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc) + return -1; + list = list_desc->priv_desc; + + list->l_it.elem = list->first; + if (0 != no_os_iterator_move(&(list->l_it), idx)) + return -1; + + return no_os_iterator_edit(&(list->l_it), new_data); +} + +/** @brief Edit the element which match with cmp_data. Refer to \ref f_edit */ +int32_t no_os_list_edit_find(struct no_os_list_desc *list_desc, void *new_data, + void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc) + return -1; + list = list_desc->priv_desc; + + list->l_it.elem = list->first; + if (0 != no_os_iterator_find(&(list->l_it), cmp_data)) + return -1; + + return no_os_iterator_edit(&(list->l_it), new_data); +} + +/** @brief Read the first element of the list. Refer to \ref f_read */ +int32_t no_os_list_read_first(struct no_os_list_desc *list_desc, void **data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->first) + return -1; + + *data = list->first->data; + + return 0; +} + +/** @brief Read the last element of the list. Refer to \ref f_read */ +int32_t no_os_list_read_last(struct no_os_list_desc *list_desc, void **data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->last) + return -1; + + *data = list->last->data; + + return 0; +} + +/** @brief Read the element at the specified idx. Refer to \ref f_read */ +int32_t no_os_list_read_idx(struct no_os_list_desc *list_desc, void **data, + uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list) + return -1; + + if (idx >= list->nb_elements) + return -1; + + list->l_it.elem = list->first; + if (0 != no_os_iterator_move(&(list->l_it), idx)) + return -1; + + return no_os_iterator_read(&(list->l_it), data); +} + +/** @brief Read the element which match with cmp_data. Refer to \ref f_read */ +int32_t no_os_list_read_find(struct no_os_list_desc *list_desc, void **data, + void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list) + return -1; + + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (0 != no_os_iterator_find(&(list->l_it), cmp_data)) + return -1; + + return no_os_iterator_read(&(list->l_it), data); +} + +/** @brief Read and delete the first element of the list. Refer to \ref f_get */ +int32_t no_os_list_get_first(struct no_os_list_desc *list_desc, void **data) +{ + struct no_os_list_elem *prev; + struct no_os_list_elem *next; + struct no_os_list_elem *elem; + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->nb_elements) + return -1; + + elem = list->first; + prev = elem->prev; + next = elem->next; + + no_os_update_links(prev, NULL, next); + no_os_update_desc(list, next, list->last); + list->nb_elements--; + + *data = elem->data; + no_os_free(elem); + + return 0; +} + +/** @brief Read and delete the last element of the list. Refer to \ref f_get */ +int32_t no_os_list_get_last(struct no_os_list_desc *list_desc, void **data) +{ + struct no_os_list_elem *prev; + struct no_os_list_elem *next; + struct no_os_list_elem *elem; + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->nb_elements) + return -1; + + elem = list->last; + prev = elem->prev; + next = elem->next; + + no_os_update_links(prev, NULL, next); + no_os_update_desc(list, list->first, prev); + list->nb_elements--; + + *data = elem->data; + no_os_free(elem); + + return 0; +} + +/** @brief Read and delete the element at idx. Refer to \ref f_get */ +int32_t no_os_list_get_idx(struct no_os_list_desc *list_desc, void **data, + uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (0 != no_os_iterator_move(&(list->l_it), idx)) + return -1; + + return no_os_iterator_get(&(list->l_it), data); +} + +/** + * @brief Read and delete the element which match with cmp_data. + * Refer to \ref f_get + */ +int32_t no_os_list_get_find(struct no_os_list_desc *list_desc, void **data, + void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return -1; + + *data = NULL; + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (0 != no_os_iterator_find(&(list->l_it), cmp_data)) + return -1; + + return no_os_iterator_get(&(list->l_it), data); +} + +/** + * @brief Create a new iterator + * @param iter - Where to store the reference for the new iterator + * @param list_desc - Reference of the list the iterator will be used for + * @param start - If it is true the iterator will be positioned at the first + * element of the list, else it will be positioned at the last. + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_iterator_init(struct no_os_iterator **iter, + struct no_os_list_desc *list_desc, + bool start) +{ + struct no_os_iterator *it; + + if (!list_desc) + return -1; + + it = (struct no_os_iterator *)no_os_calloc(1, sizeof(*it)); + if (!it) + return -1; + it->list = list_desc->priv_desc; + it->list->nb_iterators++; + it->elem = start ? it->list->first : it->list->last; + *iter = it; + + return 0; +} + +/** + * @brief Remove the created iterator + * @param iter - Reference of the iterator + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_iterator_remove(struct no_os_iterator *iter) +{ + struct no_os_iterator *it = iter; + + if (!it) + return -1; + + it->list->nb_iterators--; + no_os_free(it); + + return 0; +} + +/** + * @brief Move the position of the iteration through the list. + * + * If the required position is outside the list, the call will fail and the + * iterator will keep its position. + * @param iter - Reference of the iterator + * @param steps - Number of positions to be move. If positive, it will be moved + * forward, otherwise backwords. + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_iterator_move(struct no_os_iterator *iter, int32_t steps) +{ + struct no_os_iterator *it = iter; + struct no_os_list_elem *elem; + int32_t dir = (steps < 0) ? -1 : 1; + + if (!it) + return -1; + + steps = abs(steps); + elem = it->elem; + while (steps > 0 && elem) { + elem = dir > 0 ? elem->next : elem->prev; + steps--; + } + if (!elem) + return -1; + + it->elem = elem; + + return 0; +} + +/** + * @brief Move the position of the iterator at the specified index of the list. + * + * @param iter - Reference of the iterator + * @param idx - Position in the list. If negative start counting backwords + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_iterator_move_to_idx(struct no_os_iterator *iter, int32_t idx) +{ + struct no_os_list_elem *elem; + int32_t dir = (idx < 0) ? -1 : 1; + + if (!iter) + return -1; + + idx = abs(idx); + elem = dir > 0 ? iter->list->first : iter->list->last; + while (idx > 0 && elem) { + elem = dir > 0 ? elem->next : elem->prev; + idx--; + } + if (!elem) + return -1; + + iter->elem = elem; + + return 0; +} + +/** + * @brief Place the iterator where cmp_data if found. + * @param iter - Reference to the iterator + * @param cmp_data - Data to be found + * @return + * - 0 : On success + * - -1 : Otherwise + */ +int32_t no_os_iterator_find(struct no_os_iterator *iter, void *cmp_data) +{ + struct no_os_iterator *it = iter; + struct no_os_list_elem *elem; + + if (!it) + return -1; + + elem = it->list->first; + while (elem) { + if (0 == it->list->comparator(elem->data, cmp_data)) { + it->elem = elem; + return 0; + } + elem = elem->next; + } + + return -1; +} + +/** + * @brief Replace the data at the current position. Refer to \ref f_edit + */ +int32_t no_os_iterator_edit(struct no_os_iterator *iter, void *new_data) +{ + struct no_os_iterator *it = iter; + + if (!it) + return -1; + + it->elem->data = new_data; + + return 0; +} + +/** + * @brief Read and remove the data at the current position. Refer to \ref f_get. + * + * If the current item is the last one, the iterator will be moved to the + * previous one. + */ +int32_t no_os_iterator_get(struct no_os_iterator *iter, void **data) +{ + struct no_os_iterator *it = iter; + struct no_os_list_elem *next; + + + if (!it || !it->elem || !data) + return -1; + + no_os_update_links(it->elem->prev, NULL, it->elem->next); + if (it->elem == it->list->first) + no_os_update_desc(it->list, it->elem->next, it->list->last); + else if (it->elem == it->list->last) + no_os_update_desc(it->list, it->list->first, it->elem->prev); + it->list->nb_elements--; + + *data = it->elem->data; + if (it->elem == it->list->last) + next = it->elem->prev; + else + next = it->elem->next; + no_os_free(it->elem); + it->elem = next; + + return 0; +} + +/** + * @brief Read the data at the current position. Refer to \ref f_read + */ +int32_t no_os_iterator_read(struct no_os_iterator *iter, void **data) +{ + struct no_os_iterator *it = iter; + + if (!it || !it->elem || !data) + return -1; + + *data = it->elem->data; + + return 0; +} + +/** + * @brief Insert an item in the list. Refer to \ref f_add + * @param iter + * @param data + * @param after - If true, the item will be inserted after the current position. + * Otherwise it will be inserted before. + */ +int32_t no_os_iterator_insert(struct no_os_iterator *iter, void *data, + bool after) +{ + struct no_os_iterator *it = iter; + struct no_os_list_elem *elem; + struct no_os_list_desc list_desc; + + if (!it) + return -1; + + list_desc.priv_desc = iter->list; + if (after && it->elem == it->list->last) + return no_os_list_add_last(&list_desc, data); + if (!after && it->elem == it->list->first) + return no_os_list_add_first(&list_desc, data); + + if (after) + elem = create_element(data, it->elem, it->elem->next); + else + elem = create_element(data, it->elem->prev, it->elem); + if (!elem) + return -1; + + no_os_update_links(elem->prev, elem, elem->next); + + it->list->nb_elements++; + + return 0; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.h new file mode 100644 index 0000000..002d6be --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_list.h @@ -0,0 +1,309 @@ +/***************************************************************************//** + * @file no_os_list.h + * @brief List library header + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +******************************************************************************** + * + * @section list_details Library description + * This library handles double linked lists and it expose inseart, + * read, get and delete functions. \n + * It also can be accesed using it member functions which wrapp function for + * usual list types.\n + * @subsection example Sample code + * @code{.c} + * // -- Use a generic list + * struct no_os_list_desc *list1; + * struct no_os_iterator *it; + * uint32_t a; + * // Create list list1 + * no_os_list_init(&list1, NO_OS_LIST_DEFAULT, NULL); + * // Add items to the list + * no_os_list_add_last(list1, 1); + * no_os_list_add_last(list1, 2); + * no_os_list_add_last(list1, 3); + * // Here the list will be: 1 -> 2 - > 3 + * + * no_os_list_read_last(list1, &a); + * printf("Last: %d\n", a); + * // 3 will be printed + * // Create an iterator on the end of the list + * no_os_iterator_init(&it, list1, 0); + * // Move the iterator backword with one position + * no_os_iterator_move(it, -1); + * // Read the data at the current position + * no_os_iterator_read(it, &a); + * printf("Current: %d\n", a); + * // 2 will be printed + * no_os_iterator_remove(it); + * no_os_list_remove(list1); + * + * // -- Use a popular list + * struct no_os_list_desc *stack; + * // Create a FIFO list + * no_os_list_init(&stack, NO_OS_LIST_STACK, NULL); + * // Put elements in the list + * stack->push(stack, 1); + * stack->push(stack, 2); + * stack->push(stack, 3); + * // Read from the stack + * stack->pop(stack, &a); + * printf("Last: %d\n", a); + * // 3 will be printed + * no_os_list_remove(stack); + * @endcode +*******************************************************************************/ + +#ifndef _NO_OS_LIST_H_ +#define _NO_OS_LIST_H_ + +#include +#include + +/** + * @struct no_os_list_desc + * @brief Structure storing the list and function wrapper for usual list types + * + * With this structure the funtionalities of usual list types + * ( \ref no_os_adapter_type ) can be accesed with the functions referenced in this + * structure. + * For example: + * @code{.c} + * my_queue->push(my_queue, my_data); + * @endcode + */ +struct no_os_list_desc; + +/** + * @struct list_iterator + * @brief Structure used to iterate through the list using Iterator functions. + */ +struct no_os_iterator; + +/** + * @brief Prototype of the compare function. + * + * The function used to compare the elements of the liste when doing + * operations on an ordered list. + * @param data1 - First element to be compared + * @param data2 - Second element to be compared + * @return + * - -1 - If data1 < data2 + * - 0 - If data1 == data2 + * - 1 - If data1 > data2 + */ +typedef int32_t (*f_cmp)(void *data1, void *data2); + +/** + * @name Generic functions + * Each function interacting with the list have one of the following formats.\n + * Aditionaly they may have one more parametere for specific functionalities.\n + * In the Iterator functions, the list reference is replaced by the iterator's + * one. + * @{ + */ + +/** + * @brief Add an element in the list. + * + * The element of the list is created and the data field is stored in it. + * @param list_desc - Reference to the list. Created by \ref no_os_list_init. + * @param data - Data to store in a list element + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_add)(struct no_os_list_desc *list_desc, void *data); + +/** + * @brief Edit an element in the list. The content is replaced by new_data. + * @param list_desc - Reference to the list. Created by \ref no_os_list_init. + * @param new_data - New data to replace the old one + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_edit)(struct no_os_list_desc *list_desc, void *new_data); + +/** + * @brief Read an element from the list. + * @param list_desc - Reference to the list. Created by \ref no_os_list_init. + * @param result - If not null, result is filled with: + * @param data - Content of the list element, NULL if some error occur. + * @return \n + * - 0 : On success + * - -1 : Otherwise + * @note If the content of an element can be 0 then the result must be checked + * to see if the functions has succeded + */ +typedef int32_t (*f_read)(struct no_os_list_desc *list_desc, void **data); + +/** + * @brief Read and remove an element from the list. + * @param list_desc - Reference to the list. Created by \ref no_os_list_init. + * @param result - If not null, result is filled with: + * @param data - Content of the list element, NULL if some error occur. + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_get)(struct no_os_list_desc *list_desc, void **data); + +/** @} */ + +/** + * @enum no_os_adapter_type + * @brief Selects functionalities for functions in \ref no_os_list_desc + */ +enum no_os_adapter_type { + /** Default type is NO_OS_LIST_STACK */ + NO_OS_LIST_DEFAULT, + /** + * Functions for a FIFO list (First-in first-out). Elements are inserted + * in one end and extracted from the other end. + * - \e Push: Insert element + * - \e Pop: Get next element (Read and remove) + * - \e Top_next: Read next element + * - \e Back: Read first element + * - \e Swap: Edit the content of the next element + */ + NO_OS_LIST_QUEUE, + /** + * Functions for a LIFO list (Last-in first-out). Elements are inserted + * and extracted only from the same end. + * - \e Push: Insert element + * - \e Pop: Get top element (Read and remove) + * - \e Top_next: Read top element + * - \e Back: Read bottom element + * - \e Swap: Edit the content of the top element + */ + NO_OS_LIST_STACK, + /** + * Functions for ordered list. The order of element is determinated + * usinge the \ref f_cmp. + * - \e Push: Insert element + * - \e Pop: Get lowest element (Read and remove) + * - \e Top_next: Read lowest element + * - \e Back: Read the biggest element + * - \e Swap: Edit the lowest element + */ + NO_OS_LIST_PRIORITY_LIST +}; + +struct no_os_list_desc { + /** Refer to \ref no_os_adapter_type */ + f_add push; + /** Refer to \ref no_os_adapter_type */ + f_get pop; + /** Refer to \ref no_os_adapter_type */ + f_read top_next; + /** Refer to \ref no_os_adapter_type */ + f_read back; + /** Refer to \ref no_os_adapter_type */ + f_edit swap; + /** Structure storing the list internal parameters */ + void *priv_desc; +}; + +int32_t no_os_list_init(struct no_os_list_desc **list_desc, + enum no_os_adapter_type type, + f_cmp comparator); +int32_t no_os_list_remove(struct no_os_list_desc *list_desc); +int32_t no_os_list_get_size(struct no_os_list_desc *list_desc, + uint32_t *out_size); + +/** + * @name Iterator functions + * An iterator is used to iterate through the list. For a list, any number of + * iterators can be created. All must be removed before removing a list. + * @{ + */ +int32_t no_os_iterator_init(struct no_os_iterator **iter, + struct no_os_list_desc *list_desc, + bool start); +int32_t no_os_iterator_remove(struct no_os_iterator *iter); +int32_t no_os_iterator_move(struct no_os_iterator *iter, int32_t steps); +int32_t no_os_iterator_move_to_idx(struct no_os_iterator *iter, int32_t idx); +int32_t no_os_iterator_find(struct no_os_iterator *iter, void *cmp_data); +int32_t no_os_iterator_insert(struct no_os_iterator *iter, void *data, + bool after); +int32_t no_os_iterator_edit(struct no_os_iterator *iter, void *new_data); +int32_t no_os_iterator_read(struct no_os_iterator *iter, void **data); +int32_t no_os_iterator_get(struct no_os_iterator *iter, void **data); +/** @}*/ + +/** + * @name Operations on the ends of the list + * These functions will operate on the first or last element of the list + * @{ + */ +int32_t no_os_list_add_first(struct no_os_list_desc *list_desc, void *data); +int32_t no_os_list_edit_first(struct no_os_list_desc *list_desc, + void *new_data); +int32_t no_os_list_read_first(struct no_os_list_desc *list_desc, void **data); +int32_t no_os_list_get_first(struct no_os_list_desc *list_desc, void **data); + +int32_t no_os_list_add_last(struct no_os_list_desc *list_desc, void *data); +int32_t no_os_list_edit_last(struct no_os_list_desc *list_desc, void *new_data); +int32_t no_os_list_read_last(struct no_os_list_desc *list_desc, void **data); +int32_t no_os_list_get_last(struct no_os_list_desc *list_desc, void **data); +/** @}*/ + +/** + * @name Operations by index + * These functions use an index to identify the element in the list. + * @{ + */ +int32_t no_os_list_add_idx(struct no_os_list_desc *list_desc, void *data, + uint32_t idx); +int32_t no_os_list_edit_idx(struct no_os_list_desc *list_desc, void *new_data, + uint32_t idx); +int32_t no_os_list_read_idx(struct no_os_list_desc *list_desc, void **data, + uint32_t idx); +int32_t no_os_list_get_idx(struct no_os_list_desc *list_desc, void **data, + uint32_t idx); +/** @}*/ + +/** + * @name Operations by comparation + * These functions use the specified \ref f_cmp at \ref no_os_list_init to identify + * the element this will operate on. + * @{ + */ +int32_t no_os_list_add_find(struct no_os_list_desc *list_desc, void *data); +int32_t no_os_list_edit_find(struct no_os_list_desc *list_desc, void *new_data, + void *cmp_data); +int32_t no_os_list_read_find(struct no_os_list_desc *list_desc, void **data, + void *cmp_data); +int32_t no_os_list_get_find(struct no_os_list_desc *list_desc, void **data, + void *cmp_data); +/** @}*/ + +#endif // _NO_OS_LIST_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.c new file mode 100644 index 0000000..5c3aaa1 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.c @@ -0,0 +1,119 @@ +/***************************************************************************//** + * @file no_os_mdio.c + * @brief Source file for MDIO interface driver. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include +#include "no_os_mdio.h" + +/** + * @brief Initialize the MDIO interface. + * @param desc - The MDIO descriptor. + * @param param - MDIO parameters. + * @return 0 in case of success, error code otherwise. + */ +int no_os_mdio_init(struct no_os_mdio_desc **desc, + struct no_os_mdio_init_param *param) +{ + int ret; + + if (!param || !param->ops) + return -EINVAL; + + if (!param->ops->init) + return -ENOSYS; + + ret = param->ops->init(desc, param); + if (ret) + return ret; + + (*desc)->id = param->id; + (*desc)->c45 = param->c45; + (*desc)->addr = param->addr; + (*desc)->ops = param->ops; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_mdio_init(). + * @param desc - The MDIO descriptor. + * @return 0 in case of success, error code otherwise. + */ +int no_os_mdio_remove(struct no_os_mdio_desc *desc) +{ + if (!desc || !desc->ops) + return -EINVAL; + + if (!desc->ops->remove) + return -ENOSYS; + + return desc->ops->remove(desc); +} + +/** + * @brief Write a register using MDIO. + * @param desc - The MDIO descriptor. + * @param reg - Register address. + * For clause 45 reg is constructed using NO_OS_MDIO_C45_ADDR macro. + * It is otherwise the plain clause 22 address (0...31). + * @param val - Value to write into register. + * @return 0 in case of success, error code otherwise. + */ +int no_os_mdio_write(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t val) +{ + if (!desc || !desc->ops) + return -EINVAL; + + if (!desc->ops->write) + return -ENOSYS; + + return desc->ops->write(desc, reg, val); +} + +/** + * @brief Read a register using MDIO. + * @param desc - The MDIO descriptor. + * @param reg - Register address. + * For clause 45 reg is constructed using NO_OS_MDIO_C45_ADDR macro. + * It is otherwise the plain clause 22 address (0...31). + * @param val - Value read from register. + * @return 0 in case of success, error code otherwise. + */ +int no_os_mdio_read(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t *val) +{ + if (!desc || !desc->ops) + return -EINVAL; + + if (!desc->ops->read) + return -ENOSYS; + + return desc->ops->read(desc, reg, val); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.h new file mode 100644 index 0000000..8dc02b7 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mdio.h @@ -0,0 +1,107 @@ +/***************************************************************************//** + * @file no_os_mdio.h + * @brief Header file for MDIO interface driver. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_MDIO_H_ +#define _NO_OS_MDIO_H_ + +#include +#include +#include "no_os_util.h" + +#define NO_OS_MDIO_C22_REGS 32 +#define NO_OS_MDIO_C45_START 0 +#define NO_OS_MDIO_C22_START 1 +#define NO_OS_MDIO_START_MASK NO_OS_GENMASK(31, 30) +#define NO_OS_MDIO_OP_ADDRESS 0 +#define NO_OS_MDIO_OP_WRITE 1 +#define NO_OS_MDIO_OP_READ 2 +#define NO_OS_MDIO_OP_MASK NO_OS_GENMASK(29, 28) +#define NO_OS_MDIO_PHYADDR_MASK NO_OS_GENMASK(27, 23) +#define NO_OS_MDIO_REGADDR_MASK NO_OS_GENMASK(22, 18) +#define NO_OS_MDIO_TURNAROUND 2 +#define NO_OS_MDIO_TURNAROUND_MASK NO_OS_GENMASK(17, 16) +#define NO_OS_MDIO_DATA_MASK NO_OS_GENMASK(15, 0) +#define NO_OS_MDIO_C45_DEVADDR_MASK NO_OS_GENMASK(20, 16) +#define NO_OS_MDIO_C45_ADDR(dev, reg) (NO_OS_BIT(31) | no_os_field_prep(NO_OS_MDIO_C45_DEVADDR_MASK, dev) | (uint16_t)reg) + +/** + * @struct no_os_mdio_init_param + * @brief Parameters for an MDIO slave. + */ +struct no_os_mdio_init_param { + /** Device ID (when using MDIO peripheral), optional. */ + int id; + /** Specifies if clause 45 frame format is supported by the slave, + * otherwise clause 22 frame format is used. */ + bool c45; + /** MDIO slave address on the bus. */ + uint8_t addr; + /** Specific implementations of the API. */ + struct no_os_mdio_ops *ops; + /** Platform or implementation specific parameters. */ + void *extra; +}; + +/** + * @struct no_os_mdio_desc + * @brief MDIO device descriptor created with no_os_mdio_init(). + */ +struct no_os_mdio_desc { + int id; + bool c45; + uint8_t addr; + struct no_os_mdio_ops *ops; + void *extra; +}; + +/** + * @struct no_os_mdio_ops + * @brief Collection of MDIO ops that point to specific implementations. + */ +struct no_os_mdio_ops { + /** MDIO initialization op */ + int (*init)(struct no_os_mdio_desc **, struct no_os_mdio_init_param *); + /** MDIO write register op */ + int (*write)(struct no_os_mdio_desc *, uint32_t, uint16_t); + /** MDIO read register op */ + int (*read)(struct no_os_mdio_desc *, uint32_t, uint16_t *); + /** MDIO remove op */ + int (*remove)(struct no_os_mdio_desc *); +}; + +int no_os_mdio_init(struct no_os_mdio_desc **desc, + struct no_os_mdio_init_param *param); +int no_os_mdio_remove(struct no_os_mdio_desc *desc); +int no_os_mdio_write(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t val); +int no_os_mdio_read(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t *val); + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.c new file mode 100644 index 0000000..b5741e8 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.c @@ -0,0 +1,63 @@ +/******************************************************************************* + * @file util/no_os_mutex.c + * @brief Implementation of no-OS mutex funtionality. + * @author Robert Budai (robert.budai@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include "no_os_mutex.h" + +/** + * @brief Initialize mutex. + * @param ptr - Pointer toward the mutex. + * @return None. + */ +__attribute__((weak)) void no_os_mutex_init(void **mutex) {} + +/** + * @brief Lock mutex. + * @param ptr - Pointer toward the mutex. + * @return None. + */ +__attribute__((weak)) void no_os_mutex_lock(void *mutex) {} + +/** + * @brief Unlock mutex. + * @param ptr - Pointer toward the mutex. + * @return None. + */ +__attribute((weak)) void no_os_mutex_unlock(void *mutex) {} + +/** + * @brief Remove mutex. + * @param ptr - Pointer toward the mutex. + * @return None. + */ +__attribute__((weak)) void no_os_mutex_remove(void *mutex) {} + diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.h new file mode 100644 index 0000000..0ddbd8e --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_mutex.h @@ -0,0 +1,78 @@ +/******************************************************************************* + * @file no_os_mutex.h + * @brief Header file of mutex implementation. + * @author Robert Budai (robert.budai@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_MUTEX_H_ +#define _NO_OS_MUTEX_H_ + +/** +* @brief Function for no-os mutex initialization and thread safety. +* This function is implemented based on different platforms/OS libraries +* that NO-OS supports. These mutex functions are used for thread safety +* of peripherals. Since these functions don't return error values it is +* the developers responsibility to implement the safety checks in case +* new mutex implementation is being added, like the following: +* +* if ((*mutex) == NULL) +* { +* //code to initialize the mutex +* } +* +* Also these check are responsible not to allocate different mutexes +* for the same peripheral descriptor. +*/ +void no_os_mutex_init(void **mutex); + +/** + * @brief Function for locking mutex +*/ +void no_os_mutex_lock(void *mutex); + +/** + * @brief Function for unlocking mutex +*/ +void no_os_mutex_unlock(void *mutex); + +/** + * @brief Function for removing the initialized mutex. + * This function is responsible to remove the allocated mutex. This function is + * also used by the peripherals mutex thread safety feature and in case + * new mutex implementation is going to be added, it is the developers + * responsibility to add extra check inside the function while de-allocating the memory. + * + * if (mutex != NULL) + * { + * //code to de-allocate mutex + * } +*/ +void no_os_mutex_remove(void *mutex); + +#endif // _NO_OS_MUTEX_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.c new file mode 100644 index 0000000..c39bce4 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.c @@ -0,0 +1,202 @@ +/***************************************************************************//** + * @file no_os_pid.c + * @brief Source file for PID control utility. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include +#include "no_os_pid.h" +#include "no_os_alloc.h" +#include "no_os_print_log.h" + +struct no_os_pid { + int iacc; // integral accumulator + int dacc; // derivative accumulator + int64_t output; // on 64-bits to avoid overflow + struct no_os_pid_config config; // copy of the user-provided configuration +}; + +/** + * @brief Initialize a PID controller with given configuration + * @param pid - Double pointer to a PID descriptor that the function allocates + * @param config - PID configuration structure + * @return + * - 0 : On success + * - -EINVAL : Invalid input + * - -ENOMEM : Memory allocation failure + */ +int no_os_pid_init(struct no_os_pid **pid, struct no_os_pid_config config) +{ + if (!pid) + return -EINVAL; + + if (config.output_clip.high < config.output_clip.low) + return -EINVAL; + + *pid = no_os_calloc(1, sizeof(**pid)); + if (!*pid) + return -ENOMEM; + + (*pid)->config = config; + (*pid)->output = config.initial; + (*pid)->iacc = 0; + (*pid)->dacc = 0; + + return 0; +} + +/** + * @brief Perform PID control given a controller, a set-point and a process variable. + * @param pid - PID descriptor created with no_os_pid_init() + * @param SP - Set-point + * @param PV - Process variable + * @param output - The output of the PID control + * @return + * - 0 : On success + * - -EINVAL : Invalid input + */ +int no_os_pid_control(struct no_os_pid *pid, int SP, int PV, int *output) +{ + int err; // error + int64_t p; // proportional component + int64_t i; // integral component + int64_t d; // derivative component + struct no_os_pid_range *i_clip; + struct no_os_pid_range *output_clip; + + if (!pid || !output) + return -EINVAL; + + i_clip = &pid->config.i_clip; + output_clip = &pid->config.output_clip; + + // error is the difference between the set point and process variable + err = SP - PV; + + // don't control (maintain output) if within hysteresis range + if (abs(err) < pid->config.hysteresis) { + pr_debug("SP: %d PV: %d --> output: %lu for err=%d\n", SP, PV, pid->output, + err); + goto end; + } + + // compute proportional component + p = (int64_t)pid->config.Kp * err; + + // clip integrator accumulator if enabled and if needed + if (i_clip->high > i_clip->low) { + if (pid->iacc > i_clip->high) + pid->iacc = i_clip->high; + else if (pid->iacc < i_clip->low) + pid->iacc = i_clip->low; + } + + // compute integral component + i = (int64_t)pid->config.Ki * pid->iacc; + + // compute the derivative component + d = (int64_t)pid->config.Kd * (pid->dacc - err); + + // compute the output + pid->output = (pid->output * 1000000 - (p + i + d)) / 1000000; + pr_debug("SP: %d PV: %d --> output: %ld for p %ld i %ld d %ld err=%d\n", SP, PV, + pid->output, p, i, d, err); + + // clip the output if enabled and if needed + if (output_clip->high > output_clip->low) { + if (pid->output > output_clip->high) + pid->output = output_clip->high; + else if (pid->output < output_clip->low) + pid->output = output_clip->low; + } + + // keep track of error history in the integrator accumulator + pid->iacc += err; + + // keep track of process variable change rate in the derivative accumulator + pid->dacc = err; +end: + *output = pid->output; + + return 0; +} + +/** + * @brief Change the hysteresis. + * @param pid - PID descriptor created with no_os_pid_init() + * @param hyst - The new hysteresis value + * @return + * - 0 : On success + * - -EINVAL : Invalid input + */ +int no_os_pid_hysteresis(struct no_os_pid *pid, unsigned int hyst) +{ + if (!pid) + return -EINVAL; + + pid->config.hysteresis = hyst; + + return 0; +} + +/** + * @brief Reset internal accumulators, useful when the same pid descriptor is used to start over. + * @param pid - PID descriptor created with no_os_pid_init() + * @return + * - 0 : On success + * - -EINVAL : Invalid input + */ +int no_os_pid_reset(struct no_os_pid *pid) +{ + if (!pid) + return -EINVAL; + + pid->iacc = 0; + pid->dacc = 0; + + return 0; +} + +/** + * @brief De-initialize a PID controller by freeing the allocated memory + * @param pid - PID descriptor created with no_os_pid_init() + * @return + * - 0 : On success + * - -EINVAL : Invalid input + */ +int no_os_pid_remove(struct no_os_pid *pid) +{ + if (!pid) + return -EINVAL; + + no_os_free(pid); + pid = NULL; + + return 0; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.h new file mode 100644 index 0000000..20b212c --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pid.h @@ -0,0 +1,79 @@ +/***************************************************************************//** + * @file no_os_pid.h + * @brief Header file for PID control utility. + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_PID_H +#define _NO_OS_PID_H +#include +#include +#include + +/** + * @struct no_os_pid_range + * @brief Range definition for limiting PID control output or internal integrator accumulator + */ +struct no_os_pid_range { + /* High limit of the range */ + int high; + /** Low limit of the range */ + int low; +}; + +/** + * @struct no_os_pid_config + * @brief Configuration of the PID + */ +struct no_os_pid_config { + /** Proportional gain (micro-units) */ + unsigned int Kp; + /** Integral gain (micro-units) */ + unsigned int Ki; + /** Derivative gain (micro-units) */ + unsigned int Kd; + /** (Optional) Control supressed when process variable is within set point +/- hysteresis */ + unsigned int hysteresis; + /** (Optional) Boundary limits for integral component */ + struct no_os_pid_range i_clip; + /** (Optional) Boundary limits for the output (for example, for an 8-bit controlled PWM, one would clip the output to 0-255 range) */ + struct no_os_pid_range output_clip; + /** (Optional) Initial output */ + int initial; +}; + +struct no_os_pid; + +int no_os_pid_init(struct no_os_pid **pid, struct no_os_pid_config config); +int no_os_pid_control(struct no_os_pid *pid, int SP, int PV, int *output); +int no_os_pid_hysteresis(struct no_os_pid *pid, unsigned int hyst); +int no_os_pid_reset(struct no_os_pid *pid); +int no_os_pid_remove(struct no_os_pid *pid); + +#endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_print_log.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_print_log.h new file mode 100644 index 0000000..8a6877f --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_print_log.h @@ -0,0 +1,132 @@ +/***************************************************************************//** + * @file no_os_print_log.h + * @brief Print messages helpers. + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_PRINT_LOG_H_ +#define _NO_OS_PRINT_LOG_H_ + +#include + +#define NO_OS_LOG_EMERG 0x0 +#define NO_OS_LOG_ALERT 0x1 +#define NO_OS_LOG_CRIT 0x2 +#define NO_OS_LOG_ERR 0x3 +#define NO_OS_LOG_WARNING 0x4 +#define NO_OS_LOG_NOTICE 0x5 +#define NO_OS_LOG_INFO 0x6 +#define NO_OS_LOG_DEBUG 0x7 + +#ifndef NO_OS_LOG_LEVEL +#define NO_OS_LOG_LEVEL NO_OS_LOG_INFO +#endif + +#if defined(PRINT_TIME) +#define pr_time { struct no_os_time _t = no_os_get_time(); \ + printf("[%5d.%06d] ", _t.s, _t.us); \ +} +#else +#define pr_time ; +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_EMERG && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_emerg(fmt, args...) do { \ + pr_time \ + printf("EMERG: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \ +} while (0) +#else +#define pr_emerg(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_ALERT && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_alert(fmt, args...) do { \ + pr_time \ + printf("ALERT: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \ +} while (0) +#else +#define pr_alert(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_CRIT && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_crit(fmt, args...) do { \ + pr_time \ + printf("CRIT: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \ +} while (0) +#else +#define pr_crit(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_ERR && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_err(fmt, args...) do { \ + pr_time \ + printf("ERR: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \ +} while (0) +#else +#define pr_err(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_WARNING && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_warning(fmt, args...) do { \ + pr_time \ + printf("WARNING: " fmt, ##args); \ +} while (0) +#else +#define pr_warning(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_NOTICE && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_notice(fmt, args...) do { \ + pr_time \ + printf("NOTICE: " fmt, ##args); \ +} while (0) +#else +#define pr_notice(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_INFO && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG +#define pr_info(fmt, args...) do { \ + pr_time \ + printf(fmt, ##args); \ +} while(0) +#else +#define pr_info(fmt, args...) +#endif + +#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL == NO_OS_LOG_DEBUG +#define pr_debug(fmt, args...) do { \ + pr_time \ + printf("DEBUG: " fmt, ##args); \ +} while(0) +#else +#define pr_debug(fmt, args...) +#endif + +#endif // _NO_OS_PRINT_LOG_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.c new file mode 100644 index 0000000..db6d0a4 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.c @@ -0,0 +1,273 @@ +/***************************************************************************//** + * @file no_os_pwm.c + * @brief Implementation of the PWM Interface + * @author Pratyush Mallick (pratyush.mallick@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_pwm.h" +#include +#include "no_os_error.h" +#include "no_os_mutex.h" + +/** + * @brief - PWM mutex +*/ +static void *pwm_mutex_table[PWM_MAX_NUMBER + 1]; + +/** + * @brief Initialize the PWM peripheral. + * @param desc - The PWM descriptor. + * @param param - The structure that contains the PWM parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_init(struct no_os_pwm_desc **desc, + const struct no_os_pwm_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->pwm_ops_init) + return -ENOSYS; + + ret = param->platform_ops->pwm_ops_init(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + no_os_mutex_init(&pwm_mutex_table[param->id]); + (*desc)->mutex = pwm_mutex_table[param->id]; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_pwm_init(). + * @param desc - The PWM descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_remove(struct no_os_pwm_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_remove) + return -ENOSYS; + + no_os_mutex_remove(desc->mutex); + pwm_mutex_table[desc->id] = NULL; + + return desc->platform_ops->pwm_ops_remove(desc); +} + +/** + * @brief Enable PWM signal generation. + * @param desc - The PWM descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_enable(struct no_os_pwm_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_enable) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + return desc->platform_ops->pwm_ops_enable(desc); +} + +/** + * @brief Disable PWM signal generation. + * @param desc - The PWM descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_disable(struct no_os_pwm_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_disable) + return -ENOSYS; + + no_os_mutex_unlock(desc->mutex); + return desc->platform_ops->pwm_ops_disable(desc); +} + +/** + * @brief Set the PWM period value. + * @param desc - The PWM descriptor. + * @param period_ns - The period value in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_set_period(struct no_os_pwm_desc *desc, + uint32_t period_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_set_period) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_set_period(desc, period_ns); +} + +/** + * @brief Get the PWM period value. + * @param desc - The PWM descriptor. + * @param period_ns - The period value in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_get_period(struct no_os_pwm_desc *desc, + uint32_t *period_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_get_period) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_get_period(desc, period_ns); +} + +/** + * @brief Set the PWM duty cycle. + * @param desc - The PWM descriptor. + * @param duty_cycle_ns - Duty cycle in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_set_duty_cycle(struct no_os_pwm_desc *desc, + uint32_t duty_cycle_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_set_duty_cycle) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_set_duty_cycle(desc, duty_cycle_ns); +} + +/** + * @brief Get the PWM duty cycle. + * @param desc - The PWM descriptor. + * @param duty_cycle_ns - Duty cycle in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_get_duty_cycle(struct no_os_pwm_desc *desc, + uint32_t *duty_cycle_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_get_duty_cycle) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_get_duty_cycle(desc, duty_cycle_ns); +} + +/** + * @brief Set the PWM phase value. + * @param desc - The PWM descriptor. + * @param phase_ns - Phase value in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_set_phase(struct no_os_pwm_desc *desc, + uint32_t phase_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_set_phase) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_set_phase(desc, phase_ns); +} + +/** + * @brief Get the PWM phase value. + * @param desc - The PWM descriptor. + * @param phase_ns - Phase value in nanoseconds. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_get_phase(struct no_os_pwm_desc *desc, + uint32_t *phase_ns) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_get_phase) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_get_phase(desc, phase_ns); +} + +/** + * @brief Set the PWM polarity. + * @param desc - The PWM descriptor. + * @param polarity - Polarity value. + * Example: NO_OS_PWM_POLARITY_HIGH + * NO_OS_PWM_POLARITY_LOW + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_set_polarity(struct no_os_pwm_desc *desc, + enum no_os_pwm_polarity polarity) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_set_polarity) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_set_polarity(desc, polarity); +} + +/** + * @brief Get the PWM polarity. + * @param desc - The PWM descriptor. + * @param polarity - Polarity value. + * Example: NO_OS_PWM_POLARITY_HIGH + * NO_OS_PWM_POLARITY_LOW + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_pwm_get_polarity(struct no_os_pwm_desc *desc, + enum no_os_pwm_polarity *polarity) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->pwm_ops_get_polarity) + return -ENOSYS; + + return desc->platform_ops->pwm_ops_get_polarity(desc, polarity); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.h new file mode 100644 index 0000000..278d518 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_pwm.h @@ -0,0 +1,190 @@ +/***************************************************************************//** + * @file no_os_pwm.h + * @brief Header file of PWM Interface + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_PWM_H_ +#define _NO_OS_PWM_H_ + +#include +#include + +#define PWM_MAX_NUMBER 4 + +/** + * @enum no_os_pwm_polarity + * @brief Possible polarities of the PWM signal + */ +enum no_os_pwm_polarity { + /** PWM duty cycle is high, idle low */ + NO_OS_PWM_POLARITY_HIGH, + /** PWM duty cycle is low, idle high */ + NO_OS_PWM_POLARITY_LOW, +}; + +/** + * @struct no_os_pwm_init_param + * @brief Structure containing the init parameters needed by the PWM generator + */ +struct no_os_pwm_init_param { + /** Pwm id (Ex. Pin number, timer_id) */ + uint32_t id; + /** PWM generator period */ + uint32_t period_ns; + /** PWM generator duty cycle */ + uint32_t duty_cycle_ns; + /** PWM generator phase */ + uint32_t phase_ns; + /** PWM generator polarity */ + enum no_os_pwm_polarity polarity; + /** PWM gpio pin init param*/ + struct no_os_gpio_init_param *pwm_gpio; + /* IRQ ID */ + uint32_t irq_id; + /** PWM callback **/ + void (*pwm_callback)(void *arg); + /** PWM platform specific functions */ + const struct no_os_pwm_platform_ops *platform_ops; + /** PWM extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_pwm_desc + * @brief Structure representing an PWM generator device + */ +struct no_os_pwm_desc { + /** PWM mutex*/ + void *mutex; + /** Pwm id */ + uint32_t id; + /** PWM generator period */ + uint32_t period_ns; + /** PWM generator duty cycle */ + uint32_t duty_cycle_ns; + /** PWM generator phase */ + uint32_t phase_ns; + /** PWM generator polarity */ + enum no_os_pwm_polarity polarity; + /** PWM generator enabled */ + bool enabled; + /** PWM gpio pin instance */ + struct no_os_gpio_desc *pwm_gpio; + /* IRQ ID */ + uint32_t irq_id; + /** PWM callback **/ + void (*pwm_callback)(void* arg); + /** PWM platform specific functions */ + const struct no_os_pwm_platform_ops *platform_ops; + /** PWM extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_pwm_platform_ops + * @brief Structure holding PWM function pointers that point to the platform + * specific function + */ +struct no_os_pwm_platform_ops { + /** pwm initialization function pointer */ + int32_t (*pwm_ops_init)(struct no_os_pwm_desc **, + const struct no_os_pwm_init_param *); + /** pwm enable function pointer */ + int32_t (*pwm_ops_enable)(struct no_os_pwm_desc *); + /** pwm disable function pointer */ + int32_t (*pwm_ops_disable)(struct no_os_pwm_desc *); + /** pwm set period function pointer */ + int32_t (*pwm_ops_set_period)(struct no_os_pwm_desc *, uint32_t); + /** pwm get period function pointer */ + int32_t (*pwm_ops_get_period)(struct no_os_pwm_desc *, uint32_t *); + /** pwm set duty cycle function pointer */ + int32_t (*pwm_ops_set_duty_cycle)(struct no_os_pwm_desc *, uint32_t); + /** pwm get duty cycle function pointer */ + int32_t (*pwm_ops_get_duty_cycle)(struct no_os_pwm_desc *, uint32_t *); + /** pwm set phase function pointer */ + int32_t (*pwm_ops_set_phase)(struct no_os_pwm_desc *, uint32_t); + /** pwm get phase function pointer */ + int32_t (*pwm_ops_get_phase)(struct no_os_pwm_desc *, uint32_t *); + /** pwm set polarity function pointer */ + int32_t (*pwm_ops_set_polarity)(struct no_os_pwm_desc *, + enum no_os_pwm_polarity); + /** pwm get polarity function pointer */ + int32_t (*pwm_ops_get_polarity)(struct no_os_pwm_desc *, + enum no_os_pwm_polarity *); + /** pwm remove function pointer */ + int32_t(*pwm_ops_remove)(struct no_os_pwm_desc *); +}; + +/* Initialize the PWM generator device */ +int32_t no_os_pwm_init(struct no_os_pwm_desc **desc, + const struct no_os_pwm_init_param *param); + +/* Free the resources used by the PWM generator device */ +int32_t no_os_pwm_remove(struct no_os_pwm_desc *desc); + +/* Enable PWM generator device */ +int32_t no_os_pwm_enable(struct no_os_pwm_desc *desc); + +/* Disable PWM generator device */ +int32_t no_os_pwm_disable(struct no_os_pwm_desc *desc); + +/* Set period of PWM generator device */ +int32_t no_os_pwm_set_period(struct no_os_pwm_desc *desc, + uint32_t period_ns); + +/* Get period of PWM generator device */ +int32_t no_os_pwm_get_period(struct no_os_pwm_desc *desc, + uint32_t *period_ns); + +/* Set duty cycle of PWM generator device */ +int32_t no_os_pwm_set_duty_cycle(struct no_os_pwm_desc *desc, + uint32_t duty_cycle_ns); + +/* Get period of PWM generator device */ +int32_t no_os_pwm_get_duty_cycle(struct no_os_pwm_desc *desc, + uint32_t *duty_cycle_ns); + +/* Set the phase of PWM generator channel */ +int32_t no_os_pwm_set_phase(struct no_os_pwm_desc *desc, + uint32_t phase_ns); + +/* Get the phase of PWM generator channel */ +int32_t no_os_pwm_get_phase(struct no_os_pwm_desc *desc, + uint32_t *phase_ns); + +/* Set polarity of PWM generator device */ +int32_t no_os_pwm_set_polarity(struct no_os_pwm_desc *desc, + enum no_os_pwm_polarity polarity); + +/* Set polarity of PWM generator device */ +int32_t no_os_pwm_get_polarity(struct no_os_pwm_desc *desc, + enum no_os_pwm_polarity *polarity); + +#endif // _NO_OS_PWM_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_rtc.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_rtc.h new file mode 100644 index 0000000..5c7af0d --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_rtc.h @@ -0,0 +1,91 @@ +/***************************************************************************//** + * @file no_os_rtc.h + * @brief Header of the RTC interface + * @author Andrei Drimbarean (andrei.drimbarean@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_RTC_H_ +#define _NO_OS_RTC_H_ + +#include + +/** + * @struct no_os_rtc_desc + * @brief Structure holding RTC descriptor. + */ +struct no_os_rtc_desc { + /** ID of the real time clock core. */ + uint8_t id; + /** Frequency of the RTC */ + uint32_t freq; + /** Load value of the RTC */ + uint32_t load; + /** Device specific RTC parameters. */ + void *extra; +}; + +/** + * @struct no_os_rtc_init_param + * @brief Structure holding RTC initialization parameters. + */ +struct no_os_rtc_init_param { + /** ID of the real time clock core. */ + uint8_t id; + /** Frequency of the RTC */ + uint32_t freq; + /** Load value of the RTC */ + uint32_t load; + /** Device specific RTC parameters. */ + void *extra; +}; + +/** Initialize the RTC peripheral. */ +int32_t no_os_rtc_init(struct no_os_rtc_desc **device, + struct no_os_rtc_init_param *init_param); + +/** Free the resources allocated by no_os_rtc_init(). */ +int32_t no_os_rtc_remove(struct no_os_rtc_desc *dev); + +/** Start the real time clock. */ +int32_t no_os_rtc_start(struct no_os_rtc_desc *dev); + +/** Stop the real time clock. */ +int32_t no_os_rtc_stop(struct no_os_rtc_desc *dev); + +/** Get the current count for the real time clock. */ +int32_t no_os_rtc_get_cnt(struct no_os_rtc_desc *dev, uint32_t *tmr_cnt); + +/** Set the current count for the real time clock. */ +int32_t no_os_rtc_set_cnt(struct no_os_rtc_desc *dev, uint32_t tmr_cnt); + +/** Set the time at which an interrupt will occur */ +int32_t no_os_rtc_set_irq_time(struct no_os_rtc_desc *dev, uint32_t irq_time); + +#endif // _NO_OS_RTC_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.c new file mode 100644 index 0000000..b5c104a --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.c @@ -0,0 +1,63 @@ +/******************************************************************************* + * @file util/no_os_semaphore.c + * @brief Implementation of no-OS semaphore funtionality. + * @author Robert Budai (robert.budai@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include "no_os_semaphore.h" + +/** + * @brief Initialize semaphore. + * @param ptr - Pointer toward the semaphore. + * @return None. + */ +__attribute__((weak)) void no_os_semaphore_init(void **semaphore) {} + +/** + * @brief Take token from semaphore. + * @param ptr - Pointer toward the semaphore. + * @return None. + */ +__attribute__((weak)) void no_os_semaphore_take(void *semaphore) {} + +/** + * @brief Give token to semaphore + * @param ptr - Pointer toward the semaphore. + * @return None. + */ +__attribute((weak)) void no_os_semaphore_give(void *semaphore) {} + +/** + * @brief Remove semaphore. + * @param ptr - Pointer toward the semaphore. + * @return None. + */ +__attribute__((weak)) void no_os_semaphore_remove(void *semaphore) {} + diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.h new file mode 100644 index 0000000..e8f90d2 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_semaphore.h @@ -0,0 +1,48 @@ +/******************************************************************************* + * @file no_os_semaphore.h + * @brief Header file of semaphore implementation. + * @author Robert Budai (robert.budai@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_SEMAPHORE_H_ +#define _NO_OS_SEMAPHORE_H_ + +/* Initialize semaphore */ +void no_os_semaphore_init(void **semaphore); + +/* Take token from semaphore */ +void no_os_semaphore_take(void *semaphore); + +/* Give token to semaphore */ +void no_os_semaphore_give(void *semaphore); + +/* Remove semaphore */ +void no_os_semaphore_remove(void *semaphore); + +#endif // _NO_OS_SEMAPHORE_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_sin_lut.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_sin_lut.c new file mode 100644 index 0000000..0219bf2 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_sin_lut.c @@ -0,0 +1,68 @@ +#include + +const uint16_t no_os_sine_lut_16[512] = { + 0x8000, 0x8192, 0x8324, 0x84b6, 0x8647, 0x87d9, 0x896a, 0x8afb, + 0x8c8b, 0x8e1b, 0x8fab, 0x9139, 0x92c7, 0x9455, 0x95e1, 0x976d, + 0x98f8, 0x9a82, 0x9c0b, 0x9d93, 0x9f19, 0xa09f, 0xa223, 0xa3a6, + 0xa527, 0xa6a7, 0xa826, 0xa9a3, 0xab1f, 0xac98, 0xae10, 0xaf87, + 0xb0fb, 0xb26e, 0xb3de, 0xb54d, 0xb6b9, 0xb824, 0xb98c, 0xbaf2, + 0xbc56, 0xbdb7, 0xbf17, 0xc073, 0xc1cd, 0xc325, 0xc47a, 0xc5cc, + 0xc71c, 0xc869, 0xc9b3, 0xcafb, 0xcc3f, 0xcd81, 0xcebf, 0xcffb, + 0xd133, 0xd268, 0xd39a, 0xd4c9, 0xd5f5, 0xd71d, 0xd842, 0xd964, + 0xda82, 0xdb9c, 0xdcb3, 0xddc7, 0xded7, 0xdfe3, 0xe0eb, 0xe1f0, + 0xe2f1, 0xe3ee, 0xe4e8, 0xe5dd, 0xe6cf, 0xe7bc, 0xe8a6, 0xe98b, + 0xea6d, 0xeb4a, 0xec23, 0xecf8, 0xedc9, 0xee96, 0xef5e, 0xf022, + 0xf0e2, 0xf19d, 0xf254, 0xf307, 0xf3b5, 0xf45f, 0xf504, 0xf5a5, + 0xf641, 0xf6d8, 0xf76b, 0xf7fa, 0xf884, 0xf909, 0xf989, 0xfa05, + 0xfa7c, 0xfaee, 0xfb5c, 0xfbc5, 0xfc29, 0xfc88, 0xfce3, 0xfd39, + 0xfd89, 0xfdd5, 0xfe1d, 0xfe5f, 0xfe9c, 0xfed5, 0xff09, 0xff37, + 0xff61, 0xff86, 0xffa6, 0xffc1, 0xffd8, 0xffe9, 0xfff5, 0xfffd, + 0xffff, 0xfffd, 0xfff5, 0xffe9, 0xffd8, 0xffc1, 0xffa6, 0xff86, + 0xff61, 0xff37, 0xff09, 0xfed5, 0xfe9c, 0xfe5f, 0xfe1d, 0xfdd5, + 0xfd89, 0xfd39, 0xfce3, 0xfc88, 0xfc29, 0xfbc5, 0xfb5c, 0xfaee, + 0xfa7c, 0xfa05, 0xf989, 0xf909, 0xf884, 0xf7fa, 0xf76b, 0xf6d8, + 0xf641, 0xf5a5, 0xf504, 0xf45f, 0xf3b5, 0xf307, 0xf254, 0xf19d, + 0xf0e2, 0xf022, 0xef5e, 0xee96, 0xedc9, 0xecf8, 0xec23, 0xeb4a, + 0xea6d, 0xe98b, 0xe8a6, 0xe7bc, 0xe6cf, 0xe5dd, 0xe4e8, 0xe3ee, + 0xe2f1, 0xe1f0, 0xe0eb, 0xdfe3, 0xded7, 0xddc7, 0xdcb3, 0xdb9c, + 0xda82, 0xd964, 0xd842, 0xd71d, 0xd5f5, 0xd4c9, 0xd39a, 0xd268, + 0xd133, 0xcffb, 0xcebf, 0xcd81, 0xcc3f, 0xcafb, 0xc9b3, 0xc869, + 0xc71c, 0xc5cc, 0xc47a, 0xc325, 0xc1cd, 0xc073, 0xbf17, 0xbdb7, + 0xbc56, 0xbaf2, 0xb98c, 0xb824, 0xb6b9, 0xb54d, 0xb3de, 0xb26e, + 0xb0fb, 0xaf87, 0xae10, 0xac98, 0xab1f, 0xa9a3, 0xa826, 0xa6a7, + 0xa527, 0xa3a6, 0xa223, 0xa09f, 0x9f19, 0x9d93, 0x9c0b, 0x9a82, + 0x98f8, 0x976d, 0x95e1, 0x9455, 0x92c7, 0x9139, 0x8fab, 0x8e1b, + 0x8c8b, 0x8afb, 0x896a, 0x87d9, 0x8647, 0x84b6, 0x8324, 0x8192, + 0x8000, 0x7e6d, 0x7cdb, 0x7b49, 0x79b8, 0x7826, 0x7695, 0x7504, + 0x7374, 0x71e4, 0x7054, 0x6ec6, 0x6d38, 0x6baa, 0x6a1e, 0x6892, + 0x6707, 0x657d, 0x63f4, 0x626c, 0x60e6, 0x5f60, 0x5ddc, 0x5c59, + 0x5ad8, 0x5958, 0x57d9, 0x565c, 0x54e0, 0x5367, 0x51ef, 0x5078, + 0x4f04, 0x4d91, 0x4c21, 0x4ab2, 0x4946, 0x47db, 0x4673, 0x450d, + 0x43a9, 0x4248, 0x40e8, 0x3f8c, 0x3e32, 0x3cda, 0x3b85, 0x3a33, + 0x38e3, 0x3796, 0x364c, 0x3504, 0x33c0, 0x327e, 0x3140, 0x3004, + 0x2ecc, 0x2d97, 0x2c65, 0x2b36, 0x2a0a, 0x28e2, 0x27bd, 0x269b, + 0x257d, 0x2463, 0x234c, 0x2238, 0x2128, 0x201c, 0x1f14, 0x1e0f, + 0x1d0e, 0x1c11, 0x1b17, 0x1a22, 0x1930, 0x1843, 0x1759, 0x1674, + 0x1592, 0x14b5, 0x13dc, 0x1307, 0x1236, 0x1169, 0x10a1, 0xfdd, + 0xf1d, 0xe62, 0xdab, 0xcf8, 0xc4a, 0xba0, 0xafb, 0xa5a, + 0x9be, 0x927, 0x894, 0x805, 0x77b, 0x6f6, 0x676, 0x5fa, + 0x583, 0x511, 0x4a3, 0x43a, 0x3d6, 0x377, 0x31c, 0x2c6, + 0x276, 0x22a, 0x1e2, 0x1a0, 0x163, 0x12a, 0xf6, 0xc8, + 0x9e, 0x79, 0x59, 0x3e, 0x27, 0x16, 0xa, 0x2, + 0x0, 0x2, 0xa, 0x16, 0x27, 0x3e, 0x59, 0x79, + 0x9e, 0xc8, 0xf6, 0x12a, 0x163, 0x1a0, 0x1e2, 0x22a, + 0x276, 0x2c6, 0x31c, 0x377, 0x3d6, 0x43a, 0x4a3, 0x511, + 0x583, 0x5fa, 0x676, 0x6f6, 0x77b, 0x805, 0x894, 0x927, + 0x9be, 0xa5a, 0xafb, 0xba0, 0xc4a, 0xcf8, 0xdab, 0xe62, + 0xf1d, 0xfdd, 0x10a1, 0x1169, 0x1236, 0x1307, 0x13dc, 0x14b5, + 0x1592, 0x1674, 0x1759, 0x1843, 0x1930, 0x1a22, 0x1b17, 0x1c11, + 0x1d0e, 0x1e0f, 0x1f14, 0x201c, 0x2128, 0x2238, 0x234c, 0x2463, + 0x257d, 0x269b, 0x27bd, 0x28e2, 0x2a0a, 0x2b36, 0x2c65, 0x2d97, + 0x2ecc, 0x3004, 0x3140, 0x327e, 0x33c0, 0x3504, 0x364c, 0x3796, + 0x38e3, 0x3a33, 0x3b85, 0x3cda, 0x3e32, 0x3f8c, 0x40e8, 0x4248, + 0x43a9, 0x450d, 0x4673, 0x47db, 0x4946, 0x4ab2, 0x4c21, 0x4d91, + 0x4f04, 0x5078, 0x51ef, 0x5367, 0x54e0, 0x565c, 0x57d9, 0x5958, + 0x5ad8, 0x5c59, 0x5ddc, 0x5f60, 0x60e6, 0x626c, 0x63f4, 0x657d, + 0x6707, 0x6892, 0x6a1e, 0x6baa, 0x6d38, 0x6ec6, 0x7054, 0x71e4, + 0x7374, 0x7504, 0x7695, 0x7826, 0x79b8, 0x7b49, 0x7cdb, 0x7e6d, +}; diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.c new file mode 100644 index 0000000..f752e01 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.c @@ -0,0 +1,278 @@ +/***************************************************************************//** + * @file no_os_spi.c + * @brief Implementation of the SPI Interface + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_spi.h" +#include +#include "no_os_error.h" +#include "no_os_mutex.h" +#include "no_os_alloc.h" + +/** + * @brief spi_table contains the pointers towards the SPI buses +*/ +static void *spi_table[SPI_MAX_BUS_NUMBER + 1]; + +/** + * @brief Initialize the SPI communication peripheral. + * @param desc - The SPI descriptor. + * @param param - The structure that contains the SPI parameters. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_spi_init(struct no_os_spi_desc **desc, + const struct no_os_spi_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + if (param->device_id > SPI_MAX_BUS_NUMBER) + return -EINVAL; + // Initializing BUS descriptor + if (!spi_table[param->device_id]) { + ret = no_os_spibus_init(param); + if (ret) + return ret; + } + // Initilize SPI descriptor + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + (*desc)->bus = spi_table[param->device_id]; + (*desc)->bus->slave_number++; + (*desc)->platform_ops = param->platform_ops; + (*desc)->parent = param->parent; + (*desc)->platform_delays = param->platform_delays; + + return 0; +} + +/** + * @brief Initialize the SPI bus communication peripheral. + * @param param - The structure that containes the SPI bus parameters + * @return 0 in case of success, error code otherwise +*/ +int32_t no_os_spibus_init(const struct no_os_spi_init_param *param) +{ + struct no_os_spibus_desc *bus = (struct no_os_spibus_desc *)no_os_calloc(1, + sizeof(struct no_os_spibus_desc)); + + if (!bus) + return -ENOMEM; + + no_os_mutex_init(&(bus->mutex)); + + bus->slave_number = 0; + bus->device_id = param->device_id; + bus->max_speed_hz = param->max_speed_hz; + bus->mode = param->mode; + bus->bit_order = param->bit_order; + bus->platform_ops = param->platform_ops; + bus->extra = param->extra; + + spi_table[param->device_id] = bus; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_spi_init(). + * @param desc - The SPI descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_spi_remove(struct no_os_spi_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (desc->bus) + no_os_spibus_remove(desc->bus->device_id); + + if (!desc->platform_ops->remove) + return -ENOSYS; + return desc->platform_ops->remove(desc); +} + +/** + * @brief Removes SPI bus instance + * @param bus_number - SPI bus number +*/ +void no_os_spibus_remove(uint32_t bus_number) +{ + struct no_os_spibus_desc *bus = (struct no_os_spibus_desc *) + spi_table[bus_number]; + + if (bus->slave_number > 0) + bus->slave_number--; + + if (bus->slave_number == 0) { + no_os_mutex_remove(bus->mutex); + + if (bus) { + no_os_free(bus); + bus = NULL; + spi_table[bus_number] = NULL; + } + } +} + +/** + * @brief Write and read data to/from SPI. + * @param desc - The SPI descriptor. + * @param data - The buffer with the transmitted/received data. + * @param bytes_number - Number of bytes to write/read. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_spi_write_and_read(struct no_os_spi_desc *desc, + uint8_t *data, + uint16_t bytes_number) +{ + int32_t ret; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->write_and_read) + return -ENOSYS; + + no_os_mutex_lock(desc->bus->mutex); + ret = desc->platform_ops->write_and_read(desc, data, bytes_number); + no_os_mutex_unlock(desc->bus->mutex); + + return ret; +} + +/** + * @brief Iterate over head list and send all spi messages + * @param desc - The SPI descriptor. + * @param msgs - Array of messages. + * @param len - Number of messages in the array. + * @return 0 in case of success, negativ error code otherwise. + */ +int32_t no_os_spi_transfer(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len) +{ + int32_t ret = 0; + uint32_t i; + + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (desc->platform_ops->transfer) + return desc->platform_ops->transfer(desc, msgs, len); + + no_os_mutex_lock(desc->bus->mutex); + + for (i = 0; i < len; i++) { + if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff) { + ret = -EINVAL; + goto out; + } + ret = no_os_spi_write_and_read(desc, msgs[i].rx_buff, + msgs[i].bytes_number); + if (NO_OS_IS_ERR_VALUE(ret)) { + goto out; + } + } + +out: + no_os_mutex_unlock(desc->bus->mutex); + return ret; +} + +/** + * @brief Transfer a list of messages using DMA and busy wait for the completion + * @param desc - The SPI descriptor. + * @param msgs - Array of messages. + * @param len - Number of messages in the array. + * @return 0 in case of success, negativ error code otherwise. + */ +int32_t no_os_spi_transfer_dma(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len) +{ + if (!desc || !desc->platform_ops || !msgs || !len) + return -EINVAL; + + if (desc->platform_ops->transfer_dma) + return desc->platform_ops->transfer_dma(desc, msgs, len); + + return -ENOSYS; +} + +/** + * @brief Transfer a list of messages using DMA. The function will return after the + * first transfer is started. Once all the transfers are complete, a callback + * will be called. + * @param desc - The SPI descriptor. + * @param msgs - Array of messages. + * @param len - Number of messages in the array. + * @param callback - A function which will be called after all the transfers are done. + * @param ctx - User specific data which should be passed to the callback function. + * @return 0 in case of success, negativ error code otherwise. + */ +int32_t no_os_spi_transfer_dma_async(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len, + void (*callback)(void *), + void *ctx) +{ + if (!desc || !desc->platform_ops || !msgs || !len) + return -EINVAL; + + if (desc->platform_ops->transfer_dma_async) + return desc->platform_ops->transfer_dma_async(desc, msgs, len, + callback, ctx); + + return -ENOSYS; +} + +/** + * @brief Abort SPI transfers. + * @param desc - The SPI descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int32_t no_os_spi_transfer_abort(struct no_os_spi_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->transfer_abort) + return -ENOSYS; + + return desc->platform_ops->transfer_abort(desc); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.h new file mode 100644 index 0000000..9aa77cc --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_spi.h @@ -0,0 +1,275 @@ +/***************************************************************************//** + * @file no_os_spi.h + * @brief Header file of SPI Interface + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_SPI_H_ +#define _NO_OS_SPI_H_ + +#include + +#define NO_OS_SPI_CPHA 0x01 +#define NO_OS_SPI_CPOL 0x02 +#define SPI_MAX_BUS_NUMBER 8 + +/** + * @enum no_os_spi_mode + * @brief SPI configuration for clock phase and polarity. + */ +enum no_os_spi_mode { + /** Data on rising, shift out on falling */ + NO_OS_SPI_MODE_0 = (0 | 0), + /** Data on falling, shift out on rising */ + NO_OS_SPI_MODE_1 = (0 | NO_OS_SPI_CPHA), + /** Data on rising, shift out on falling */ + NO_OS_SPI_MODE_2 = (NO_OS_SPI_CPOL | 0), + /** Data on falling, shift out on rising */ + NO_OS_SPI_MODE_3 = (NO_OS_SPI_CPOL | NO_OS_SPI_CPHA) +}; + +/** + * @enum no_os_spi_bit_order + * @brief SPI configuration for bit order (MSB/LSB). + */ +enum no_os_spi_bit_order { + /** Most-significant bit (MSB) first */ + NO_OS_SPI_BIT_ORDER_MSB_FIRST = 0, + /** Least-significant bit (LSB) first */ + NO_OS_SPI_BIT_ORDER_LSB_FIRST = 1, +}; + +/** + * @enum no_os_spi_lanes + * @brief SPI configuration for number of lanes. + */ +enum no_os_spi_lanes { + /** Single Lane */ + NO_OS_SPI_SINGLE_LANE, + /** Dual Lane */ + NO_OS_SPI_DUAL_LANE, + /** Quad Lane */ + NO_OS_SPI_QUAD_LANE, + /** Octo Lane */ + NO_OS_SPI_OCTO_LANE, +}; + +/** + * @struct no_os_spi_msg_list + * @brief List item describing a SPI transfer + */ +struct no_os_spi_msg { + /** Buffer with data to send. If NULL, 0x00 will be sent */ + uint8_t *tx_buff; + /** Buffer where to store data. If NULL, incoming data won't be saved */ + uint8_t *rx_buff; + /** Length of buffers. Must have equal size. */ + uint32_t bytes_number; + /** If set, CS will be deasserted after the transfer */ + uint8_t cs_change; + /** + * Minimum delay (in us) between the CS de-assert event of the current message + * and the assert of the next one. + */ + uint32_t cs_change_delay; + /** Delay (in us) between the CS assert and the first SCLK edge. */ + uint32_t cs_delay_first; + /** Delay (in us) between the last SCLK edge and the CS deassert */ + uint32_t cs_delay_last; +}; + +/** + * @struct no_os_platform_spi_delays + * @brief Delays resulted from components in the SPI signal path. The values is ns. + */ +struct no_os_platform_spi_delays { + uint32_t cs_delay_first; + uint32_t cs_delay_last; +}; + +/** + * @struct no_os_spi_platform_ops + * @brief Structure holding SPI function pointers that point to the platform + * specific function + */ +struct no_os_spi_platform_ops ; + +/** + * @struct no_os_spi_init_param + * @brief Structure holding the parameters for SPI initialization + */ +struct no_os_spi_init_param { + /** Device ID */ + uint32_t device_id; + /** maximum transfer speed */ + uint32_t max_speed_hz; + /** SPI chip select */ + uint8_t chip_select; + /** SPI mode */ + enum no_os_spi_mode mode; + /** SPI bit order */ + enum no_os_spi_bit_order bit_order; + /** SPI Lanes */ + enum no_os_spi_lanes lanes; + /** SPI bus platform ops */ + const struct no_os_spi_platform_ops *platform_ops; + /** SPI delays */ + struct no_os_platform_spi_delays platform_delays; + /** SPI extra parameters (device specific) */ + void *extra; + /** Parent of the device */ + struct no_os_spi_desc *parent; +}; + +/** + * @struct no_os_spibus_desc + * @brief SPI bus descriptor +*/ +struct no_os_spibus_desc { + /** SPI bus mutex (lock) */ + void *mutex; + /** SPI bus slave number*/ + uint8_t slave_number; + /** SPI bus device id */ + uint32_t device_id; + /** SPI bus max speed */ + uint32_t max_speed_hz; + /** SPI bus mode */ + enum no_os_spi_mode mode; + /** SPI bus bit order */ + enum no_os_spi_bit_order bit_order; + /** SPI Lanes */ + enum no_os_spi_lanes lanes; + /** SPI bus platform ops */ + const struct no_os_spi_platform_ops *platform_ops; + /** SPI bus extra */ + void *extra; +}; + +/** + * @struct no_os_spi_desc + * @brief Structure holding SPI descriptor. + */ +struct no_os_spi_desc { + /** SPI bus address */ + struct no_os_spibus_desc *bus; + /** SPI bus number (0 for SPI0, 1 for SPI1, ...) */ + uint32_t device_id; + /** maximum transfer speed */ + uint32_t max_speed_hz; + /** SPI chip select */ + uint8_t chip_select; + /** SPI mode */ + enum no_os_spi_mode mode; + /** SPI bit order */ + enum no_os_spi_bit_order bit_order; + /** SPI Lanes */ + enum no_os_spi_lanes lanes; + /** SPI bus platform ops */ + const struct no_os_spi_platform_ops *platform_ops; + /** SPI delays */ + struct no_os_platform_spi_delays platform_delays; + /** SPI extra parameters (device specific) */ + void *extra; + /** Parent of the device */ + struct no_os_spi_desc *parent; +}; + +/** + * @struct no_os_spi_platform_ops + * @brief Structure holding SPI function pointers that point to the platform + * specific function + */ +struct no_os_spi_platform_ops { + /** SPI initialization function pointer */ + int32_t (*init)(struct no_os_spi_desc **, const struct no_os_spi_init_param *); + /** SPI write/read function pointer */ + int32_t (*write_and_read)(struct no_os_spi_desc *, uint8_t *, uint16_t); + /** Iterate over the spi_msg array and send all messages at once */ + int32_t (*transfer)(struct no_os_spi_desc *, struct no_os_spi_msg *, uint32_t); + /** Iterate over the spi_msg array and send all messages using DMA. + * Blocks until the transfer is completed. + */ + int32_t (*transfer_dma)(struct no_os_spi_desc *, struct no_os_spi_msg *, + uint32_t); + /** Iterate over the spi_msg array and send all messages using DMA. + * Returns immediately after the transfer is started and invokes a + * callback once all the messages have been transfered. + */ + int32_t (*transfer_dma_async)(struct no_os_spi_desc *, struct no_os_spi_msg *, + uint32_t, void (*)(void *), void *); + /** SPI remove function pointer */ + int32_t (*remove)(struct no_os_spi_desc *); + /** SPI abort function pointer */ + int32_t (*transfer_abort)(struct no_os_spi_desc *); +}; + +/* Initialize the SPI communication peripheral. */ +int32_t no_os_spi_init(struct no_os_spi_desc **desc, + const struct no_os_spi_init_param *param); + +/* Free the resources allocated by no_os_spi_init(). */ +int32_t no_os_spi_remove(struct no_os_spi_desc *desc); + +/* Write and read data to/from SPI. */ +int32_t no_os_spi_write_and_read(struct no_os_spi_desc *desc, + uint8_t *data, + uint16_t bytes_number); + +/* Iterate over the spi_msg array and send all messages at once */ +int32_t no_os_spi_transfer(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len); + +/* Transfer a list of messages using DMA. Wait until all transfers are done */ +int32_t no_os_spi_transfer_dma(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len); +/* + * Transfer a list of messages using DMA. Return once the first one started and + * invoke a callback when they are done. + */ +int32_t no_os_spi_transfer_dma_async(struct no_os_spi_desc *desc, + struct no_os_spi_msg *msgs, + uint32_t len, + void (*callback)(void *), + void *ctx); + +/* Abort SPI transfers. */ +int32_t no_os_spi_transfer_abort(struct no_os_spi_desc *desc); + +/* Initialize SPI bus descriptor*/ +int32_t no_os_spibus_init(const struct no_os_spi_init_param *param); + +/* Free the resources allocated for SPI bus desc*/ +void no_os_spibus_remove(uint32_t bus_number); + + +#endif // _NO_OS_SPI_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.c new file mode 100644 index 0000000..e2bcf16 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.c @@ -0,0 +1,125 @@ +/***************************************************************************//** + * @file no_os_tdm.c + * @brief Implementation of the TDM interface + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_tdm.h" +#include +#include "no_os_error.h" + +/** + * @brief Initialize the TDM communication peripheral. + * @param desc - The TDM descriptor. + * @param param - The structure that contains the TDM parameters. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_init(struct no_os_tdm_desc **desc, + const struct no_os_tdm_init_param *param) +{ + if (!param) + return -1; + + if ((param->platform_ops->tdm_ops_init(desc, param))) + return -1; + + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_tdm_init(). + * @param desc - The TDM descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_remove(struct no_os_tdm_desc *desc) +{ + return desc->platform_ops->tdm_ops_remove(desc); +} + +/** + * @brief Read data using the TDM interface + * @param desc - The TDM descriptor. + * @param data - The buffer to store the received data. + * @param nb_samples - Number of samples to read. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_read(struct no_os_tdm_desc *desc, + void *data, + uint16_t nb_samples) +{ + return desc->platform_ops->tdm_ops_read(desc, data, nb_samples); +} + +/** + * @brief Pause TDM DMA transfer + * @param desc - The TDM descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_pause(struct no_os_tdm_desc *desc) +{ + return desc->platform_ops->tdm_ops_pause(desc); +} + +/** + * @brief Resume TDM DMA transfer + * @param desc - The TDM descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_resume(struct no_os_tdm_desc *desc) +{ + return desc->platform_ops->tdm_ops_resume(desc); +} + +/** + * @brief Stop TDM DMA transfer + * @param desc - The TDM descriptor. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_stop(struct no_os_tdm_desc *desc) +{ + return desc->platform_ops->tdm_ops_stop(desc); +} + +/** + * @brief Write data using the TDM interface + * @param desc - The TDM descriptor. + * @param data - The buffer with the data to be transmitted. + * @param nb_samples - Number of samples to write. + * @return 0 in case of success, negative error code otherwise. + */ +int32_t no_os_tdm_write(struct no_os_tdm_desc *desc, + void *data, + uint16_t nb_samples) +{ + return desc->platform_ops->tdm_ops_write(desc, data, nb_samples); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.h new file mode 100644 index 0000000..64fd5f7 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_tdm.h @@ -0,0 +1,152 @@ +/***************************************************************************//** + * @file no_os_tdm.h + * @brief Header file of TDM Interface + * @author Darius Berghe (darius.berghe@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_TDM_H_ +#define _NO_OS_TDM_H_ + +#include +#include + +/** + * @struct no_os_tdm_platform_ops + * @brief Structure holding TDM function pointers that point to the platform + * specific function + */ +struct no_os_tdm_platform_ops; + +enum no_os_tdm_mode { + NO_OS_TDM_MASTER_TX, + NO_OS_TDM_MASTER_RX, + NO_OS_TDM_SLAVE_TX, + NO_OS_TDM_SLAVE_RX +}; + +/** + * @struct no_os_tdm_init_param + * @brief Structure holding the parameters for TDM initialization + */ +struct no_os_tdm_init_param { + /** TDM operating mode: master/slave, tx/rx */ + enum no_os_tdm_mode mode; + /** Useful data size in a slot, specified in number of bits */ + uint8_t data_size; + /** Data offset in a slot, specified in number of bits as offset from MSbit */ + uint8_t data_offset; + /** Data ordering (default: msb first) */ + bool data_lsb_first; + /** Number of slots in a frame */ + uint8_t slots_per_frame; + /** Frame sync polarity specifier (default: FS active high) */ + bool fs_active_low; + /** Frame sync active length specified in number of bits */ + uint8_t fs_active_length; + /** Frame sync is normally asserted on first bit of slot 0 of a frame, this specifier allows assertion on last bit of the previous frame */ + bool fs_lastbit; + /** Specify whether data sampling occurs on SCK rising edge (default: on SCK falling edge) */ + bool rising_edge_sampling; + /* IRQ ID */ + uint32_t irq_id; + /** DMA receive complete callback **/ + void (*rx_complete_callback)(void *rx_arg); + /** DMA receive Half complete callback **/ + void (*rx_half_complete_callback)(void *rx_arg); + /** Platform operation function pointers */ + const struct no_os_tdm_platform_ops *platform_ops; + /** TDM extra parameters (platform specific) */ + void *extra; +}; + +/** + * @struct no_os_tdm_desc + * @brief Structure holding TDM descriptor. + */ +struct no_os_tdm_desc { + /* IRQ ID */ + uint32_t irq_id; + /** Platform operation function pointers */ + const struct no_os_tdm_platform_ops *platform_ops; + /** Software FIFO. */ + struct lf256fifo *rx_fifo; + /** TDM extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_tdm_platform_ops + * @brief Structure holding TDM function pointers that point to the platform + * specific function. + */ +struct no_os_tdm_platform_ops { + /** TDM initialization operation function pointer */ + int32_t (*tdm_ops_init)(struct no_os_tdm_desc **, + const struct no_os_tdm_init_param *); + /** TDM read operation function pointer */ + int32_t (*tdm_ops_read)(struct no_os_tdm_desc *, void *, uint16_t); + /** TDM write operation function pointer */ + int32_t (*tdm_ops_write)(struct no_os_tdm_desc *, void *, uint16_t); + /** Pause TDM DMA transfer */ + int32_t (*tdm_ops_pause)(struct no_os_tdm_desc *); + /** Resume TDM DMA transfer */ + int32_t (*tdm_ops_resume)(struct no_os_tdm_desc *); + /** Stop TDM DMA transfer */ + int32_t (*tdm_ops_stop)(struct no_os_tdm_desc *); + /** TDM remove operation function pointer */ + int32_t (*tdm_ops_remove)(struct no_os_tdm_desc *); +}; + +/* Initialize the TDM communication peripheral. */ +int32_t no_os_tdm_init(struct no_os_tdm_desc **desc, + const struct no_os_tdm_init_param *param); + +/* Free the resources allocated by no_os_tdm_init(). */ +int32_t no_os_tdm_remove(struct no_os_tdm_desc *desc); + +/* Read data. */ +int32_t no_os_tdm_read(struct no_os_tdm_desc *desc, + void *data, + uint16_t bytes_number); + +/* Write data. */ +int32_t no_os_tdm_write(struct no_os_tdm_desc *desc, + void *data, + uint16_t bytes_number); + +/* Pause TDM DMA Transfer */ +int32_t no_os_tdm_pause(struct no_os_tdm_desc *desc); + +/* Resume TDM DMA Transfer */ +int32_t no_os_tdm_resume(struct no_os_tdm_desc *desc); + +/* Stop TDM DMA Transfer */ +int32_t no_os_tdm_stop(struct no_os_tdm_desc *desc); + +#endif // _NO_OS_TDM_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.c new file mode 100644 index 0000000..d10870f --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.c @@ -0,0 +1,213 @@ +/***************************************************************************//** +* @file no_os_timer.c +* @brief Implementation of the timer Interface +* @author RBolboac (ramona.bolboaca@analog.com) +******************************************************************************** +* Copyright 2022(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_error.h" +#include "no_os_timer.h" +#include "no_os_mutex.h" + +/** + * @brief - TIMER mutex +*/ +static void *timer_mutex_table[TIMER_MAX_TABLE + 1]; + +/** + * @brief Initialize hardware timer and the handler structure associated with + * it. + * @param [out] desc - Pointer to the reference of the device handler. + * @param [in] param - Initialization structure. + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_timer_init(struct no_os_timer_desc **desc, + const struct no_os_timer_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + no_os_mutex_init(&timer_mutex_table[param->id]); + (*desc)->mutex = timer_mutex_table[param->id]; + + return 0; +} + +/** + * @brief Free the memory allocated by timer_init(). + * @param [in] desc - Pointer to the device handler. + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_timer_remove(struct no_os_timer_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->remove) + return -ENOSYS; + + no_os_mutex_remove(desc->mutex); + timer_mutex_table[desc->id] = NULL; + + return desc->platform_ops->remove(desc); +} + +/** + * @brief Start a timer. + * @param [in] desc - Pointer to the device handler. + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_timer_start(struct no_os_timer_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->start) + return -ENOSYS; + + return desc->platform_ops->start(desc); +} + +/** + * @brief Stop a timer from counting. + * @param [in] desc - Pointer to the device handler. + * @return 0 in case of success, negative error code otherwise + */ +int32_t no_os_timer_stop(struct no_os_timer_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->stop) + return -ENOSYS; + + no_os_mutex_unlock(desc->mutex); + return desc->platform_ops->stop(desc); +} + +/** + * @brief Get the value of the counter register for the timer. + * @param [in] desc - Pointer to the device handler. + * @param [out] counter - Pointer to the counter value. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_timer_counter_get(struct no_os_timer_desc *desc, + uint32_t *counter) +{ + if (!desc || !desc->platform_ops || !counter) + return -EINVAL; + + if (!desc->platform_ops->counter_get) + return -ENOSYS; + + return desc->platform_ops->counter_get(desc, counter); +} + +/** + * @brief Set the timer counter register value. + * @param [in] desc - Pointer to the device handler. + * @param [in] new_val - The new value of the counter register. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_timer_counter_set(struct no_os_timer_desc *desc, uint32_t new_val) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->counter_set) + return -ENOSYS; + + return desc->platform_ops->counter_set(desc, new_val); +} + +/** + * @brief Get the timer clock frequency. + * @param [in] desc - Pointer to the device handler. + * @param [out] freq_hz - The value in Hz of the timer clock. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_timer_count_clk_get(struct no_os_timer_desc *desc, + uint32_t *freq_hz) +{ + if (!desc || !desc->platform_ops || !freq_hz) + return -EINVAL; + + if (!desc->platform_ops->count_clk_get) + return -ENOSYS; + + return desc->platform_ops->count_clk_get(desc, freq_hz); +} + +/** + * @brief Set the timer clock frequency. + * @param [in] desc - Pointer to the device handler. + * @param [in] freq_hz - The value in Hz of the new timer clock. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_timer_count_clk_set(struct no_os_timer_desc *desc, + uint32_t freq_hz) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->count_clk_set) + return -ENOSYS; + + return desc->platform_ops->count_clk_set(desc, freq_hz); +} + +/** + * @brief Get the elapsed time in nsec for the timer. + * @param [in] desc - Pointer to the device handler. + * @param [in] elapsed_time - The elapsed time in nsec. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_timer_get_elapsed_time_nsec(struct no_os_timer_desc *desc, + uint64_t *elapsed_time) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->get_elapsed_time_nsec) + return -ENOSYS; + + return desc->platform_ops->get_elapsed_time_nsec(desc, elapsed_time); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.h new file mode 100644 index 0000000..3c8b565 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_timer.h @@ -0,0 +1,145 @@ +/***************************************************************************//** +* @file no_os_timer.h +* @brief Timer control module header. +* @author Andrei Drimbarean (andrei.drimbarean@analog.com) +******************************************************************************** +* Copyright 2019(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_SRC_TIMER_H_ +#define _NO_OS_SRC_TIMER_H_ + +#include + +#define TIMER_MAX_TABLE 4 + +/** + * @struct no_os_timer_desc + * @brief Structure holding timer descriptor + */ +struct no_os_timer_desc { + /** Timer mutex*/ + void *mutex; + /** timer ID */ + uint16_t id; + /** timer count frequency (Hz) */ + uint32_t freq_hz; + /** the number of ticks the timer counts until it resets */ + uint32_t ticks_count; + /** Timer platform operations */ + const struct no_os_timer_platform_ops *platform_ops; + /** timer extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_timer_platform_ops + * @brief Structure holding timer function pointers that point to the platform + * specific function + */ +struct no_os_timer_platform_ops ; + +/** + * @struct no_os_timer_init_param + * @brief Structure holding the parameters for timer initialization + */ +struct no_os_timer_init_param { + /** timer ID */ + uint16_t id; + /** timer count frequency (Hz) */ + uint32_t freq_hz; + /** the number of ticks the timer counts until it resets */ + uint32_t ticks_count; + /** Timer platform operations */ + const struct no_os_timer_platform_ops *platform_ops; + /** timer extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_timer_platform_ops + * @brief Structure holding timer function pointers that point to the platform + * specific function + */ +struct no_os_timer_platform_ops { + /** timer initialization function pointer */ + int32_t (*init)(struct no_os_timer_desc **, + const struct no_os_timer_init_param *); + /** timer start function pointer */ + int32_t (*start)(struct no_os_timer_desc *); + /** timer stop function pointer */ + int32_t (*stop)(struct no_os_timer_desc *); + /** timer get counter function pointer */ + int32_t (*counter_get)(struct no_os_timer_desc *, uint32_t *counter); + /** timer set counter function pointer */ + int32_t (*counter_set)(struct no_os_timer_desc *, uint32_t new_val); + /** timer get clock frequency function pointer */ + int32_t (*count_clk_get)(struct no_os_timer_desc *, uint32_t *freq_hz); + /** timer set clock frequency function pointer */ + int32_t (*count_clk_set)(struct no_os_timer_desc *, uint32_t freq_hz); + /** timer get elapsed time in nsec */ + int32_t (*get_elapsed_time_nsec)(struct no_os_timer_desc *, + uint64_t *elapsed_time); + /** timer remove function pointer */ + int32_t (*remove)(struct no_os_timer_desc *); +}; + +/* Initialize hardware timer and the handler structure associated with it. */ +int32_t no_os_timer_init(struct no_os_timer_desc **desc, + const struct no_os_timer_init_param *param); + +/* Free the memory allocated by timer_setup(). */ +int32_t no_os_timer_remove(struct no_os_timer_desc *desc); + +/* Start a timer. */ +int32_t no_os_timer_start(struct no_os_timer_desc *desc); + +/* Stop a timer from counting. */ +int32_t no_os_timer_stop(struct no_os_timer_desc *desc); + +/* Get the value of the counter register for the timer. */ +int32_t no_os_timer_counter_get(struct no_os_timer_desc *desc, + uint32_t *counter); + +/* Set the timer counter register value. */ +int32_t no_os_timer_counter_set(struct no_os_timer_desc *desc, + uint32_t new_val); + +/* Get the timer clock frequency. */ +int32_t no_os_timer_count_clk_get(struct no_os_timer_desc *desc, + uint32_t *freq_hz); + +/* Set the timer clock frequency. */ +int32_t no_os_timer_count_clk_set(struct no_os_timer_desc *desc, + uint32_t freq_hz); + +/* Get the elapsed time in nsec for the timer. */ +int32_t no_os_timer_get_elapsed_time_nsec(struct no_os_timer_desc *desc, + uint64_t *elapsed_time); + +#endif // _NO_OS_SRC_TIMER_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.c new file mode 100644 index 0000000..a849c7a --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.c @@ -0,0 +1,98 @@ +/***************************************************************************//** + * @file no_os_trng.c + * @brief Implementation of the TRNG Interface + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2023(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_trng.h" +#include +#include "no_os_error.h" + +/** + * @brief Initialize the TRNG. + * @param desc - The TRNG descriptor. + * @param param - The structure that contains the TRNG parameters. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_trng_init(struct no_os_trng_desc **desc, + const struct no_os_trng_init_param *param) +{ + int ret; + + if (!param || !param->platform_ops) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_trng_init(). + * @param desc - The TRNG descriptor. + * @return 0 in case of success, -1 otherwise. + */ +int no_os_trng_remove(struct no_os_trng_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->remove) + return -ENOSYS; + + return desc->platform_ops->remove(desc); +} + +/** + * @brief Fill buffer with rng data. + * @param desc - The TRNG descriptor. + * @param buff - Buffer to be filled + * @param len - Size of the buffer + * @return 0 in case of success, -1 otherwise. + */ +int no_os_trng_fill_buffer(struct no_os_trng_desc *desc, uint8_t *buff, + uint32_t len) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->fill_buffer) + return -ENOSYS; + + return desc->platform_ops->fill_buffer(desc, buff, len); +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.h new file mode 100644 index 0000000..22fec6b --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_trng.h @@ -0,0 +1,97 @@ +/***************************************************************************//** + * @file no_os_trng.h + * @brief Header file of true random number generator + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef _NO_OS_TRNG_H_ +#define _NO_OS_TRNG_H_ + +#include + +/** + * @struct no_os_trng_platform_ops + * @brief Structure holding TRNG function pointers that point to the platform + * specific function + */ +struct no_os_trng_platform_ops; + +/** + * @struct no_os_trng_desc + * @brief TRNG Descriptor + */ +struct no_os_trng_desc { + /** Platform ops */ + const struct no_os_trng_platform_ops *platform_ops; + /** Platform specific parameters */ + void *extra; +}; + +/** + * @struct no_os_trng_init_param + * @brief Init parameter for TRNG + */ +struct no_os_trng_init_param { + /** Device id */ + uint32_t dev_id; + /** Platform specific parameter */ + void *extra; + /** Platform ops */ + const struct no_os_trng_platform_ops *platform_ops; +}; + +/** + * @struct no_os_trng_platform_ops + * @brief Structure holding TRNG function pointers that point to the platform + * specific function + */ +struct no_os_trng_platform_ops { + /** TRNG initialization function pointer */ + int (*init)(struct no_os_trng_desc **, + struct no_os_trng_init_param *); + /** Fill buffer with random numbers */ + int (*fill_buffer)(struct no_os_trng_desc *, uint8_t *, uint32_t); + /** TRNG remove function pointer */ + int (*remove)(struct no_os_trng_desc *); +}; + +/* Initialize descriptor */ +int no_os_trng_init(struct no_os_trng_desc **desc, + const struct no_os_trng_init_param *param); + +/* Free resources allocated in descriptor */ +int no_os_trng_remove(struct no_os_trng_desc *desc); + +/* Fill buffer with random numbers */ +int no_os_trng_fill_buffer(struct no_os_trng_desc *desc, uint8_t *buff, + uint32_t len); + +#endif // _NO_OS_TRNG_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.c new file mode 100644 index 0000000..4053645 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.c @@ -0,0 +1,220 @@ +/***************************************************************************//** + * @file no_os_uart.c + * @brief Implementation of the UART Interface + * @author Ramona Bolboaca (ramona.bolboaca@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include "no_os_uart.h" +#include +#include "no_os_error.h" +#include "no_os_mutex.h" +#include "no_os_util.h" + +/** + * @brief - UART mutex +*/ +static void *uart_mutex_table[UART_MAX_NUMBER + 1]; + +/** + * @brief Initialize the UART communication peripheral. + * @param desc - The UART descriptor. + * @param param - The structure that contains the UART parameters. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_init(struct no_os_uart_desc **desc, + struct no_os_uart_init_param *param) +{ + int32_t ret; + + if (!param || !param->platform_ops + || param->device_id >= NO_OS_ARRAY_SIZE(uart_mutex_table)) + return -EINVAL; + + if (!param->platform_ops->init) + return -ENOSYS; + + ret = param->platform_ops->init(desc, param); + if (ret) + return ret; + + (*desc)->platform_ops = param->platform_ops; + + no_os_mutex_init(&(uart_mutex_table[param->device_id])); + (*desc)-> mutex = uart_mutex_table[param->device_id]; + + return 0; +} + +/** + * @brief Free the resources allocated by no_os_uart_init(). + * @param desc - The UART descriptor. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_remove(struct no_os_uart_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->remove) + return -ENOSYS; + + no_os_mutex_remove(desc->mutex); + uart_mutex_table[desc->device_id] = NULL; + + return desc->platform_ops->remove(desc); +} + +/** + * @brief Check if errors occurred on UART. + * @param desc - The UART descriptor. + * @return number of errors in case of success, error code otherwise. + */ +uint32_t no_os_uart_get_errors(struct no_os_uart_desc *desc) +{ + if (!desc || !desc->platform_ops) + return -EINVAL; + + if (!desc->platform_ops->get_errors) + return -ENOSYS; + + return desc->platform_ops->get_errors(desc); +} + +/** + * @brief Read data from UART. + * @param desc - The UART descriptor. + * @param data - The buffer with the received data. + * @param bytes_number - Number of bytes to read. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_read(struct no_os_uart_desc *desc, + uint8_t *data, + uint32_t bytes_number) +{ + int32_t ret; + + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->read) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + ret = desc->platform_ops->read(desc, data, bytes_number); + no_os_mutex_unlock(desc->mutex); + + return ret; +} + +/** + * @brief Write to UART. + * @param desc - The UART descriptor. + * @param data - The buffer with the transmitted data. + * @param bytes_number - Number of bytes to write. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_write(struct no_os_uart_desc *desc, + const uint8_t *data, + uint32_t bytes_number) +{ + int32_t ret; + + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->write) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + ret = desc->platform_ops->write(desc, data, bytes_number); + no_os_mutex_unlock(desc->mutex); + + return ret; +} + +/** + * @brief Read data from UART non-blocking. + * @param desc - The UART descriptor. + * @param data - The buffer with the received data. + * @param bytes_number - Number of bytes to read. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_read_nonblocking(struct no_os_uart_desc *desc, + uint8_t *data, + uint32_t bytes_number) +{ + int32_t ret; + + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->read_nonblocking) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + ret = desc->platform_ops->read_nonblocking(desc, data, bytes_number); + no_os_mutex_unlock(desc->mutex); + + return ret; +} + +/** + * @brief Write to UART non-blocking. + * @param desc - The UART descriptor. + * @param data - The buffer with the transmitted data. + * @param bytes_number - Number of bytes to write. + * @return 0 in case of success, error code otherwise. + */ +int32_t no_os_uart_write_nonblocking(struct no_os_uart_desc *desc, + const uint8_t *data, + uint32_t bytes_number) +{ + int32_t ret; + + if (!desc || !desc->platform_ops || !data) + return -EINVAL; + + if (!desc->platform_ops->write_nonblocking) + return -ENOSYS; + + no_os_mutex_lock(desc->mutex); + ret = desc->platform_ops->write_nonblocking(desc, data, bytes_number); + no_os_mutex_unlock(desc->mutex); + + return ret; +} + + +void __attribute__((weak)) no_os_uart_stdio(struct no_os_uart_desc *desc) +{ + /* This can optionally be implemented under drivers/platform. + * It does nothing if unimplemented. */ +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.h new file mode 100644 index 0000000..b8605ff --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_uart.h @@ -0,0 +1,191 @@ +/***************************************************************************//** + * @file no_os_uart.h + * @brief Header file of UART interface. + * @author Cristian Pop (cristian.pop@analog.com) +******************************************************************************** + * Copyright 2019(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_UART_H_ +#define _NO_OS_UART_H_ + +#include +#include +#include "no_os_lf256fifo.h" + +#define UART_MAX_NUMBER 10 + +/** + * @enum no_os_uart_size + * @brief UART character size (number of data bits) options. + */ +enum no_os_uart_size { + /** 5 data bits */ + NO_OS_UART_CS_5, + /** 6 data bits */ + NO_OS_UART_CS_6, + /** 7 data bits */ + NO_OS_UART_CS_7, + /** 8 data bits */ + NO_OS_UART_CS_8, + /** 9 data bits */ + NO_OS_UART_CS_9, +}; + +/** + * @enum no_os_uart_parity + * @brief UART parity options. + */ +enum no_os_uart_parity { + /** no parity */ + NO_OS_UART_PAR_NO, + /** mark parity */ + NO_OS_UART_PAR_MARK, + /** space parity */ + NO_OS_UART_PAR_SPACE, + /** odd parity */ + NO_OS_UART_PAR_ODD, + /** even parity */ + NO_OS_UART_PAR_EVEN +}; + +/** + * @enum no_os_uart_stop + * @brief UART number of stop bits options. + */ +enum no_os_uart_stop { + /** one stop bit */ + NO_OS_UART_STOP_1_BIT, + /** two stop bits */ + NO_OS_UART_STOP_2_BIT +}; + +/** + * @struct no_os_uart_platform_ops + * @brief Structure holding UART function pointers that point to the platform + * specific function + */ +struct no_os_uart_platform_ops ; + +/** + * @struct no_os_uart_init_param + * @brief Structure holding the parameters for UART initialization + */ +struct no_os_uart_init_param { + /** UART Device ID */ + uint8_t device_id; + /** UART Interrupt ID */ + uint32_t irq_id; + /** If set, the reception is interrupt driven. */ + bool asynchronous_rx; + /** UART Baud Rate */ + uint32_t baud_rate; + /** UART number of data bits */ + enum no_os_uart_size size; + /** UART parity */ + enum no_os_uart_parity parity; + /** UART number of stop bits */ + enum no_os_uart_stop stop; + const struct no_os_uart_platform_ops *platform_ops; + /** UART extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_uart_desc + * @brief Stucture holding the UART descriptor. + */ +struct no_os_uart_desc { + /** UART mutex*/ + void *mutex; + /** UART Device ID */ + uint8_t device_id; + /** UART Interrupt ID */ + uint32_t irq_id; + /** Software FIFO. */ + struct lf256fifo *rx_fifo; + /** UART Baud Rate */ + uint32_t baud_rate; + const struct no_os_uart_platform_ops *platform_ops; + /** UART extra parameters (device specific) */ + void *extra; +}; + +/** + * @struct no_os_uart_platform_ops + * @brief Structure holding UART function pointers that point to the platform + * specific function + */ +struct no_os_uart_platform_ops { + /** UART initialization function pointer */ + int32_t (*init)(struct no_os_uart_desc **, struct no_os_uart_init_param *); + /** UART read function pointer */ + int32_t (*read)(struct no_os_uart_desc *, uint8_t *, uint32_t); + /** UART write function pointer */ + int32_t (*write)(struct no_os_uart_desc *, const uint8_t *, uint32_t); + /** UART read non-blocking function pointer */ + int32_t (*read_nonblocking)(struct no_os_uart_desc *, uint8_t *, uint32_t); + /** UART wrote non-blocking function pointer */ + int32_t (*write_nonblocking)(struct no_os_uart_desc *, const uint8_t *, + uint32_t); + /** UART remove function pointer */ + int32_t (*remove)(struct no_os_uart_desc *); + /** UART get errors function pointer */ + uint32_t (*get_errors)(struct no_os_uart_desc *); +}; + +/* Read data from UART. Blocking function */ +int32_t no_os_uart_read(struct no_os_uart_desc *desc, uint8_t *data, + uint32_t bytes_number); + +/* Write data to UART. Blocking function */ +int32_t no_os_uart_write(struct no_os_uart_desc *desc, const uint8_t *data, + uint32_t bytes_number); + +/* Read data from UART. Non blocking function */ +int32_t no_os_uart_read_nonblocking(struct no_os_uart_desc *desc, uint8_t *data, + uint32_t bytes_number); + +/* Write data to UART. Non blocking function*/ +int32_t no_os_uart_write_nonblocking(struct no_os_uart_desc *desc, + const uint8_t *data, + uint32_t bytes_number); + +/* Initialize the UART communication peripheral. */ +int32_t no_os_uart_init(struct no_os_uart_desc **desc, + struct no_os_uart_init_param *param); + +/* Free the resources allocated by no_os_uart_init(). */ +int32_t no_os_uart_remove(struct no_os_uart_desc *desc); + +/* Check if UART errors occurred. */ +uint32_t no_os_uart_get_errors(struct no_os_uart_desc *desc); + +/* Make stdio to use this UART. */ +void no_os_uart_stdio(struct no_os_uart_desc *desc); + +#endif // _NO_OS_UART_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_units.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_units.h new file mode 100644 index 0000000..826ed3e --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_units.h @@ -0,0 +1,83 @@ +/***************************************************************************//** + * @file no_os_units.h + * @brief Header file of Units + * @author Antoniu Miclaus (antoniu.miclaus@analog.com) +******************************************************************************** + * Copyright 2022(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_UNITS_H_ +#define _NO_OS_UNITS_H_ + +#define PETA 1000000000000000ULL +#define TERA 1000000000000ULL +#define GIGA 1000000000UL +#define MEGA 1000000UL +#define KILO 1000UL +#define HECTO 100UL +#define DECA 10UL +#define DECI 10UL +#define CENTI 100UL +#define MILLI 1000UL +#define MICRO 1000000UL +#define NANO 1000000000UL +#define PICO 1000000000000ULL +#define FEMTO 1000000000000000ULL + +#define HZ_PER_KHZ 1000UL +#define KHZ_PER_MHZ 1000UL +#define HZ_PER_MHZ 1000000UL + +#define MILLIVOLT_PER_VOLT 1000UL +#define MICROVOLT_PER_VOLT 1000000UL +#define NANOVOLT_PER_VOLT 1000000000ULL + +#define MILLIAMPER_PER_AMPER 1000UL +#define MICROAMPER_PER_MILLIAMPER 1000UL +#define MICROAMPER_PER_AMPER 1000000UL +#define NANOAMPER_PER_AMPER 1000000000ULL + +#define MILLIWATT_PER_WATT 1000UL +#define MICROWATT_PER_MILLIWATT 1000UL +#define MICROWATT_PER_WATT 1000000UL + +#define MILLIDEGREE_PER_DEGREE 1000UL + +/* Returns the given value converted from degree to rad */ +#define DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL) + +/* Returns the given value converted from rad to degree */ +#define RAD_TO_DEGREE(rad) \ + (((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL) + +/* Returns the given value converted from g to meter / second**2 */ +#define G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL) + +/* Returns the given value converted from meter / second**2 to g */ +#define M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL) + +#endif // _NO_OS_UNITS_H_ diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.c new file mode 100644 index 0000000..0b3239b --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.c @@ -0,0 +1,568 @@ +/***************************************************************************//** + * @file no_os_util.c + * @brief Implementation of utility functions. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2018(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include "no_os_util.h" +#include "errno.h" +extern int no_os_test_bit(int pos, const volatile void * addr); + +/** + * Find first set bit in word. + */ +uint32_t no_os_find_first_set_bit(uint32_t word) +{ + uint32_t first_set_bit = 0; + + while (word) { + if (word & 0x1) + return first_set_bit; + word >>= 1; + first_set_bit ++; + } + + return 32; +} + +/** + * Find first set bit in word. + */ +uint64_t no_os_find_first_set_bit_u64(uint64_t word) +{ + uint64_t first_set_bit = 0; + + while (word) { + if (word & 0x1) + return first_set_bit; + word >>= 1; + first_set_bit ++; + } + + return 64; +} + +/** + * Find last set bit in word. + */ +uint32_t no_os_find_last_set_bit(uint32_t word) +{ + uint32_t bit = 0; + uint32_t last_set_bit = 32; + + while (word) { + if (word & 0x1) + last_set_bit = bit; + word >>= 1; + bit ++; + } + + return last_set_bit; +} + +/** + * Locate the closest element in an array. + */ +uint32_t no_os_find_closest(int32_t val, + const int32_t *array, + uint32_t size) +{ + int32_t diff = abs(array[0] - val); + uint32_t ret = 0; + uint32_t i; + + for (i = 1; i < size; i++) { + if (abs(array[i] - val) < diff) { + diff = abs(array[i] - val); + ret = i; + } + } + + return ret; +} + +/** + * Shift the value and apply the specified mask. + */ +uint32_t no_os_field_prep(uint32_t mask, uint32_t val) +{ + return (val << no_os_find_first_set_bit(mask)) & mask; +} + +uint64_t no_os_field_prep_u64(uint64_t mask, uint64_t val) +{ + return (val << no_os_find_first_set_bit_u64(mask)) & mask; +} + +/** + * Get a field specified by a mask from a word. + */ +uint32_t no_os_field_get(uint32_t mask, uint32_t word) +{ + return (word & mask) >> no_os_find_first_set_bit(mask); +} + +/** + * Produce the maximum value representable by a field + */ +uint32_t no_os_field_max(uint32_t mask) +{ + // Find the first set bit to determine the shift position + uint32_t first_set_bit = no_os_find_first_set_bit(mask); + + // Shift the mask to the right by the position of the first set bit + uint32_t shifted_mask = mask >> first_set_bit; + + return shifted_mask; +} + +/** + * Produce the maximum value representable by a field + */ +uint64_t no_os_field_max_u64(uint64_t mask) +{ + // Find the first set bit to determine the shift position + uint64_t first_set_bit = no_os_find_first_set_bit_u64(mask); + + // Shift the mask to the right by the position of the first set bit + uint64_t shifted_mask = mask >> first_set_bit; + + return shifted_mask; +} + + +/** + * Log base 2 of the given number. + */ +int32_t no_os_log_base_2(uint32_t x) +{ + return no_os_find_last_set_bit(x); +} + +/** + * Find greatest common divisor of the given two numbers. + */ +uint32_t no_os_greatest_common_divisor(uint32_t a, + uint32_t b) +{ + uint32_t div; + + if ((a == 0) || (b == 0)) + return no_os_max(a, b); + + while (b != 0) { + div = a % b; + a = b; + b = div; + } + + return a; +} + +uint64_t no_os_greatest_common_divisor_u64(uint64_t a, + uint64_t b) +{ + uint64_t div; + + if ((a == 0) || (b == 0)) + return no_os_max(a, b); + + while (b != 0) { + div = a % b; + a = b; + b = div; + } + + return a; +} + +/** + * Find lowest common multiple of the given two numbers. + */ +uint32_t no_os_lowest_common_multiple(uint32_t a, uint32_t b) +{ + if (a && b) + return (a / no_os_greatest_common_divisor(a, b)) * b; + else + return 0; +} + +/** + * Calculate best rational approximation for a given fraction. + */ +void no_os_rational_best_approximation(uint32_t given_numerator, + uint32_t given_denominator, + uint32_t max_numerator, + uint32_t max_denominator, + uint32_t *best_numerator, + uint32_t *best_denominator) +{ + uint32_t gcd; + + gcd = no_os_greatest_common_divisor(given_numerator, given_denominator); + + *best_numerator = given_numerator / gcd; + *best_denominator = given_denominator / gcd; + + if ((*best_numerator > max_numerator) || + (*best_denominator > max_denominator)) { + *best_numerator = 0; + *best_denominator = 0; + } +} + +void no_os_rational_best_approximation_u64(uint64_t given_numerator, + uint64_t given_denominator, + uint64_t max_numerator, + uint64_t max_denominator, + uint64_t *best_numerator, + uint64_t *best_denominator) +{ + uint64_t gcd; + + gcd = no_os_greatest_common_divisor_u64(given_numerator, given_denominator); + + *best_numerator = given_numerator / gcd; + *best_denominator = given_denominator / gcd; + + if ((*best_numerator > max_numerator) || + (*best_denominator > max_denominator)) { + *best_numerator = 0; + *best_denominator = 0; + } +} + +/** + * Calculate the number of set bits (8-bit size). + */ +unsigned int no_os_hweight8(uint8_t word) +{ + uint32_t count = 0; + + while (word) { + if (word & 0x1) + count++; + word >>= 1; + } + + return count; +} + +/** + * Calculate the number of set bits (16-bit size). + */ +unsigned int no_os_hweight16(uint16_t word) +{ + return no_os_hweight8(word >> 8) + + no_os_hweight8(word); +} + +/** + * Calculate the number of set bits (32-bit size). + */ +unsigned int no_os_hweight32(uint32_t word) +{ + return no_os_hweight16(word >> 16) + + no_os_hweight16(word); +} + +/** + * Calculate the quotient and the remainder of an integer division. + */ +uint64_t no_os_do_div(uint64_t* n, + uint64_t base) +{ + uint64_t mod = 0; + + mod = *n % base; + *n = *n / base; + + return mod; +} + +/** + * Unsigned 64bit divide with 64bit divisor and remainder + */ +uint64_t no_os_div64_u64_rem(uint64_t dividend, uint64_t divisor, + uint64_t *remainder) +{ + *remainder = dividend % divisor; + + return dividend / divisor; +} + +/** + * Unsigned 64bit divide with 32bit divisor with remainder + */ +uint64_t no_os_div_u64_rem(uint64_t dividend, uint32_t divisor, + uint32_t *remainder) +{ + *remainder = no_os_do_div(÷nd, divisor); + + return dividend; +} + +/** + * Signed 64bit divide with 32bit divisor with remainder + */ +int64_t no_os_div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder) +{ + *remainder = dividend % divisor; + return dividend / divisor; +} + +/** + * Unsigned 64bit divide with 32bit divisor + */ +uint64_t no_os_div_u64(uint64_t dividend, uint32_t divisor) +{ + uint32_t remainder; + + return no_os_div_u64_rem(dividend, divisor, &remainder); +} + +/** + * Signed 64bit divide with 32bit divisor + */ +int64_t no_os_div_s64(int64_t dividend, int32_t divisor) +{ + int32_t remainder; + return no_os_div_s64_rem(dividend, divisor, &remainder); +} + +/** + * Converts from string to int32_t + * @param *str + * @return int32_t + */ +int32_t no_os_str_to_int32(const char *str) +{ + char *end; + int32_t value = strtol(str, &end, 0); + + if (end == str) + return -EINVAL; + else + return value; +} + +/** + * Converts from string to uint32_t + * @param *str + * @return uint32_t + */ +uint32_t no_os_str_to_uint32(const char *str) +{ + char *end; + uint32_t value = strtoul(str, &end, 0); + + if (end == str) + return -EINVAL; + else + return value; +} + +void no_os_put_unaligned_be16(uint16_t val, uint8_t *buf) +{ + buf[1] = val & 0xFF; + buf[0] = val >> 8; +} + +uint16_t no_os_get_unaligned_be16(uint8_t *buf) +{ + return buf[1] | ((uint16_t)buf[0] << 8); +} + +void no_os_put_unaligned_le16(uint16_t val, uint8_t *buf) +{ + buf[0] = val & 0xFF; + buf[1] = val >> 8; +} + +uint16_t no_os_get_unaligned_le16(uint8_t *buf) +{ + return buf[0] | ((uint16_t)buf[1] << 8); +} + +void no_os_put_unaligned_be24(uint32_t val, uint8_t *buf) +{ + buf[2] = val & 0xFF; + buf[1] = (val >> 8) & 0xFF; + buf[0] = val >> 16; +} + +uint32_t no_os_get_unaligned_be24(uint8_t *buf) +{ + return buf[2] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[0] << 16); +} + +void no_os_put_unaligned_le24(uint32_t val, uint8_t *buf) +{ + buf[0] = val & 0xFF; + buf[1] = (val >> 8) & 0xFF; + buf[2] = val >> 16; +} + +uint32_t no_os_get_unaligned_le24(uint8_t *buf) +{ + return buf[0] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[2] << 16); +} + +void no_os_put_unaligned_be32(uint32_t val, uint8_t *buf) +{ + buf[3] = val & 0xFF; + buf[2] = (val >> 8) & 0xFF; + buf[1] = (val >> 16) & 0xFF; + buf[0] = val >> 24; +} + +uint32_t no_os_get_unaligned_be32(uint8_t *buf) +{ + return buf[3] | ((uint16_t)buf[2] << 8) | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[0] << 24); +} + +void no_os_put_unaligned_le32(uint32_t val, uint8_t *buf) +{ + buf[0] = val & 0xFF; + buf[1] = (val >> 8) & 0xFF; + buf[2] = (val >> 16) & 0xFF; + buf[3] = val >> 24; +} + +uint32_t no_os_get_unaligned_le32(uint8_t *buf) +{ + return buf[0] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +} + +int16_t no_os_sign_extend16(uint16_t value, int index) +{ + uint8_t shift = 15 - index; + return (int16_t)(value << shift) >> shift; +} + +int32_t no_os_sign_extend32(uint32_t value, int index) +{ + uint8_t shift = 31 - index; + return (int32_t)(value << shift) >> shift; +} + +uint64_t no_os_mul_u32_u32(uint32_t a, uint32_t b) +{ + return (uint64_t)a * b; +} + +uint64_t no_os_mul_u64_u32_shr(uint64_t a, uint32_t mul, unsigned int shift) +{ + uint32_t ah, al; + uint64_t ret; + + al = a; + ah = a >> 32; + + ret = no_os_mul_u32_u32(al, mul) >> shift; + if (ah) + ret += no_os_mul_u32_u32(ah, mul) << (32 - shift); + + return ret; +} + +uint64_t no_os_mul_u64_u32_div(uint64_t a, uint32_t mul, uint32_t divisor) +{ + int i; + uint64_t low, high, temp, rem; + uint32_t a_high = a >> 32; + uint32_t a_low = a & 0xFFFFFFFF; + uint64_t result = 0; + uint64_t low_low = no_os_mul_u32_u32(a_low, mul); + uint64_t high_low = no_os_mul_u32_u32(a_high, mul); + + low = low_low + ((high_low & 0xFFFFFFFF) << 32); + high = (high_low >> 32) + (low_low >> 32); + + rem = high; + + for (i = 0; i < 64; i++) { + /* Shift remainder left and add the next bit from low */ + rem = (rem << 1) | (low >> 63); + low <<= 1; + + /* Compare the remainder with the divisor */ + if (rem >= divisor) { + rem -= divisor; + temp = (uint64_t)1 << (63 - i); + result |= temp; + } + } + return result; +} + +/** + * @brief Check big endianess of the host processor. + * @return Big endianess status (true/false) + */ +bool no_os_is_big_endian(void) +{ + uint16_t a = 0x0100; + return (bool) * (uint8_t *)&a; +} + +/* @brief Swap bytes in a buffer with a given step + * Swap with step of 2: + * AA BB CC DD EE FF 00 11 becomes + * BB AA DD CC FF EE 11 00 + * Swap with step of 3: + * AA BB CC DD EE FF 00 11 22 becomes + * CC BB AA FF EE DD 22 11 00 + * etc. + * @param buf - Input buffer to be swapped. + * @param bytes - Number of bytes. + * @param step - Number of steps. + * @return None + */ +void no_os_memswap64(void *buf, uint32_t bytes, uint32_t step) +{ + uint8_t * p = buf; + uint32_t i, j; + uint8_t temp[8]; + + if (step < 2 || step > 8 || bytes < step || bytes % step != 0) + return; + + for (i = 0; i < bytes; i += step) { + memcpy(temp, p, step); + for (j = step; j > 0; j--) { + *p++ = temp[j - 1]; + } + } +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.h new file mode 100644 index 0000000..9bf54f3 --- /dev/null +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_util.h @@ -0,0 +1,215 @@ +/***************************************************************************//** + * @file no_os_util.h + * @brief Header file of utility functions. + * @author DBogdan (dragos.bogdan@analog.com) +******************************************************************************** + * Copyright 2018(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef _NO_OS_UTIL_H_ +#define _NO_OS_UTIL_H_ + +#include +#include +#include +#define NO_OS_BIT(x) (1 << (x)) + +#define NO_OS_BIT_ULL(x) ((uint64_t) 1 << (x)) + +#define NO_OS_ARRAY_SIZE(x) \ + (sizeof(x) / sizeof((x)[0])) + +#define NO_OS_DIV_ROUND_UP(x,y) \ + (((x) + (y) - 1) / (y)) +#define NO_OS_DIV_ROUND_CLOSEST(x, y) \ + (((x) + (y) / 2) / (y)) +#define NO_OS_DIV_ROUND_CLOSEST_ULL(x, y) \ + NO_OS_DIV_ROUND_CLOSEST(x, y) + +#define no_os_min(x, y) \ + (((x) < (y)) ? (x) : (y)) +#define no_os_min_t(type, x, y) \ + (type)no_os_min((type)(x), (type)(y)) + +#define no_os_max(x, y) \ + (((x) > (y)) ? (x) : (y)) +#define no_os_max_t(type, x, y) \ + (type)no_os_max((type)(x), (type)(y)) + +#define no_os_clamp(val, min_val, max_val) \ + (no_os_max(no_os_min((val), (max_val)), (min_val))) +#define no_os_clamp_t(type, val, min_val, max_val) \ + (type)no_os_clamp((type)(val), (type)(min_val), (type)(max_val)) + +#define no_os_swap(x, y) \ + {typeof(x) _tmp_ = (x); (x) = (y); (y) = _tmp_;} + +#define no_os_round_up(x,y) \ + (((x)+(y)-1)/(y)) + +#define NO_OS_BITS_PER_LONG 32 + +#define NO_OS_GENMASK(h, l) ({ \ + uint32_t t = (uint32_t)(~0UL); \ + t = t << (NO_OS_BITS_PER_LONG - (h - l + 1)); \ + t = t >> (NO_OS_BITS_PER_LONG - (h + 1)); \ + t; \ +}) +#define NO_OS_GENMASK_ULL(h, l) ({ \ + unsigned long long t = (unsigned long long)(~0ULL); \ + t = t << (64 - (h - l + 1)); \ + t = t >> (64 - (h + 1)); \ + t; \ +}) + +#define no_os_bswap_constant_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define no_os_bswap_constant_16(x) ((((x) & (uint16_t)0xff00) >> 8) | \ + (((x) & (uint16_t)0x00ff) << 8)) + +#define no_os_bit_swap_constant_8(x) \ + ((((x) & 0x80) >> 7) | \ + (((x) & 0x40) >> 5) | \ + (((x) & 0x20) >> 3) | \ + (((x) & 0x10) >> 1) | \ + (((x) & 0x08) << 1) | \ + (((x) & 0x04) << 3) | \ + (((x) & 0x02) << 5) | \ + (((x) & 0x01) << 7)) + +#define NO_OS_U16_MAX ((uint16_t)~0U) +#define NO_OS_S16_MAX ((int16_t)(NO_OS_U16_MAX>>1)) + +#define NO_OS_DIV_U64(x, y) (x / y) + +#define NO_OS_UNUSED_PARAM(x) ((void)x) + +#define no_os_shift_right(x, s) ((x) < 0 ? -(-(x) >> (s)) : (x) >> (s)) + +#define no_os_align(x, align) (((x) + ((typeof(x))(align) - 1)) & ~((typeof(x))(align) - 1)) + +#define no_os_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10) +#define no_os_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10) + +#define NO_OS_CONTAINER_OF(ptr, type, name) ((type *)((char *)(ptr) - offsetof(type, name))) + +/* Check if bit set */ +inline int no_os_test_bit(int pos, const volatile void * addr) +{ + return (((const int *)addr)[pos / 32] >> pos) & 1UL; +} + +/* Find first set bit in word. */ +uint32_t no_os_find_first_set_bit(uint32_t word); +uint64_t no_os_find_first_set_bit_u64(uint64_t word); +/* Find last set bit in word. */ +uint32_t no_os_find_last_set_bit(uint32_t word); +/* Locate the closest element in an array. */ +uint32_t no_os_find_closest(int32_t val, + const int32_t *array, + uint32_t size); +/* Shift the value and apply the specified mask. */ +uint32_t no_os_field_prep(uint32_t mask, uint32_t val); +uint64_t no_os_field_prep_u64(uint64_t mask, uint64_t val); +/* Get a field specified by a mask from a word. */ +uint32_t no_os_field_get(uint32_t mask, uint32_t word); +/* Produce the maximum value representable by a field */ +uint32_t no_os_field_max(uint32_t mask); +uint64_t no_os_field_max_u64(uint64_t mask); + +/* Log base 2 of the given number. */ +int32_t no_os_log_base_2(uint32_t x); +/* Find greatest common divisor of the given two numbers. */ +uint32_t no_os_greatest_common_divisor(uint32_t a, + uint32_t b); +uint64_t no_os_greatest_common_divisor_u64(uint64_t a, + uint64_t b); +/* Find lowest common multiple of the given two numbers. */ +uint32_t no_os_lowest_common_multiple(uint32_t a, uint32_t b); +/* Calculate best rational approximation for a given fraction. */ +void no_os_rational_best_approximation(uint32_t given_numerator, + uint32_t given_denominator, + uint32_t max_numerator, + uint32_t max_denominator, + uint32_t *best_numerator, + uint32_t *best_denominator); +void no_os_rational_best_approximation_u64(uint64_t given_numerator, + uint64_t given_denominator, + uint64_t max_numerator, + uint64_t max_denominator, + uint64_t *best_numerator, + uint64_t *best_denominator); +/* Calculate the number of set bits (8-bit size). */ +unsigned int no_os_hweight8(uint8_t word); +/* Calculate the number of set bits (16-bit size). */ +unsigned int no_os_hweight16(uint16_t word); +/* Calculate the number of set bits (32-bit size). */ +unsigned int no_os_hweight32(uint32_t word); +/* Calculate the quotient and the remainder of an integer division. */ +uint64_t no_os_do_div(uint64_t* n, + uint64_t base); +/* Unsigned 64bit divide with 64bit divisor and remainder */ +uint64_t no_os_div64_u64_rem(uint64_t dividend, uint64_t divisor, + uint64_t *remainder); +/* Unsigned 64bit divide with 32bit divisor with remainder */ +uint64_t no_os_div_u64_rem(uint64_t dividend, uint32_t divisor, + uint32_t *remainder); +int64_t no_os_div_s64_rem(int64_t dividend, int32_t divisor, + int32_t *remainder); +/* Unsigned 64bit divide with 32bit divisor */ +uint64_t no_os_div_u64(uint64_t dividend, uint32_t divisor); +int64_t no_os_div_s64(int64_t dividend, int32_t divisor); +/* Converts from string to int32_t */ +int32_t no_os_str_to_int32(const char *str); +/* Converts from string to uint32_t */ +uint32_t no_os_str_to_uint32(const char *str); + +void no_os_put_unaligned_be16(uint16_t val, uint8_t *buf); +uint16_t no_os_get_unaligned_be16(uint8_t *buf); +void no_os_put_unaligned_le16(uint16_t val, uint8_t *buf); +uint16_t no_os_get_unaligned_le16(uint8_t *buf); +void no_os_put_unaligned_be24(uint32_t val, uint8_t *buf); +uint32_t no_os_get_unaligned_be24(uint8_t *buf); +void no_os_put_unaligned_le24(uint32_t val, uint8_t *buf); +uint32_t no_os_get_unaligned_le24(uint8_t *buf); +void no_os_put_unaligned_be32(uint32_t val, uint8_t *buf); +uint32_t no_os_get_unaligned_be32(uint8_t *buf); +void no_os_put_unaligned_le32(uint32_t val, uint8_t *buf); +uint32_t no_os_get_unaligned_le32(uint8_t *buf); + +int16_t no_os_sign_extend16(uint16_t value, int index); +int32_t no_os_sign_extend32(uint32_t value, int index); +uint64_t no_os_mul_u32_u32(uint32_t a, uint32_t b); +uint64_t no_os_mul_u64_u32_shr(uint64_t a, uint32_t mul, unsigned int shift); +uint64_t no_os_mul_u64_u32_div(uint64_t a, uint32_t mul, uint32_t divisor); + +bool no_os_is_big_endian(void); +void no_os_memswap64(void *buf, uint32_t bytes, uint32_t step); + +#endif // _NO_OS_UTIL_H_