libsi24: recv mode fifo read changes
[libsi24] / libsi24.c
1 /**
2  * File              : libsi24.c
3  * Author            : Robin Krens <robin@robinkrens.nl>
4  * Date              : 18.01.2023
5  * Last Modified Date: 22.01.2023
6  * Last Modified By  : Robin Krens <robin@robinkrens.nl>
7  */
8
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "libsi24.h"
16 #include "libsi24reg.h"
17
18 #define DEBUG 0
19 #define TIMEOUT 0xFFFF
20
21 struct si24_t {
22         const si24_opts_t *opts;
23         const si24_ioctl_t *ctl;
24         si24_event_handler_t eh;
25 };
26
27 static uint8_t _reg_read(si24_t *si, uint8_t reg,
28                 uint8_t *data, int sz)
29 {
30         uint8_t buf[sz+1];
31         
32         memset(buf, 0, sz+1); 
33         buf[0] = reg | SI24_R_REGISTER;
34
35         
36         if (si->ctl->write_and_read(buf, sz+1) == -1) {
37                 si24_event_t ev;
38                 ev.type = EV_ERR_BUS;
39                 si->eh(si, &ev);
40                 return -1;
41         }
42         
43         memcpy(data, (buf+1), sz);
44         
45         return 0;
46 }
47
48 static uint8_t _reg_write(si24_t *si, uint8_t reg,
49                 const uint8_t *data, int sz)
50 {
51         uint8_t buf[sz+1];
52         
53         buf[0] = reg | SI24_W_REGISTER;
54         memcpy((buf+1), data, sz);
55         
56         if(DEBUG) {
57                 printf("REG 0x%x:\t", reg);
58                 for (int i = 1; i <= sz; ++i) {
59                         fprintf(stdout, "0x%x(%c)", buf[i], buf[i]);
60                 }
61                 fprintf(stdout, "\n");
62         }
63
64         if (si->ctl->write_and_read(buf, sz+1) == -1) {
65                 si24_event_t ev;
66                 ev.type = EV_ERR_BUS;
67                 si->eh(si, &ev);
68                 return -1;
69         }
70
71         return 0;
72 }
73
74 static int _config(si24_t * si)
75 {
76         int ret = 0;
77         uint8_t config_reg = (1 << PWR_UP);
78         uint8_t feature_reg = 0x0; /* default value */
79         uint8_t rf_setup_reg = 0xE; /* default value */
80         uint8_t setup_retr_reg = 0x3; /* default value */
81         const uint8_t rf_ch_reg = 0x40; /* default value */
82         const si24_opts_t * params = si->opts; 
83         
84         if (params->enable_crc) {
85                 config_reg |= (1 << EN_CRC);
86                 config_reg |= (si->opts->crc << CRCO);
87         }
88
89         if (params->enable_ack) {
90                 uint8_t dyn = (1 << DPL_P0);
91                 ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1);
92                 feature_reg |= (1 << EN_DPL);
93                 ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
94                 if (params->mode == SEND_MODE) {
95                         setup_retr_reg = ARD(params->timeout) | ARC(params->retries);
96                         ret += _reg_write(si, SI24_REG_SETUP_RETR, &setup_retr_reg, 1);
97                 }
98         } else {
99                 if (params->mode == SEND_MODE) {
100                         feature_reg |= (1 << EN_DYN_ACK);
101                         ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
102                 }
103         }
104
105         uint8_t aw = AW_5;
106         ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); 
107
108         if (params->mode == SEND_MODE && params->enable_ack) {
109                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
110         }
111         
112         if (params->mode == RECV_MODE) {
113                 config_reg |= (1 << PRIM_RX);
114                 uint8_t ch = 0x1;
115                 ret += _reg_write(si, SI24_REG_EN_RXADDR, &ch, 1); 
116                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, params->mac_addr, sizeof(params->mac_addr));
117                 ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) &params->payload, 1);
118         } else {
119                 ret += _reg_write(si, SI24_REG_TX_ADDR, params->mac_addr, sizeof(params->mac_addr));
120         }
121
122         rf_setup_reg |= (params->speed << RF_DR_HIGH);
123         rf_setup_reg |= (params->txpwr << RF_PWR);
124         ret += _reg_write(si, SI24_REG_RF_SETUP, &rf_setup_reg, 1);
125
126
127         ret += _reg_write(si, SI24_REG_RF_CH, &rf_ch_reg, 1);
128         ret += _reg_write(si, SI24_REG_CONFIG, &config_reg, 1);
129
130         if (params->mode == RECV_MODE) {
131                 /* start accepting data immediately,
132                  * for send mode it is onyl activated upon sending */
133                 params->ioctl->chip_enable(1);
134         }
135
136         return ret;
137 }
138
139 si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh)
140 {
141         struct si24_t *si = (si24_t*) calloc(1, sizeof(si24_t));
142         if (si == 0)
143                 return 0;
144
145         si->opts = opts;
146         si->ctl = opts->ioctl;
147         si->eh = eh;
148
149         int ret = _config(si);
150         if (ret < 0) {
151                 free(si);
152                 return 0;
153         }
154
155         return si;
156 }
157
158 size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
159 {
160         si24_event_t ev;
161         size_t bytes_sent = 0;
162         uint16_t timeout = 0;
163         int sz;
164         uint8_t flags;
165         
166         if (si->opts->mode == RECV_MODE)
167                 return -1;
168
169         _reg_read(si, SI24_REG_STATUS, (uint8_t *) &flags, 1);
170
171         if (flags & (1 << TX_FULL)) {
172                 ev.type = EV_TX_FULL;
173                 si->eh(si, &ev);
174                 return -1;
175         }
176
177         for (size_t idx = 0; idx < size; idx += si->opts->payload) {
178                 sz = (size - idx) < si->opts->payload ? (size - idx) : si->opts->payload;  
179                 if (si->opts->enable_ack) {
180                         _reg_write(si, SI24_W_TX_PAYLOAD, buf + idx, sz);
181                         si->ctl->chip_enable(1);
182                         while ((!(flags & (1 << TX_DS)) && !(flags & (1 << MAX_RT))) && timeout < TIMEOUT) {
183                                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
184                                 timeout++;
185                         }
186                         if (flags & (1 << MAX_RT)) {
187                                 ev.type = EV_ERR_MAX_RETRIES;
188                                 si->eh(si, &ev);
189                                 si24_reset(si);
190                                 return bytes_sent;
191                         }
192
193                 } else {
194                         _reg_write(si, SI24_W_TX_PAYLOAD_NO_ACK, buf + idx, sz);
195                         si->ctl->chip_enable(1);
196                         while (!(flags & (1 << TX_DS)) && timeout < TIMEOUT) {
197                                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
198                                 timeout++;
199                         }
200                 }
201
202                 if (timeout >= TIMEOUT) {
203                         ev.type = EV_ERR_TIMEOUT;
204                         si->eh(si, &ev);
205                         si24_reset(si);
206                         return bytes_sent;
207                 }
208
209                 flags |= (1 << TX_DS);
210                 _reg_write(si, SI24_REG_STATUS, &flags, 1);
211                 _reg_read(si, SI24_REG_STATUS, &flags, 1);
212                 bytes_sent += sz;
213                 timeout = 0;
214         }
215
216         ev.type = EV_TX_COMPLETE;
217         si->eh(si, &ev);
218         si->ctl->chip_enable(0);
219
220         return bytes_sent;
221 }
222
223 size_t si24_recv(si24_t* si, unsigned char * buf, size_t size) 
224 {
225         si24_event_t ev;
226         size_t bytes_read = 0;
227         uint8_t p_size = si->opts->payload;
228         uint8_t tmpbuf[p_size];
229         uint8_t flags;
230         uint8_t fifo_flags;
231         
232         if (si->opts->mode == SEND_MODE)
233                 return -1;
234
235         _reg_read(si, SI24_REG_STATUS, &flags, 1);
236
237         if (!(flags & (1 << RX_DR))) {
238                 ev.type = EV_RX_EMPTY;
239                 si->eh(si, &ev);
240                 return bytes_read;
241         }
242
243         /* do not accept any new incoming data */
244         si->opts->ioctl->chip_enable(0);
245
246         _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
247         while(!(fifo_flags & (1 << RX_EMPTY)) &&
248                         bytes_read < size) {
249                 
250                 int m_size = (size - bytes_read) > p_size ? p_size : (size - bytes_read);
251                 _reg_read(si, SI24_R_RX_PAYLOAD, tmpbuf, m_size);
252
253                 memcpy(buf + bytes_read, tmpbuf, m_size);
254                 bytes_read += m_size;
255
256                 _reg_read(si, SI24_REG_FIFO_SATUS, &fifo_flags, 1);
257         }
258
259         /* only clear data ready flag when FIFO is empty */
260         if (fifo_flags & (1 << RX_EMPTY)) {
261                 flags |= (1 << RX_DR);
262                 _reg_write(si, SI24_REG_STATUS, &flags, 1);
263         }
264         
265         ev.type = EV_RX_COMPLETE;
266         si->eh(si, &ev);
267
268         si->opts->ioctl->chip_enable(1);
269         
270         return bytes_read;
271 }
272
273 void si24_reset(si24_t* si)
274 {
275         if (si->opts->mode == RECV_MODE) {
276                 _reg_write(si, SI24_FLUSH_RX, 0, 0);
277         }
278         else if (si->opts->mode == SEND_MODE) {
279                 _reg_write(si, SI24_FLUSH_TX, 0, 0);
280         }
281
282         uint8_t status_reg = {0};
283         status_reg |= (1 << RX_DR);
284         status_reg |= (1 << TX_DS);
285         status_reg |= (1 << MAX_RT);
286
287         _reg_write(si, SI24_REG_STATUS, (uint8_t *) &status_reg, 1);
288
289         si->ctl->chip_enable(0);
290 }
291
292 void si24_free(si24_t * si)
293 {
294         free(si);
295 }
296
297 /* hardware linkage */
298 int spi_w_r(unsigned char *data, size_t sz)
299 {
300         if (sz >= 2)
301                 data[1] = (1 << RX_DR);
302         return sz;
303 }
304
305 void ce(unsigned val)
306 {
307         (void) val;
308 }
309
310 void eh(si24_t *si, si24_event_t * e)
311 {
312         (void) si;
313
314         switch(e->type) {
315                 case EV_TX_COMPLETE:
316                         printf("SENT SUCCESFUL\n");
317                         break;
318                 case EV_RX_COMPLETE:
319                         printf("RECV COMPLETE\n");
320                         break;
321                 case EV_RX_EMPTY:
322                         printf("NO NEW DATA\n");
323                         break;
324                 case EV_ERR_TIMEOUT:
325                         printf("TIMEOUT\n");
326                         break;
327                 default:
328                         printf("EVENT: %x\n", e->type);
329                         break;
330         }
331 }
332
333 int main(void)
334 {
335         /* const unsigned char buf[] = "THIS IS A WIRELESS TEST MESSAGE!";*/
336         unsigned char recv_buf[29];
337
338         si24_ioctl_t ctl = {
339                 .write_and_read = spi_w_r,
340                 .chip_enable = ce,
341         };
342
343         const si24_opts_t opts = {
344                 .mode = RECV_MODE,
345                 .enable_ack = 1,
346                 .non_blocking = 0,
347                 .enable_crc = 1,
348                 .enable_dynpd = 1,
349                 .crc = TWO_BYTE,
350                 .ioctl = &ctl,
351                 .speed = MBPS2,
352                 .txpwr = PLUS4DB,
353                 .payload = 5,
354                 .timeout = 1,
355                 .retries = 5,
356                 .mac_addr = 0xAAAAAAAAAA
357         };
358
359         struct si24_t * si = si24_init(&opts, eh);
360         /* si24_send(si, buf, sizeof(buf)); */
361         printf("READ: %ld\n", si24_recv(si, recv_buf, sizeof(recv_buf)));
362         
363 }