1 /*
2  * Copyright 2018 Oticon A/S
3  * Copyright 2024 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #include "bs_pc_2G4_types.h"
8 #include "bs_pc_2G4.h"
9 #include "bs_pc_2G4_priv.h"
10 #include "bs_tracing.h"
11 
p2G4_dev_initcom_s_c(p2G4_dev_state_s_t * p2G4_dev_state,unsigned int dev_nbr,const char * s,const char * p,dev_abort_reeval_f abort_fptr)12 int p2G4_dev_initcom_s_c(p2G4_dev_state_s_t *p2G4_dev_state, unsigned int dev_nbr,
13                          const char* s, const char* p, dev_abort_reeval_f abort_fptr) {
14   p2G4_dev_state->abort_f = abort_fptr;
15   return pb_dev_init_com(&p2G4_dev_state->pb_dev_state, dev_nbr, s, p);
16 }
17 
18 /**
19  * Attempt to terminate the simulation
20  */
p2G4_dev_terminate_s_c(p2G4_dev_state_s_t * p2G4_dev_state)21 void p2G4_dev_terminate_s_c(p2G4_dev_state_s_t *p2G4_dev_state){
22   pb_dev_terminate(&p2G4_dev_state->pb_dev_state);
23 }
24 
25 /**
26  * Disconnect from the phy
27  */
p2G4_dev_disconnect_s_c(p2G4_dev_state_s_t * p2G4_dev_state)28 void p2G4_dev_disconnect_s_c(p2G4_dev_state_s_t *p2G4_dev_state){
29   pb_dev_disconnect(&p2G4_dev_state->pb_dev_state);
30 }
31 
32 /**
33  * The phy has just asked us to reevaluate the abort => call the device
34  * function which will give us a new abort structure and give it back to the
35  * phy.
36  * The device may have problems to do so, in that case we send a disconnect
37  * to the phy and we return from this function -1
38  */
p2G4_dev_do_abort_reeval_s(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_abort_t * abort_s)39 static int p2G4_dev_do_abort_reeval_s(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_abort_t *abort_s) {
40 
41   if (p2G4_dev_state->abort_f != NULL) {
42     if (p2G4_dev_state->abort_f(abort_s) != 0) {
43       bs_trace_warning_line("We (device) are dying in the middle of abort reevaluation!!\n");
44       pb_dev_disconnect(&p2G4_dev_state->pb_dev_state);
45       return -1;
46     }
47   } else {
48     bs_trace_warning_line("The phy wants to reevaluate an abort but the "
49        "device did not register an abort reevaluation call back => I try to "
50        "handle it by responding with recheck set to infinite time and leaving "
51        "abort as it was\n");
52     abort_s->recheck_time = TIME_NEVER;
53   }
54 
55   pb_send_msg(p2G4_dev_state->pb_dev_state.ff_dtp, P2G4_MSG_RERESP_ABORTREEVAL,
56               (void *)abort_s, sizeof(p2G4_abort_t));
57 
58   return 0;
59 }
60 
get_resp_while_handling_abortreeval_s(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_abort_t * abort)61 static pc_header_t get_resp_while_handling_abortreeval_s(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_abort_t *abort) {
62   pc_header_t header;
63   while (1) {
64     int ret;
65     ret = pb_dev_read(&p2G4_dev_state->pb_dev_state, &header, sizeof(header));
66     if (ret == -1)
67         return -1;
68 
69     if (header == P2G4_MSG_ABORTREEVAL) { //while the phy answers us with abort reevaluations we handle them and wait for new responses
70       ret = p2G4_dev_do_abort_reeval_s(p2G4_dev_state, abort);
71       if (ret == -1)
72           return -1;
73     } else {
74       break;
75     }
76   }
77   return header;
78 }
79 
80 /**
81  * Request a transmissions to the phy
82  *
83  * returns -1 on error, 0 otherwise
84  */
p2G4_dev_req_tx_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_tx_t * tx_s,uint8_t * packet,p2G4_tx_done_t * tx_done_s)85 int p2G4_dev_req_tx_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_tx_t *tx_s, uint8_t *packet, p2G4_tx_done_t *tx_done_s)
86 {
87   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
88   int ret;
89   pc_header_t header;
90 
91   p2G4_dev_req_tx_i(&p2G4_dev_state->pb_dev_state, tx_s, packet);
92 
93   header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &tx_s->abort);
94 
95   ret = p2G4_dev_handle_tx_resp_i(&p2G4_dev_state->pb_dev_state, header,
96                                   tx_done_s);
97   return ret;
98 }
99 
100 /**
101  * Request a transmissions to the phy
102  *
103  * returns -1 on error, 0 otherwise
104  */
p2G4_dev_req_txv2_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_txv2_t * tx_s,uint8_t * packet,p2G4_tx_done_t * tx_done_s)105 int p2G4_dev_req_txv2_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_txv2_t *tx_s, uint8_t *packet, p2G4_tx_done_t *tx_done_s)
106 {
107   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
108   int ret;
109   pc_header_t header;
110 
111   p2G4_dev_req_txv2_i(&p2G4_dev_state->pb_dev_state, tx_s, packet);
112 
113   header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &tx_s->abort);
114 
115   ret = p2G4_dev_handle_tx_resp_i(&p2G4_dev_state->pb_dev_state, header,
116                                   tx_done_s);
117   return ret;
118 }
119 
120 /**
121  * Request a transmissions to the phy
122  *
123  * returns -1 on error, 0 otherwise
124  *
125  * It does not wait for a response, p2G4_dev_pick_txresp_s_c_b() should be called after
126  */
p2G4_dev_req_tx_s_c(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_tx_t * tx_s,uint8_t * packet)127 int p2G4_dev_req_tx_s_c(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_tx_t *tx_s, uint8_t *packet) {
128   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
129   p2G4_dev_req_tx_i(&p2G4_dev_state->pb_dev_state, tx_s, packet);
130   return 0;
131 }
132 
133 /**
134  * Request a transmissions to the phy
135  *
136  * returns -1 on error, 0 otherwise
137  *
138  * It does not wait for a response, p2G4_dev_pick_txresp_s_c_b() should be called after
139  */
p2G4_dev_req_txv2_s_c(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_txv2_t * tx_s,uint8_t * packet)140 int p2G4_dev_req_txv2_s_c(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_txv2_t *tx_s, uint8_t *packet) {
141   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
142   p2G4_dev_req_txv2_i(&p2G4_dev_state->pb_dev_state, tx_s, packet);
143   return 0;
144 }
145 
146 /**
147  * Pickup a tx response (This function is meant only for devices which use p2G4_dev_req_tx_s_c()
148  * or p2G4_dev_req_txv2_s_c()
149  * Note that this function canNOT handle abort reevaluations.
150  * (if those are expected they should have been handled before, or with a different function)
151  *
152  * returns -1 on error, 0 otherwise
153  */
p2G4_dev_pick_txresp_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_tx_done_t * tx_done_s)154 int p2G4_dev_pick_txresp_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_tx_done_t *tx_done_s) {
155   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
156   int ret = p2G4_dev_get_tx_resp_i(&p2G4_dev_state->pb_dev_state, tx_done_s);
157   return ret;
158 }
159 
160 /**
161  * Request a (v1) reception to the phy
162  *
163  * rx_done_s needs to be allocated by the caller
164  *
165  * rx_buf is a pointer to a buffer in which the packet will be copied.
166  * This buffer shall have buf_size bytes.
167  * If buf_size is 0, this function will allocate a new buffer and point
168  *  *rx_buf to it (the application must free it afterwards).
169  * Otherwise this function will fail if the buffer is too small to fit
170  * the incoming packet
171  *
172  * dev_rxeval_f is a function which will be called when receiving the packet.
173  * If the device will accept any packet (quite normal behavior), set this to
174  * NULL.
175  * dev_rxeval_f() shall return 1, if it accepts the packet, 0 otherwise
176  *
177  * returns -1 on error, the received response header >=0 otherwise
178  */
p2G4_dev_req_rx_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_rx_t * rx_s,p2G4_rx_done_t * rx_done_s,uint8_t ** rx_buf,size_t buf_size,device_eval_rx_f dev_rxeval_f)179 int p2G4_dev_req_rx_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_rx_t *rx_s,
180                           p2G4_rx_done_t *rx_done_s, uint8_t **rx_buf,
181                           size_t buf_size, device_eval_rx_f dev_rxeval_f) {
182 
183   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
184 
185   pb_send_msg(p2G4_dev_state->pb_dev_state.ff_dtp,
186               P2G4_MSG_RX, (void *)rx_s, sizeof(p2G4_rx_t));
187 
188   pc_header_t r_header;
189   r_header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &rx_s->abort);
190 
191   if (r_header == P2G4_MSG_RX_ADDRESSFOUND) {
192     int ret;
193 
194     ret = pb_dev_read(&p2G4_dev_state->pb_dev_state,
195                       rx_done_s, sizeof(p2G4_rx_done_t));
196     if (ret == -1)
197       return -1;
198 
199     ret = p2G4_rx_pick_packet(&p2G4_dev_state->pb_dev_state,
200                               rx_done_s->packet_size, rx_buf, buf_size);
201     if (ret)
202       return ret;
203 
204     int accept_packet = true;
205     if (dev_rxeval_f != NULL) {
206       accept_packet = dev_rxeval_f(rx_done_s, *rx_buf);
207     }
208     pc_header_t header;
209     if (accept_packet == true) {
210       header = P2G4_MSG_RXCONT;
211     } else {
212       header = P2G4_MSG_RXSTOP;
213     }
214     write(p2G4_dev_state->pb_dev_state.ff_dtp, &header, sizeof(header));
215 
216     if (accept_packet != true) {
217       return r_header;
218     }
219 
220     r_header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &rx_s->abort);
221   }
222 
223   if (r_header == PB_MSG_DISCONNECT) {
224     pb_dev_clean_up(&p2G4_dev_state->pb_dev_state);
225     return -1;
226   } else if (r_header == P2G4_MSG_RX_END) {
227     if (pb_dev_read(&p2G4_dev_state->pb_dev_state, rx_done_s, sizeof(p2G4_rx_done_t)) == -1) {
228       return -1;
229     }
230   } else {
231     INVALID_RESP(r_header);
232   }
233   return r_header;
234 }
235 
236 /**
237  * Request a (v2) reception to the phy
238  *
239  * rx_done_s needs to be allocated by the caller
240  *
241  * rx_buf is a pointer to a buffer in which the packet will be copied.
242  * This buffer shall have buf_size bytes.
243  * If buf_size is 0, this function will allocate a new buffer and point
244  *  *rx_buf to it (the application must free it afterwards).
245  * Otherwise this function will fail if the buffer is too small to fit
246  * the incoming packet
247  *
248  * dev_rxeval_f is a function which will be called when receiving the packet.
249  * If the device will accept any packet (quite normal behavior), set this to
250  * NULL.
251  * dev_rxeval_f() shall return 1, if it accepts the packet, 0 otherwise
252  *
253  * returns -1 on error, the received response header >=0 otherwise
254  */
p2G4_dev_req_rxv2_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_rxv2_t * rx_s,p2G4_address_t * phy_addr,p2G4_rxv2_done_t * rx_done_s,uint8_t ** rx_buf,size_t buf_size,device_eval_rxv2_f dev_rxeval_f)255 int p2G4_dev_req_rxv2_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_rxv2_t *rx_s,
256                           p2G4_address_t *phy_addr,
257                           p2G4_rxv2_done_t *rx_done_s, uint8_t **rx_buf,
258                           size_t buf_size, device_eval_rxv2_f dev_rxeval_f) {
259 
260   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
261 
262   pb_send_msg(p2G4_dev_state->pb_dev_state.ff_dtp,
263               P2G4_MSG_RXV2, (void *)rx_s, sizeof(p2G4_rxv2_t));
264   if (rx_s->n_addr > 0) {
265     write(p2G4_dev_state->pb_dev_state.ff_dtp, phy_addr, sizeof(p2G4_address_t)*rx_s->n_addr);
266   }
267 
268   pc_header_t r_header;
269   r_header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &rx_s->abort);
270 
271   if (r_header == P2G4_MSG_RXV2_ADDRESSFOUND) {
272     int ret;
273 
274     ret = pb_dev_read(&p2G4_dev_state->pb_dev_state,
275                       rx_done_s, sizeof(p2G4_rxv2_done_t));
276     if (ret == -1)
277       return -1;
278 
279     ret = p2G4_rx_pick_packet(&p2G4_dev_state->pb_dev_state,
280                               rx_done_s->packet_size, rx_buf, buf_size);
281     if (ret)
282       return ret;
283 
284     int accept_packet = true;
285     if (dev_rxeval_f != NULL) {
286       accept_packet = dev_rxeval_f(rx_done_s, *rx_buf);
287     }
288     pc_header_t header;
289     if (accept_packet == true) {
290       header = P2G4_MSG_RXCONT;
291     } else {
292       header = P2G4_MSG_RXSTOP;
293     }
294     write(p2G4_dev_state->pb_dev_state.ff_dtp, &header, sizeof(header));
295 
296     if (accept_packet != true) {
297       return r_header;
298     }
299 
300     r_header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &rx_s->abort);
301   }
302 
303   if (r_header == PB_MSG_DISCONNECT) {
304     pb_dev_clean_up(&p2G4_dev_state->pb_dev_state);
305     return -1;
306   } else if (r_header == P2G4_MSG_RXV2_END) {
307     if (pb_dev_read(&p2G4_dev_state->pb_dev_state, rx_done_s, sizeof(p2G4_rxv2_done_t)) == -1) {
308       return -1;
309     }
310   } else {
311     INVALID_RESP(r_header);
312   }
313   return r_header;
314 }
315 
316 /**
317  * Request a RSSI measurement to the phy
318  * RSSI_done_s needs to be allocated by the caller
319  *
320  * returns -1 if disconnected, 0 otherwise
321  */
p2G4_dev_req_RSSI_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_rssi_t * RSSI_s,p2G4_rssi_done_t * RSSI_done_s)322 int p2G4_dev_req_RSSI_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state,
323                             p2G4_rssi_t *RSSI_s, p2G4_rssi_done_t *RSSI_done_s)
324 {
325   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
326   pb_send_msg(p2G4_dev_state->pb_dev_state.ff_dtp,
327               P2G4_MSG_RSSIMEAS, (void *)RSSI_s, sizeof(p2G4_rssi_t));
328   return p2G4_dev_get_rssi_resp_i(&p2G4_dev_state->pb_dev_state, RSSI_done_s);
329 }
330 
331 /**
332  * Request a CCA measurement to the phy
333  * cca_done_s needs to be allocated by the caller
334  *
335  * returns -1 if disconnected, 0 otherwise
336  */
p2G4_dev_req_cca_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,p2G4_cca_t * cca_s,p2G4_cca_done_t * cca_done_s)337 int p2G4_dev_req_cca_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, p2G4_cca_t *cca_s, p2G4_cca_done_t *cca_done_s)
338 {
339   CHECK_CONNECTED(p2G4_dev_state->pb_dev_state.connected);
340   p2G4_dev_req_cca_i(&p2G4_dev_state->pb_dev_state, cca_s);
341 
342   pc_header_t r_header;
343   r_header = get_resp_while_handling_abortreeval_s(p2G4_dev_state, &cca_s->abort);
344 
345   return p2G4_dev_handle_cca_resp_i(&p2G4_dev_state->pb_dev_state, r_header, cca_done_s);
346 }
347 
348 /**
349  * Request a wait to the phy and block until receiving the response
350  * If everything goes ok 0 is returned
351  *
352  * Otherwise, we should disconnect (-1 will be returned)
353  */
p2G4_dev_req_wait_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state,pb_wait_t * wait_s)354 int p2G4_dev_req_wait_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state, pb_wait_t *wait_s){
355   return pb_dev_request_wait_block(&p2G4_dev_state->pb_dev_state, wait_s);
356 }
357 
358 
359 /**
360  * Request a non blocking wait to the phy
361  * Note that eventually the caller needs to pick the wait response
362  * from the phy with p2G4_dev_pick_wait_resp_s_c_b()
363  */
p2G4_dev_req_wait_s_c(p2G4_dev_state_s_t * p2G4_dev_state,pb_wait_t * wait_s)364 int p2G4_dev_req_wait_s_c(p2G4_dev_state_s_t *p2G4_dev_state, pb_wait_t *wait_s){
365   return pb_dev_request_wait_nonblock(&p2G4_dev_state->pb_dev_state, wait_s);
366 }
367 
368 /**
369  * Block until getting a wait response from the phy
370  * If everything goes ok, the phy has just reached the
371  * requested end time and 0 is returned
372  * Otherwise, we should disconnect (-1 will be returned)
373  */
p2G4_dev_pick_wait_resp_s_c_b(p2G4_dev_state_s_t * p2G4_dev_state)374 int p2G4_dev_pick_wait_resp_s_c_b(p2G4_dev_state_s_t *p2G4_dev_state){
375   return pb_dev_pick_wait_resp(&p2G4_dev_state->pb_dev_state);
376 }
377