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