From e21c79a96fea2ce90cf7236797fd4691938e91e2 Mon Sep 17 00:00:00 2001 From: Robin Krens Date: Sun, 22 Jan 2023 12:54:53 +0100 Subject: [PATCH] libsi24: config and send functionality --- CMakeLists.txt | 2 +- libsi24.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- libsi24.h | 77 ++++++++++++++++++----- libsi24reg.h | 127 ++++++++++++++++++++++++++++++++------ 4 files changed, 363 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15484ff..2fd6f5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(libsi24 set(PROJECT_DESCRIPTION "si24r1 library") set(PROJECT_HOMEPAGE_URL https://github.com/robinkrens/libsi24) -add_compile_options(-Wall -Wextra -pedantic -Werror) +add_compile_options(-Wall -Wextra -pedantic) add_library(libsi24 libsi24.c) diff --git a/libsi24.c b/libsi24.c index 43ef472..260506e 100644 --- a/libsi24.c +++ b/libsi24.c @@ -2,12 +2,13 @@ * File : libsi24.c * Author : Robin Krens * Date : 18.01.2023 - * Last Modified Date: 18.01.2023 + * Last Modified Date: 22.01.2023 * Last Modified By : Robin Krens */ #include #include +#include #include #include @@ -18,8 +19,108 @@ struct si24_t { const si24_opts_t *opts; const si24_ioctl_t *ctl; si24_event_handler_t eh; + si24_status_reg_t sr; }; +static uint8_t _reg_read(si24_t *si, uint8_t reg, + uint8_t *data, int sz) +{ + uint8_t buf[sz+1]; + + memset(buf, 0, sz+1); + buf[0] = reg | SI24_R_REGISTER; + + if (si->ctl->write_and_read(buf, sz+1) == -1) { + si24_event_t ev; + ev.type = EV_ERR_BUS; + si->eh(si, &ev); + return -1; + } + + memcpy(data, (buf+1), sz); + + return 0; +} + +static uint8_t _reg_write(si24_t *si, uint8_t reg, + const uint8_t *data, int sz) +{ + uint8_t buf[sz+1]; + + buf[0] = reg | SI24_W_REGISTER; + memcpy((buf+1), data, sz); + + if (si->ctl->write_and_read(buf, sz+1) == -1) { + si24_event_t ev; + ev.type = EV_ERR_BUS; + si->eh(si, &ev); + return -1; + } + + return 0; +} + +static int _config(si24_t * si) +{ + int ret = 0; + uint8_t config_reg = (1 << PWR_UP); + uint8_t feature_reg = 0x2; /* default value */ + uint8_t rf_setup_reg = 0xE; /* default value */ + uint8_t setup_retr_reg = 0x3; /* default value */ + const uint8_t rf_ch_reg = 0x40; /* default value */ + const si24_opts_t * params = si->opts; + + if (params->enable_crc) { + config_reg |= (1 << EN_CRC); + config_reg |= (si->opts->crc << CRCO); + } + + if (params->enable_ack) { + uint8_t dyn = (1 << DPL_P0); + ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1); + feature_reg |= (1 << EN_DYN_ACK); + ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1); + } + + uint8_t aw; + if (params->mac_addr & 0xF0000) { + aw = AW_5; + ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); + } else if (params->mac_addr & 0xF000) { + aw = AW_4; + ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); + } else { + aw = AW_3; + ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); + } + + if (params->mode == SEND_MODE && params->enable_ack) { + ret += _reg_write(si, SI24_REG_RX_ADDR_P0, (uint8_t *) ¶ms->mac_addr, aw); + } + + if (params->mode == RECV_MODE) { + config_reg |= (1 << PRIM_RX); + uint8_t ch = 0x1; + ret += _reg_write(si, SI24_REG_EN_RXADDR, &ch, 1); + ret += _reg_write(si, SI24_REG_RX_ADDR_P0, (uint8_t *) ¶ms->mac_addr, aw); + ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) ¶ms->payload, 1); + } else { + ret += _reg_write(si, SI24_REG_TX_ADDR, (uint8_t *) ¶ms->mac_addr, aw); + } + + rf_setup_reg |= (params->speed << RF_DR_HIGH); + rf_setup_reg |= (params->txpwr << RF_PWR); + ret += _reg_write(si, SI24_REG_RF_SETUP, &rf_setup_reg, 1); + + setup_retr_reg = ARD(params->timeout) | ARC(params->retries); + ret += _reg_write(si, SI24_REG_SETUP_RETR, &setup_retr_reg, 1); + + ret += _reg_write(si, SI24_REG_RF_CH, &rf_ch_reg, 1); + ret += _reg_write(si, SI24_REG_CONFIG, &config_reg, 1); + + return ret; +} + si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh) { struct si24_t *si = (si24_t*) calloc(1, sizeof(si24_t)); @@ -30,9 +131,97 @@ si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh) si->ctl = opts->ioctl; si->eh = eh; + int ret = _config(si); + if (ret < 0) { + free(si); + return 0; + } + return si; } +size_t si24_send(si24_t* si, const unsigned char * buf, size_t size) +{ + si24_event_t ev; + uint16_t timeout = 0; + int sz; + si24_status_reg_t flags; + + if (si->opts->mode == RECV_MODE) + return -1; + + _reg_read(si, 0x7, (uint8_t *) &flags, 1); + + if (flags.bits.TX_FULL) { + ev.type = EV_TX_FULL; + si->eh(si, &ev); + return -1; + } + + for (size_t idx = 0; idx < size; idx += si->opts->payload) { + sz = (size - idx) < si->opts->payload ? (size - idx) : si->opts->payload; + if (si->opts->enable_ack) { + _reg_write(si, SI24_W_TX_PAYLOAD, buf, sz); + while ((!flags.bits.TX_DS || !flags.bits.MAX_RT) && timeout < 1000) { + _reg_read(si, SI24_REG_STATUS, (uint8_t []){0x0}, 1); + timeout++; + } + if (flags.bits.MAX_RT) { + ev.type = EV_ERR_MAX_RETRIES; + si->eh(si, &ev); + si24_reset(si); + return -1; + } + + } else { + _reg_write(si, SI24_W_TX_PAYLOAD_NO_ACK, buf, sz); + si->ctl->chip_enable(1); + while (!flags.bits.TX_DS && timeout < 1000) { + _reg_read(si, SI24_REG_STATUS, (uint8_t []){0x0}, 1); + timeout++; + } + } + + if (timeout >= 1000) { + ev.type = EV_ERR_TIMEOUT; + si->eh(si, &ev); + si24_reset(si); + return -1; + } + timeout = 0; + } + + si->ctl->chip_enable(0); + + return 0; +} + +size_t si24_recv(si24_t* si, unsigned char * buf, size_t size) +{ + (void) buf; + (void) size; + if (si->opts->mode == SEND_MODE) + return -1; + + si24_status_reg_t flags; + _reg_read(si, 0x7, (uint8_t *) &flags, 1); + + if (!flags.bits.RX_DR) + return -1; + + return 0; +} + +void si24_reset(si24_t* si) +{ + si->ctl->chip_enable(0); +} + +void si24_free(si24_t * si) +{ + free(si); +} + int main(void) { } diff --git a/libsi24.h b/libsi24.h index 5e2f53c..d862537 100644 --- a/libsi24.h +++ b/libsi24.h @@ -2,7 +2,7 @@ * File : libsi24.h * Author : Robin Krens * Date : 18.01.2023 - * Last Modified Date: 18.01.2023 + * Last Modified Date: 22.01.2023 * Last Modified By : Robin Krens */ @@ -22,12 +22,12 @@ enum si24_status_t { typedef enum si24_status_t si24_status_t; -enum si24_type_t { - RECV = 0, - SEND +enum si24_mode_t { + RECV_MODE = 0, + SEND_MODE }; -typedef enum si24_type_t si24_type_t; +typedef enum si24_mode_t si24_mode_t; enum si24_crc_t { ONE_BYTE = 1, @@ -36,24 +36,73 @@ enum si24_crc_t { typedef enum si24_crc_t si24_crc_t; -enum si24_event_t { - TEST = 0 +enum si24_speed_t { + MBPS1 = 0, + MBPS2 = 1, + KBPS250 = 2 }; -typedef enum si24_event_t si24_event_t; +typedef enum si24_speed_t si24_speed_t; + +enum si24_txpower_t { + MINUS12DB = 0, + MINUS6DB, + MINUS4DB, + ZERODB, + PLUS1DB, + PLUS3DB, + PLUS4DB, + PLUS7DB +}; + +typedef enum si24_txpower_t si24_txpower_t; + +enum si24_event_type_t { + EV_RX_COMPLETE = 0, + EV_TX_COMPLETE, + EV_TX_FULL, + EV_ERR_TIMEOUT, + EV_ERR_BUS, + EV_ERR_MAX_RETRIES, + EV_ERR_CRC, + EV_ERR_CONFIG +}; + +typedef enum si24_event_type_t si24_event_type_t; + +union si24_event_t { + enum si24_event_type_t type; + struct error_t { + enum si24_event_type_t _type; + const char *file; + const char *func; + const char *msg; + int line; + } error; +}; + +typedef union si24_event_t si24_event_t; /* low level IO control */ typedef struct { - size_t (*read)(unsigned char* buf, size_t size); - size_t (*write)(const unsigned char* buf, size_t size); + int (*write_and_read)(unsigned char *data, size_t sz); + int (*chip_enable)(unsigned val); } si24_ioctl_t; typedef struct { - si24_type_t type; + si24_mode_t mode; unsigned enable_ack; + unsigned non_blocking; + unsigned enable_crc; + unsigned enable_dynpd; si24_crc_t crc; si24_ioctl_t *ioctl; - unsigned msg_len; + si24_speed_t speed; + si24_txpower_t txpwr; + unsigned payload; + unsigned timeout; /* 1: 250 us, 15: 4000 us */ + unsigned retries; /* 1 to 15 */ + unsigned mac_addr; } si24_opts_t; /* private data structure */ @@ -63,8 +112,8 @@ typedef void (*si24_event_handler_t)(si24_t* si24, si24_event_t* event); extern si24_t* si24_init(const si24_opts_t* si24opts, si24_event_handler_t eh); extern void si24_free(si24_t* si24); -extern void si24_send(si24_t* si24, const char* buf, size_t size); -extern void si24_recv(si24_t* si24, char* buf, size_t size); +extern size_t si24_send(si24_t* si24, const unsigned char * buf, size_t size); +extern size_t si24_recv(si24_t* si24, unsigned char * buf, size_t size); extern void si24_reset(si24_t* si24); #if defined(__cplusplus) diff --git a/libsi24reg.h b/libsi24reg.h index ff9cdf3..f357298 100644 --- a/libsi24reg.h +++ b/libsi24reg.h @@ -2,31 +2,122 @@ * File : libsi24reg.h * Author : Robin Krens * Date : 18.01.2023 - * Last Modified Date: 18.01.2023 + * Last Modified Date: 22.01.2023 * Last Modified By : Robin Krens */ - -#define SI24_READ_REG 0x00 -#define SI24_WRITE_REG 0x20 +/* SI24R1 commands */ +#define SI24_R_REGISTER 0x00 +#define SI24_W_REGISTER 0x20 #define SI24_R_RX_PAYLOAD 0x61 #define SI24_W_TX_PAYLOAD 0xA0 #define SI24_FLUSH_TX 0xE1 +#define SI24_FLUSH_RX 0xE2 +#define SI24_REUSE_TX_PL 0xE3 +#define SI24_RX_PL_WID 0x60 +#define SI24_W_ACK_PAYLOAD 0xA8 +#define SI24_W_TX_PAYLOAD_NO_ACK 0xB0 +#define SI24_NOP 0xFF + +/* SI24R1 register addresses */ +#define SI24_REG_CONFIG 0x00 +#define SI24_REG_EN_AA 0x01 +#define SI24_REG_EN_RXADDR 0x02 +#define SI24_REG_SETUP_AW 0x03 +#define SI24_REG_SETUP_RETR 0x04 +#define SI24_REG_RF_CH 0x05 +#define SI24_REG_RF_SETUP 0x06 +#define SI24_REG_STATUS 0x07 +#define SI24_REG_OBSERVE_TX 0x08 +#define SI24_REG_RSSI 0x09 +#define SI24_REG_RX_ADDR_P0 0x0A +#define SI24_REG_RX_ADDR_P1 0x0B +#define SI24_REG_RX_ADDR_P2 0x0C +#define SI24_REG_RX_ADDR_P3 0x0D +#define SI24_REG_RX_ADDR_P4 0x0E +#define SI24_REG_RX_ADDR_P5 0x0F +#define SI24_REG_TX_ADDR 0x10 +#define SI24_REG_RX_PW_P0 0x11 +#define SI24_REG_RX_PW_P1 0x12 +#define SI24_REG_RX_PW_P2 0x13 +#define SI24_REG_RX_PW_P3 0x14 +#define SI24_REG_RX_PW_P4 0x15 +#define SI24_REG_RX_PW_P5 0x16 +#define SI24_REG_FIFO_SATUS 0x17 +#define SI24_REG_DYNPD 0x1C +#define SI24_REG_FEATURE 0x1D + +/* config register */ +#define PRIM_RX 0x0 +#define PWR_UP 0x1 +#define CRCO 0x2 +#define EN_CRC 0x3 +#define MASK_MAX_RT 0x4 +#define MASK_TX_DS 0x5 +#define MASK_RX_DR 0x6 + +#define ENAA_P0 0x0 +#define ENAA_P1 0x1 +#define ENAA_P2 0x2 +#define ENAA_P3 0x3 +#define ENAA_P4 0x4 +#define ENAA_P5 0x5 + +#define ERX_P0 0x0 +#define ERX_P1 0x1 +#define ERX_P2 0x2 +#define ERX_P3 0x3 +#define ERX_P4 0x4 +#define ERX_P5 0x5 + +#define AW_3 0x1 +#define AW_4 0x2 +#define AW_5 0x3 + +#define ARD(x) ((x << 3) & 0xF0) +#define ARC(x) (x & 0xF) + +#define RF_CH 0x0 + +#define RF_PWR 0x0 +#define RF_DR_HIGH 0x03 +#define PLL_LOCK 0x04 +#define RF_DR_LOW 0x05 +#define CONT_WAVE 0x07 + +#define PLOS_CNT(x) (x & 0xF0) +#define ARC_CNT(x) (x & 0x0F) + +#define RSSI 0x0 + +#define RX_EMPTY 0x0 +#define RX_FULL 0x1 +#define TX_EMPTY 0x4 +#define TX_REUSE 0x6 + +#define DPL_P0 0x0 +#define DPL_P1 0x1 +#define DPL_P2 0x2 +#define DPL_P3 0x3 +#define DPL_P4 0x4 +#define DPL_P5 0x5 + +#define EN_DYN_ACK 0x0 +#define EN_ACK_PAY 0x1 +#define EN_DPL 0x2 typedef struct { - union { - unsigned char byte; - struct { - unsigned PRIM_XR : 1; - unsigned PWR_UP : 1; - unsigned CRCO : 1; - unsigned EN_CRC : 1; - unsigned MASK_MAX_RT : 1; - unsigned MASK_TX_DS : 1; - unsigned MAKS_RX_DS : 1; - unsigned _RESERVED : 1; - } bits; - }; -} config_reg_t; + union { + unsigned char byte; + struct { + unsigned _RESERVED:1; + unsigned RX_DR:1; + unsigned TX_DS:1; + unsigned MAX_RT:1; + unsigned RX_P_NO:3; + unsigned TX_FULL:1; + } bits; + }; +} si24_status_reg_t; -- 2.7.4