license: update source file and licensing files
[libsi24] / libsi24.c
index d435b5f..f4d6da5 100644 (file)
--- a/libsi24.c
+++ b/libsi24.c
@@ -1,11 +1,20 @@
-/**
- * File              : libsi24.c
- * Author            : Robin Krens <robin@robinkrens.nl>
- * Date              : 18.01.2023
- * Last Modified Date: 22.01.2023
- * Last Modified By  : Robin Krens <robin@robinkrens.nl>
+/* Copyright (C) 
+ * 2023 - Robin Krens
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 
  */
-
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -15,7 +24,8 @@
 #include "libsi24.h"
 #include "libsi24reg.h"
 
-#define DEBUG 1
+#define DEBUG 0
+#define TIMEOUT 0xFFFF
 
 struct si24_t {
        const si24_opts_t *opts;
@@ -86,10 +96,6 @@ static int _config(si24_t * si)
        }
 
        if (params->enable_ack) {
-               uint8_t dyn = (1 << DPL_P0);
-               ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1);
-               feature_reg |= (1 << EN_DPL);
-               ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
                if (params->mode == SEND_MODE) {
                        setup_retr_reg = ARD(params->timeout) | ARC(params->retries);
                        ret += _reg_write(si, SI24_REG_SETUP_RETR, &setup_retr_reg, 1);
@@ -101,33 +107,31 @@ static int _config(si24_t * si)
                }
        }
 
-       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->enable_dynpd) {
+               uint8_t dyn = (1 << DPL_P0);
+               ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1);
+               feature_reg |= (1 << EN_DPL);
+               ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
+       } else { /* fixed payload size */
+               if (params->mode == RECV_MODE) {
+                       ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) &params->payload, 1);
+               }
        }
 
-       /* quick hack */
-       aw += 2;
+       uint8_t aw = AW_5;
+       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);
+               ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
        }
        
        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);
+               ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
        } else {
-               ret += _reg_write(si, SI24_REG_TX_ADDR, (uint8_t *) &params->mac_addr, aw);
+               ret += _reg_write(si, SI24_REG_TX_ADDR, params->mac_addr, sizeof(params->mac_addr));
        }
 
        rf_setup_reg |= (params->speed << RF_DR_HIGH);
@@ -138,6 +142,12 @@ static int _config(si24_t * si)
        ret += _reg_write(si, SI24_REG_RF_CH, &rf_ch_reg, 1);
        ret += _reg_write(si, SI24_REG_CONFIG, &config_reg, 1);
 
+       if (params->mode == RECV_MODE) {
+               /* start accepting data immediately,
+                * for send mode it is onyl activated upon sending */
+               params->ioctl->chip_enable(1);
+       }
+
        return ret;
 }
 
@@ -163,6 +173,7 @@ si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh)
 size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
 {
        si24_event_t ev;
+       size_t bytes_sent = 0;
        uint16_t timeout = 0;
        int sz;
        uint8_t flags;
@@ -178,12 +189,17 @@ size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
                return -1;
        }
 
-       for (size_t idx = 0; idx < size; idx += si->opts->payload) {
-               sz = (size - idx) < si->opts->payload ? (size - idx) : si->opts->payload;  
+       int payload = si->opts->payload;
+
+       if (si->opts->enable_dynpd)
+               payload = size > 32 ? 32 : size;
+
+       for (size_t idx = 0; idx < size; idx += payload) {
+               sz = (size - idx) < payload ? (size - idx) : payload;  
                if (si->opts->enable_ack) {
                        _reg_write(si, SI24_W_TX_PAYLOAD, buf + idx, sz);
                        si->ctl->chip_enable(1);
-                       while ((!(flags & (1 << TX_DS)) && !(flags & (1 << MAX_RT))) && timeout < 1000) {
+                       while ((!(flags & (1 << TX_DS)) && !(flags & (1 << MAX_RT))) && timeout < TIMEOUT) {
                                _reg_read(si, SI24_REG_STATUS, &flags, 1);
                                timeout++;
                        }
@@ -191,25 +207,29 @@ size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
                                ev.type = EV_ERR_MAX_RETRIES;
                                si->eh(si, &ev);
                                si24_reset(si);
-                               return -1;
+                               return bytes_sent;
                        }
 
                } else {
                        _reg_write(si, SI24_W_TX_PAYLOAD_NO_ACK, buf + idx, sz);
                        si->ctl->chip_enable(1);
-                       while (!(flags & (1 << TX_DS)) && timeout < 1000) {
+                       while (!(flags & (1 << TX_DS)) && timeout < TIMEOUT) {
                                _reg_read(si, SI24_REG_STATUS, &flags, 1);
                                timeout++;
                        }
                }
 
-               if (timeout >= 1000) {
+               if (timeout >= TIMEOUT) {
                        ev.type = EV_ERR_TIMEOUT;
                        si->eh(si, &ev);
                        si24_reset(si);
-                       return -1;
+                       return bytes_sent;
                }
 
+               flags |= (1 << TX_DS);
+               _reg_write(si, SI24_REG_STATUS, &flags, 1);
+               _reg_read(si, SI24_REG_STATUS, &flags, 1);
+               bytes_sent += sz;
                timeout = 0;
        }
 
@@ -217,20 +237,62 @@ size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
        si->eh(si, &ev);
        si->ctl->chip_enable(0);
 
-       return 0;
+       return bytes_sent;
 }
 
 size_t si24_recv(si24_t* si, unsigned char * buf, size_t size) 
 {
-       (void) buf;
-       (void) size;
+       si24_event_t ev;
+       size_t bytes_read = 0;
+       uint8_t p_size = si->opts->payload;
+       uint8_t tmpbuf[p_size];
+       uint8_t flags;
+       uint8_t fifo_flags;
+       
        if (si->opts->mode == SEND_MODE)
                return -1;
+
+       _reg_read(si, SI24_REG_STATUS, &flags, 1);
+
+       if (!(flags & (1 << RX_DR))) {
+               ev.type = EV_RX_EMPTY;
+               si->eh(si, &ev);
+               return bytes_read;
+       }
+
+       /* do not accept any new incoming data */
+       si->opts->ioctl->chip_enable(0);
+
+       _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
+       while(!(fifo_flags & (1 << RX_EMPTY)) &&
+                       bytes_read < size) {
+               
+               if (si->opts->enable_dynpd) {
+                       uint8_t d_sz = 0;
+                       _reg_read(si, SI24_RX_PL_WID, &d_sz, 1);
+                       p_size = d_sz;
+               }
+               int m_size = (size - bytes_read) > p_size ? p_size : (size - bytes_read);
+               _reg_read(si, SI24_R_RX_PAYLOAD, tmpbuf, m_size);
+
+               memcpy(buf + bytes_read, tmpbuf, m_size);
+               bytes_read += m_size;
+
+               _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
+       }
+
+       /* only clear data ready flag when FIFO is empty */
+       if (fifo_flags & (1 << RX_EMPTY)) {
+               flags |= (1 << RX_DR);
+               _reg_write(si, SI24_REG_STATUS, &flags, 1);
+       }
        
-       uint8_t flags;
-       _reg_read(si, 0x7, &flags, 1);
+       ev.type = EV_RX_COMPLETE;
+       si->eh(si, &ev);
+
+       si->opts->ioctl->chip_enable(1);
        
-       return 0;
+       return bytes_read;
 }
 
 void si24_reset(si24_t* si)
@@ -256,60 +318,3 @@ void si24_free(si24_t * si)
 {
        free(si);
 }
-
-/* hardware linkage */
-int spi_w_r(unsigned char *data, size_t sz)
-{
-       if (sz >= 2)
-               data[1] = (1 << TX_DS);
-       return sz;
-}
-
-void ce(unsigned val)
-{
-}
-
-void eh(si24_t *si, si24_event_t * e)
-{
-       switch(e->type) {
-               case EV_TX_COMPLETE:
-                       printf("SENT SUCCESFUL\n");
-                       break;
-               case EV_ERR_TIMEOUT:
-                       printf("TIMEOUT\n");
-                       break;
-               default:
-                       printf("EVENT: %x\n", e->type);
-                       break;
-       }
-}
-
-int main(void)
-{
-       const unsigned char buf[] = "THIS IS A WIRELESS TEST MESSAGE!";
-
-       si24_ioctl_t ctl = {
-               .write_and_read = spi_w_r,
-               .chip_enable = ce,
-       };
-
-       const si24_opts_t opts = {
-               .mode = RECV_MODE,
-               .enable_ack = 1,
-               .non_blocking = 0,
-               .enable_crc = 1,
-               .enable_dynpd = 1,
-               .crc = TWO_BYTE,
-               .ioctl = &ctl,
-               .speed = MBPS2,
-               .txpwr = PLUS4DB,
-               .payload = 5,
-               .timeout = 1,
-               .retries = 5,
-               .mac_addr = 0xAAAAAAAAAA
-       };
-
-       struct si24_t * si = si24_init(&opts, eh);
-       si24_send(si, buf, sizeof(buf));
-       
-}