libsi24: config and send functionality
[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 struct si24_t {
19         const si24_opts_t *opts;
20         const si24_ioctl_t *ctl;
21         si24_event_handler_t eh;
22         si24_status_reg_t sr;
23 };
24
25 static uint8_t _reg_read(si24_t *si, uint8_t reg,
26                 uint8_t *data, int sz)
27 {
28         uint8_t buf[sz+1];
29         
30         memset(buf, 0, sz+1); 
31         buf[0] = reg | SI24_R_REGISTER;
32         
33         if (si->ctl->write_and_read(buf, sz+1) == -1) {
34                 si24_event_t ev;
35                 ev.type = EV_ERR_BUS;
36                 si->eh(si, &ev);
37                 return -1;
38         }
39         
40         memcpy(data, (buf+1), sz);
41         
42         return 0;
43 }
44
45 static uint8_t _reg_write(si24_t *si, uint8_t reg,
46                 const uint8_t *data, int sz)
47 {
48         uint8_t buf[sz+1];
49         
50         buf[0] = reg | SI24_W_REGISTER;
51         memcpy((buf+1), data, sz);
52
53         if (si->ctl->write_and_read(buf, sz+1) == -1) {
54                 si24_event_t ev;
55                 ev.type = EV_ERR_BUS;
56                 si->eh(si, &ev);
57                 return -1;
58         }
59
60         return 0;
61 }
62
63 static int _config(si24_t * si)
64 {
65         int ret = 0;
66         uint8_t config_reg = (1 << PWR_UP);
67         uint8_t feature_reg = 0x2; /* default value */
68         uint8_t rf_setup_reg = 0xE; /* default value */
69         uint8_t setup_retr_reg = 0x3; /* default value */
70         const uint8_t rf_ch_reg = 0x40; /* default value */
71         const si24_opts_t * params = si->opts; 
72         
73         if (params->enable_crc) {
74                 config_reg |= (1 << EN_CRC);
75                 config_reg |= (si->opts->crc << CRCO);
76         }
77
78         if (params->enable_ack) {
79                 uint8_t dyn = (1 << DPL_P0);
80                 ret += _reg_write(si, SI24_REG_DYNPD, &dyn, 1);
81                 feature_reg |= (1 << EN_DYN_ACK);
82                 ret += _reg_write(si, SI24_REG_FEATURE, &feature_reg, 1);
83         }
84
85         uint8_t aw;
86         if (params->mac_addr & 0xF0000) {
87                 aw = AW_5;
88                 ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); 
89         } else if (params->mac_addr & 0xF000) {
90                 aw = AW_4;
91                 ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); 
92         } else {
93                 aw = AW_3;
94                 ret += _reg_write(si, SI24_REG_SETUP_AW, &aw, 1); 
95         }
96
97         if (params->mode == SEND_MODE && params->enable_ack) {
98                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, (uint8_t *) &params->mac_addr, aw);
99         }
100         
101         if (params->mode == RECV_MODE) {
102                 config_reg |= (1 << PRIM_RX);
103                 uint8_t ch = 0x1;
104                 ret += _reg_write(si, SI24_REG_EN_RXADDR, &ch, 1); 
105                 ret += _reg_write(si, SI24_REG_RX_ADDR_P0, (uint8_t *) &params->mac_addr, aw);
106                 ret += _reg_write(si, SI24_REG_RX_PW_P0, (uint8_t *) &params->payload, 1);
107         } else {
108                 ret += _reg_write(si, SI24_REG_TX_ADDR, (uint8_t *) &params->mac_addr, aw);
109         }
110
111         rf_setup_reg |= (params->speed << RF_DR_HIGH);
112         rf_setup_reg |= (params->txpwr << RF_PWR);
113         ret += _reg_write(si, SI24_REG_RF_SETUP, &rf_setup_reg, 1);
114
115         setup_retr_reg = ARD(params->timeout) | ARC(params->retries);
116         ret += _reg_write(si, SI24_REG_SETUP_RETR, &setup_retr_reg, 1);
117
118         ret += _reg_write(si, SI24_REG_RF_CH, &rf_ch_reg, 1);
119         ret += _reg_write(si, SI24_REG_CONFIG, &config_reg, 1);
120
121         return ret;
122 }
123
124 si24_t* si24_init(const si24_opts_t *opts, si24_event_handler_t eh)
125 {
126         struct si24_t *si = (si24_t*) calloc(1, sizeof(si24_t));
127         if (si == 0)
128                 return 0;
129
130         si->opts = opts;
131         si->ctl = opts->ioctl;
132         si->eh = eh;
133
134         int ret = _config(si);
135         if (ret < 0) {
136                 free(si);
137                 return 0;
138         }
139
140         return si;
141 }
142
143 size_t si24_send(si24_t* si, const unsigned char * buf, size_t size)
144 {
145         si24_event_t ev;
146         uint16_t timeout = 0;
147         int sz;
148         si24_status_reg_t flags;
149
150         if (si->opts->mode == RECV_MODE)
151                 return -1;
152
153         _reg_read(si, 0x7, (uint8_t *) &flags, 1);
154
155         if (flags.bits.TX_FULL) {
156                 ev.type = EV_TX_FULL;
157                 si->eh(si, &ev);
158                 return -1;
159         }
160
161         for (size_t idx = 0; idx < size; idx += si->opts->payload) {
162                 sz = (size - idx) < si->opts->payload ? (size - idx) : si->opts->payload;  
163                 if (si->opts->enable_ack) {
164                         _reg_write(si, SI24_W_TX_PAYLOAD, buf, sz);
165                         while ((!flags.bits.TX_DS || !flags.bits.MAX_RT) && timeout < 1000) {
166                                 _reg_read(si, SI24_REG_STATUS, (uint8_t []){0x0}, 1);
167                                 timeout++;
168                         }
169                         if (flags.bits.MAX_RT) {
170                                 ev.type = EV_ERR_MAX_RETRIES;
171                                 si->eh(si, &ev);
172                                 si24_reset(si);
173                                 return -1;
174                         }
175
176                 } else {
177                         _reg_write(si, SI24_W_TX_PAYLOAD_NO_ACK, buf, sz);
178                         si->ctl->chip_enable(1);
179                         while (!flags.bits.TX_DS && timeout < 1000) {
180                                 _reg_read(si, SI24_REG_STATUS, (uint8_t []){0x0}, 1);
181                                 timeout++;
182                         }
183                 }
184
185                 if (timeout >= 1000) {
186                         ev.type = EV_ERR_TIMEOUT;
187                         si->eh(si, &ev);
188                         si24_reset(si);
189                         return -1;
190                 }
191                 timeout = 0;
192         }
193         
194         si->ctl->chip_enable(0);
195
196         return 0;
197 }
198
199 size_t si24_recv(si24_t* si, unsigned char * buf, size_t size) 
200 {
201         (void) buf;
202         (void) size;
203         if (si->opts->mode == SEND_MODE)
204                 return -1;
205         
206         si24_status_reg_t flags;
207         _reg_read(si, 0x7, (uint8_t *) &flags, 1);
208         
209         if (!flags.bits.RX_DR)
210                 return -1;
211
212         return 0;
213 }
214
215 void si24_reset(si24_t* si)
216 {
217         si->ctl->chip_enable(0);
218 }
219
220 void si24_free(si24_t * si)
221 {
222         free(si);
223 }
224
225 int main(void)
226 {
227 }