license: update source file and licensing files
[libsi24] / libsi24.c
1 /* Copyright (C) 
2  * 2023 - Robin Krens
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  * 
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16  * 
17  */
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "libsi24.h"
25 #include "libsi24reg.h"
26
27 #define DEBUG 0
28 #define TIMEOUT 0xFFFF
29
30 struct si24_t {
31         const si24_opts_t *opts;
32         const si24_ioctl_t *ctl;
33         si24_event_handler_t eh;
34 };
35
36 static uint8_t _reg_read(si24_t *si, uint8_t reg,
37                 uint8_t *data, int sz)
38 {
39         uint8_t buf[sz+1];
40         
41         memset(buf, 0, sz+1); 
42         buf[0] = reg | SI24_R_REGISTER;
43
44         
45         if (si->ctl->write_and_read(buf, sz+1) == -1) {
46                 si24_event_t ev;
47                 ev.type = EV_ERR_BUS;
48                 si->eh(si, &ev);
49                 return -1;
50         }
51         
52         memcpy(data, (buf+1), sz);
53         
54         return 0;
55 }
56
57 static uint8_t _reg_write(si24_t *si, uint8_t reg,
58                 const uint8_t *data, int sz)
59 {
60         uint8_t buf[sz+1];
61         
62         buf[0] = reg | SI24_W_REGISTER;
63         memcpy((buf+1), data, sz);
64         
65         if(DEBUG) {
66                 printf("REG 0x%x:\t", reg);
67                 for (int i = 1; i <= sz; ++i) {
68                         fprintf(stdout, "0x%x(%c)", buf[i], buf[i]);
69                 }
70                 fprintf(stdout, "\n");
71         }
72
73         if (si->ctl->write_and_read(buf, sz+1) == -1) {
74                 si24_event_t ev;
75                 ev.type = EV_ERR_BUS;
76                 si->eh(si, &ev);
77                 return -1;
78         }
79
80         return 0;
81 }
82
83 static int _config(si24_t * si)
84 {
85         int ret = 0;
86         uint8_t config_reg = (1 << PWR_UP);
87         uint8_t feature_reg = 0x0; /* default value */
88         uint8_t rf_setup_reg = 0xE; /* default value */
89         uint8_t setup_retr_reg = 0x3; /* default value */
90         const uint8_t rf_ch_reg = 0x40; /* default value */
91         const si24_opts_t * params = si->opts; 
92         
93         if (params->enable_crc) {
94                 config_reg |= (1 << EN_CRC);
95                 config_reg |= (si->opts->crc << CRCO);
96         }
97
98         if (params->enable_ack) {
99                 if (params->mode == SEND_MODE) {
100                         setup_retr_reg = ARD(params->timeout) | ARC(params->retries);
101                         ret += _reg_write(si, SI24_REG_SETUP_RETR, &setup_retr_reg, 1);
102                 }
103         } else {
104                 if (params->mode == SEND_MODE) {
105                         feature_reg |= (1 << EN_DYN_ACK);
106                         ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
107                 }
108         }
109
110         if (params->enable_dynpd) {
111                 uint8_t dyn = (1 << DPL_P0);
112                 ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1);
113                 feature_reg |= (1 << EN_DPL);
114                 ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
115         } else { /* fixed payload size */
116                 if (params->mode == RECV_MODE) {
117                         ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) &params->payload, 1);
118                 }
119         }
120
121         uint8_t aw = AW_5;
122         ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); 
123
124         if (params->mode == SEND_MODE && params->enable_ack) {
125                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
126         }
127         
128         if (params->mode == RECV_MODE) {
129                 config_reg |= (1 << PRIM_RX);
130                 uint8_t ch = 0x1;
131                 ret += _reg_write(si, SI24_REG_EN_RXADDR, &ch, 1); 
132                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
133         } else {
134                 ret += _reg_write(si, SI24_REG_TX_ADDR, params->mac_addr, sizeof(params->mac_addr));
135         }
136
137         rf_setup_reg |= (params->speed << RF_DR_HIGH);
138         rf_setup_reg |= (params->txpwr << RF_PWR);
139         ret += _reg_write(si, SI24_REG_RF_SETUP, &rf_setup_reg, 1);
140
141
142         ret += _reg_write(si, SI24_REG_RF_CH, &rf_ch_reg, 1);
143         ret += _reg_write(si, SI24_REG_CONFIG, &config_reg, 1);
144
145         if (params->mode == RECV_MODE) {
146                 /* start accepting data immediately,
147                  * for send mode it is onyl activated upon sending */
148                 params->ioctl->chip_enable(1);
149         }
150
151         return ret;
152 }
153
154 si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh)
155 {
156         struct si24_t *si = (si24_t*) calloc(1, sizeof(si24_t));
157         if (si == 0)
158                 return 0;
159
160         si->opts = opts;
161         si->ctl = opts->ioctl;
162         si->eh = eh;
163
164         int ret = _config(si);
165         if (ret < 0) {
166                 free(si);
167                 return 0;
168         }
169
170         return si;
171 }
172
173 size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
174 {
175         si24_event_t ev;
176         size_t bytes_sent = 0;
177         uint16_t timeout = 0;
178         int sz;
179         uint8_t flags;
180         
181         if (si->opts->mode == RECV_MODE)
182                 return -1;
183
184         _reg_read(si, SI24_REG_STATUS, (uint8_t *) &flags, 1);
185
186         if (flags & (1 << TX_FULL)) {
187                 ev.type = EV_TX_FULL;
188                 si->eh(si, &ev);
189                 return -1;
190         }
191
192         int payload = si->opts->payload;
193
194         if (si->opts->enable_dynpd)
195                 payload = size > 32 ? 32 : size;
196
197         for (size_t idx = 0; idx < size; idx += payload) {
198                 sz = (size - idx) < payload ? (size - idx) : payload;  
199                 if (si->opts->enable_ack) {
200                         _reg_write(si, SI24_W_TX_PAYLOAD, buf + idx, sz);
201                         si->ctl->chip_enable(1);
202                         while ((!(flags & (1 << TX_DS)) && !(flags & (1 << MAX_RT))) && timeout < TIMEOUT) {
203                                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
204                                 timeout++;
205                         }
206                         if (flags & (1 << MAX_RT)) {
207                                 ev.type = EV_ERR_MAX_RETRIES;
208                                 si->eh(si, &ev);
209                                 si24_reset(si);
210                                 return bytes_sent;
211                         }
212
213                 } else {
214                         _reg_write(si, SI24_W_TX_PAYLOAD_NO_ACK, buf + idx, sz);
215                         si->ctl->chip_enable(1);
216                         while (!(flags & (1 << TX_DS)) && timeout < TIMEOUT) {
217                                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
218                                 timeout++;
219                         }
220                 }
221
222                 if (timeout >= TIMEOUT) {
223                         ev.type = EV_ERR_TIMEOUT;
224                         si->eh(si, &ev);
225                         si24_reset(si);
226                         return bytes_sent;
227                 }
228
229                 flags |= (1 << TX_DS);
230                 _reg_write(si, SI24_REG_STATUS, &flags, 1);
231                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
232                 bytes_sent += sz;
233                 timeout = 0;
234         }
235
236         ev.type = EV_TX_COMPLETE;
237         si->eh(si, &ev);
238         si->ctl->chip_enable(0);
239
240         return bytes_sent;
241 }
242
243 size_t si24_recv(si24_t* si, unsigned char * buf, size_t size) 
244 {
245         si24_event_t ev;
246         size_t bytes_read = 0;
247         uint8_t p_size = si->opts->payload;
248         uint8_t tmpbuf[p_size];
249         uint8_t flags;
250         uint8_t fifo_flags;
251         
252         if (si->opts->mode == SEND_MODE)
253                 return -1;
254
255         _reg_read(si, SI24_REG_STATUS, &flags, 1);
256
257         if (!(flags & (1 << RX_DR))) {
258                 ev.type = EV_RX_EMPTY;
259                 si->eh(si, &ev);
260                 return bytes_read;
261         }
262
263         /* do not accept any new incoming data */
264         si->opts->ioctl->chip_enable(0);
265
266         _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
267         while(!(fifo_flags & (1 << RX_EMPTY)) &&
268                         bytes_read < size) {
269                 
270                 if (si->opts->enable_dynpd) {
271                         uint8_t d_sz = 0;
272                         _reg_read(si, SI24_RX_PL_WID, &d_sz, 1);
273                         p_size = d_sz;
274                 }
275                 int m_size = (size - bytes_read) > p_size ? p_size : (size - bytes_read);
276                 _reg_read(si, SI24_R_RX_PAYLOAD, tmpbuf, m_size);
277
278                 memcpy(buf + bytes_read, tmpbuf, m_size);
279                 bytes_read += m_size;
280
281                 _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
282         }
283
284         /* only clear data ready flag when FIFO is empty */
285         if (fifo_flags & (1 << RX_EMPTY)) {
286                 flags |= (1 << RX_DR);
287                 _reg_write(si, SI24_REG_STATUS, &flags, 1);
288         }
289         
290         ev.type = EV_RX_COMPLETE;
291         si->eh(si, &ev);
292
293         si->opts->ioctl->chip_enable(1);
294         
295         return bytes_read;
296 }
297
298 void si24_reset(si24_t* si)
299 {
300         if (si->opts->mode == RECV_MODE) {
301                 _reg_write(si, SI24_FLUSH_RX, 0, 0);
302         }
303         else if (si->opts->mode == SEND_MODE) {
304                 _reg_write(si, SI24_FLUSH_TX, 0, 0);
305         }
306
307         uint8_t status_reg = {0};
308         status_reg |= (1 << RX_DR);
309         status_reg |= (1 << TX_DS);
310         status_reg |= (1 << MAX_RT);
311
312         _reg_write(si, SI24_REG_STATUS, (uint8_t *) &status_reg, 1);
313
314         si->ctl->chip_enable(0);
315 }
316
317 void si24_free(si24_t * si)
318 {
319         free(si);
320 }