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