libsi24: config and send functionality
authorRobin Krens <robin@robinkrens.nl>
Sun, 22 Jan 2023 11:54:53 +0000 (12:54 +0100)
committerRobin Krens <robin@robinkrens.nl>
Sun, 22 Jan 2023 11:54:53 +0000 (12:54 +0100)
CMakeLists.txt
libsi24.c
libsi24.h
libsi24reg.h

index 15484ff..2fd6f5a 100644 (file)
@@ -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)
 
index 43ef472..260506e 100644 (file)
--- a/libsi24.c
+++ b/libsi24.c
@@ -2,12 +2,13 @@
  * File              : libsi24.c
  * Author            : Robin Krens <robin@robinkrens.nl>
  * Date              : 18.01.2023
- * Last Modified Date: 18.01.2023
+ * Last Modified Date: 22.01.2023
  * Last Modified By  : Robin Krens <robin@robinkrens.nl>
  */
 
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -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 *) &params->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 *) &params->mac_addr, aw);
+               ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) &params->payload, 1);
+       } else {
+               ret += _reg_write(si, SI24_REG_TX_ADDR, (uint8_t *) &params->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)
 {
 }
index 5e2f53c..d862537 100644 (file)
--- a/libsi24.h
+++ b/libsi24.h
@@ -2,7 +2,7 @@
  * File              : libsi24.h
  * Author            : Robin Krens <robin@robinkrens.nl>
  * Date              : 18.01.2023
- * Last Modified Date: 18.01.2023
+ * Last Modified Date: 22.01.2023
  * Last Modified By  : Robin Krens <robin@robinkrens.nl>
  */
 
@@ -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)
index ff9cdf3..f357298 100644 (file)
  * File              : libsi24reg.h
  * Author            : Robin Krens <robin@robinkrens.nl>
  * Date              : 18.01.2023
- * Last Modified Date: 18.01.2023
+ * Last Modified Date: 22.01.2023
  * Last Modified By  : Robin Krens <robin@robinkrens.nl>
  */
 
-
-#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;