1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <math.h>
10 #include "bs_tracing.h"
11 #include "bs_oswrap.h"
12 #include "bs_utils.h"
13 #include "bs_pc_2G4.h"
14 #include "bs_pc_2G4_utils.h"
15 #include "bs_rand_main.h"
16 #include "p2G4_args.h"
17 #include "p2G4_channel_and_modem.h"
18 #include "p2G4_dump.h"
19 #include "p2G4_func_queue.h"
20 #include "p2G4_pending_tx_rx_list.h"
21 #include "p2G4_com.h"
22 #include "p2G4_v1_v2_remap.h"
23 
24 static bs_time_t current_time = 0;
25 static int nbr_active_devs; //How many devices are still active (devices may disconnect during the simulation)
26 extern tx_l_c_t tx_l_c; //list of all transmissions
27 static p2G4_rssi_t *RSSI_a; //array of all RSSI measurements
28 static rx_status_t *rx_a; //array of all receptions
29 static cca_status_t *cca_a; //array of all "compatible" searches
30 static p2G4_args_t args;
31 
32 static void p2G4_handle_next_request(uint d);
33 
f_wait_done(uint d)34 static void f_wait_done(uint d){
35   bs_trace_raw_time(8,"Device %u - Wait done\n", d);
36   p2G4_phy_resp_wait(d);
37   p2G4_handle_next_request(d);
38 }
39 
f_tx_end(uint d)40 static void f_tx_end(uint d){
41 
42   tx_el_t* tx_el;
43   p2G4_tx_done_t tx_done_s;
44 
45   tx_el = &tx_l_c.tx_list[d];
46   if ( tx_el->tx_s.abort.abort_time < tx_el->tx_s.end_tx_time ) {
47     bs_trace_raw_time(8,"Device %u - Tx done (Tx aborted)\n", d);
48   } else {
49     bs_trace_raw_time(8,"Device %u - Tx done (Tx ended)\n", d);
50   }
51 
52   dump_tx(tx_el, d);
53 
54   txl_clear(d);
55 
56   tx_done_s.end_time = current_time;
57   p2G4_phy_resp_tx(d, &tx_done_s);
58   p2G4_handle_next_request(d);
59 }
60 
61 
pick_abort_tail(uint d,p2G4_abort_t * ab,const char * type)62 static int pick_abort_tail(uint d, p2G4_abort_t *ab, const char* type) {
63   if ( current_time > ab->abort_time ){
64     bs_trace_error_time_line("Device %u requested %s abort in %"PRItime" which has passed\n", d, type, ab->abort_time);
65   }
66   if ( current_time > ab->recheck_time ){ //we allow to recheck just now
67     bs_trace_error_time_line("Device %u requested %s abort recheck in %"PRItime" which has passed\n", d, type, ab->recheck_time);
68   }
69   if ( current_time == ab->recheck_time ){
70     bs_trace_raw_time(4,"Device %u - Note: Abort reevaluation in same time (possible infinite loop in device?)\n", d);
71     /* In this case it may be better to call here pick_and_validate_abort() recursively
72      * As some states may not handle too gracefully this case and still advance 1 microsecond */
73   }
74 
75   bs_trace_raw_time(8,"Device %u (%s) requested to reschedule abort,recheck at %"PRItime ",%"PRItime ")\n",
76                     d, type, ab->abort_time, ab->recheck_time);
77 
78   return 0;
79 }
80 /*
81  * Pick abort from device.
82  * If something goes wrong it returns != 0, and the simulation shall be terminated
83  */
pick_and_validate_abort(uint d,p2G4_abort_t * ab,const char * type)84 static int pick_and_validate_abort(uint d, p2G4_abort_t *ab, const char* type) {
85   int ret;
86 
87   bs_trace_raw_time(8,"Device %u - Reevaluating %s abort\n", d, type);
88 
89   do {
90     ret = p2G4_phy_get_new_abort(d, ab);
91     if ( ret == PB_MSG_TERMINATE) {
92       bs_trace_raw_time(4,"Device %u terminated the simulation (there was %i left)\n", d, nbr_active_devs-1);
93       nbr_active_devs = 0;
94       return 1;
95     } else if ( ret == P2G4_MSG_RERESP_IMMRSSI ) {
96       p2G4_rssi_t rssi_req;
97       p2G4_rssi_done_t rssi_resp;
98 
99       p2G4_phy_get(d, &rssi_req, sizeof(rssi_req));
100       chm_RSSImeas(&tx_l_c, rssi_req.antenna_gain, &rssi_req.radio_params, &rssi_resp, d, current_time);
101       p2G4_phy_resp_IMRSSI(d, &rssi_resp);
102     }
103   } while (ret != 0);
104 
105   return pick_abort_tail(d, ab, type);
106 }
107 
108 /*
109  * Pick abort from device after RXV2CONT (during header evaluation)
110  * If something goes wrong it returns != 0, and the simulation shall be terminated
111  */
pick_and_validate_abort_Rxcont(uint d,p2G4_abort_t * ab)112 static int pick_and_validate_abort_Rxcont(uint d, p2G4_abort_t *ab) {
113 
114   bs_trace_raw_time(8,"Device %u - Picking abort during header eval\n", d);
115 
116   p2G4_phy_get_abort_struct(d, ab);
117 
118   return pick_abort_tail(d, ab, "Rx header");
119 }
120 
121 /**
122  * Check if this Tx and Rx match
123  * and return true if found, false otherwise
124  */
tx_and_rx_match(const p2G4_txv2_t * tx_s,rx_status_t * rx_st)125 static bool tx_and_rx_match(const p2G4_txv2_t *tx_s, rx_status_t *rx_st)
126 {
127   if ((tx_s->radio_params.center_freq == rx_st->rx_s.radio_params.center_freq) &&
128      (tx_s->radio_params.modulation & P2G4_MOD_SIMILAR_MASK) ==
129          (rx_st->rx_s.radio_params.modulation & P2G4_MOD_SIMILAR_MASK) )
130   {
131     bs_time_t chopped_preamble = current_time - tx_s->start_packet_time; /*microseconds of preamble not transmitted */
132 
133     if (chopped_preamble > rx_st->rx_s.acceptable_pre_truncation) {
134       return false; //we already lost too much preamble, we can't sync
135     }
136 
137     /* Let's check if it is any of the addresses the Rx searches for */
138     p2G4_address_t *rx_addr = rx_st->phy_address;
139     p2G4_address_t tx_addr = tx_s->phy_address;
140 
141     for (int i = 0; i < rx_st->rx_s.n_addr; i++) {
142       if ( tx_addr == rx_addr[i] ) {
143         return true;
144       }
145     }
146   }
147 
148   return false;
149 }
150 
151 /**
152  * All devices which may be able to receive this transmission are moved
153  * to the Rx_Found state, where they may start synchronizing to it
154  */
find_and_activate_rx(const p2G4_txv2_t * tx_s,uint tx_d)155 static void find_and_activate_rx(const p2G4_txv2_t *tx_s, uint tx_d) {
156   for (int rx_d = 0 ; rx_d < args.n_devs; rx_d++) {
157     rx_status_t *rx_s = &rx_a[rx_d];
158     if ( rx_s->state == Rx_State_Searching &&
159         tx_and_rx_match(tx_s, rx_s) ) {
160       rx_s->tx_nbr = tx_d;
161       rx_s->state = Rx_State_NotSearching;
162       fq_add(current_time, Rx_Found, rx_d);
163     }
164   }
165 }
166 
tx_start_packet_common(p2G4_txv2_t * tx_s,uint d)167 static void tx_start_packet_common(p2G4_txv2_t* tx_s, uint d){
168   txl_start_packet(d);
169   bs_trace_raw_time(8,"Device %u - Tx packet start\n", d);
170   find_and_activate_rx(tx_s, d);
171 }
172 
tx_schedule_next_event(p2G4_txv2_t * tx_s,uint d)173 static void tx_schedule_next_event(p2G4_txv2_t* tx_s, uint d){
174   bs_time_t TxEndt, NextTime;
175   bs_time_t Packet_start_time;
176   bs_time_t Packet_end_time = TIME_NEVER; /*Must be later than Packet_start_time*/
177 
178   if ( (tx_l_c.used[d] & TXS_PACKET_ONGOING) == 0){
179     Packet_start_time = tx_s->start_packet_time;
180   } else {
181     /* Packet already started => no need to schedule another start */
182     Packet_start_time = TIME_NEVER;
183 
184     if (tx_l_c.used[d] & TXS_PACKET_ENDED){
185       /* Packet already ended */
186       Packet_end_time = TIME_NEVER;
187     } else {
188       Packet_end_time = tx_s->end_packet_time;
189     }
190   }
191 
192   TxEndt = BS_MIN(tx_s->end_tx_time, tx_s->abort.abort_time);
193   NextTime = BS_MIN(BS_MIN(Packet_start_time, TxEndt),Packet_end_time);
194 
195   if ( NextTime >= tx_s->abort.recheck_time ){
196     fq_add(tx_s->abort.recheck_time, Tx_Abort_Reeval, d);
197   } else if ( NextTime == Packet_start_time ) {
198     fq_add(TxEndt, Tx_Packet_Start, d);
199   } else if ( NextTime == TxEndt ) {
200     // If end_packet_time and end_tx_time are the same we just end
201     fq_add(TxEndt, Tx_End, d);
202   } else {
203     fq_add(TxEndt, Tx_Packet_End, d);
204   }
205 }
206 
f_tx_start(uint d)207 static void f_tx_start(uint d) {
208   p2G4_txv2_t* tx_s;
209   tx_s = &tx_l_c.tx_list[d].tx_s;
210 
211   txl_start_tx(d);
212   bs_trace_raw_time(8,"Device %u - Tx start\n", d);
213 
214   if ( current_time >= tx_s->start_packet_time) {
215     tx_start_packet_common(tx_s, d);
216     /* Technically we could let another event be scheduled,
217      * but this saves a bit of time for the most common scenario */
218   }
219 
220   tx_schedule_next_event(tx_s, d);
221 }
222 
f_tx_abort_reeval(uint d)223 static void f_tx_abort_reeval(uint d){
224   p2G4_txv2_t* tx_s;
225 
226   tx_s = &tx_l_c.tx_list[d].tx_s;
227 
228   if (pick_and_validate_abort(d, &(tx_s->abort), "Tx"))
229     return;
230 
231   tx_schedule_next_event(tx_s, d);
232 }
233 
f_tx_packet_start(uint d)234 static void f_tx_packet_start(uint d){
235   p2G4_txv2_t* tx_s;
236   tx_s = &tx_l_c.tx_list[d].tx_s;
237 
238   tx_start_packet_common(tx_s, d);
239   tx_schedule_next_event(tx_s, d);
240 }
241 
f_tx_packet_end(uint d)242 static void f_tx_packet_end(uint d){
243   p2G4_txv2_t* tx_s;
244   tx_s = &tx_l_c.tx_list[d].tx_s;
245 
246   bs_trace_raw_time(8,"Device %u - Tx packet end\n", d);
247   txl_end_packet(d);
248   tx_schedule_next_event(tx_s, d);
249 }
250 
251 
f_RSSI_meas(uint d)252 static void f_RSSI_meas(uint d) {
253   p2G4_rssi_done_t RSSI_meas;
254 
255   chm_RSSImeas(&tx_l_c, RSSI_a[d].antenna_gain, &RSSI_a[d].radio_params, &RSSI_meas, d, current_time);
256 
257   dump_RSSImeas(&RSSI_a[d], &RSSI_meas, d);
258 
259   bs_trace_raw_time(8,"RSSIDone for device %u\n", d);
260 
261   p2G4_phy_resp_RSSI(d, &RSSI_meas);
262   p2G4_handle_next_request(d);
263 }
264 
rx_do_RSSI(uint d)265 static void rx_do_RSSI(uint d) {
266   chm_RSSImeas(&tx_l_c, rx_a[d].rx_s.antenna_gain, &rx_a[d].rx_s.radio_params, &rx_a[d].rx_done_s.rssi, d, current_time);
267 }
268 
269 /**
270  * Schedule an Rx_Search_reeval event when the search scan ends or
271  * the next check of the abort reeval
272  */
rx_enqueue_search_reeval(uint d)273 static inline void rx_enqueue_search_reeval(uint d){
274   rx_status_t *rx_status = &rx_a[d];
275 
276   rx_status->state = Rx_State_Searching;
277   bs_time_t end_time = BS_MIN((rx_status->scan_end + 1), rx_status->rx_s.abort.recheck_time);
278   fq_add(end_time, Rx_Search_reeval, d);
279   return;
280 }
281 
282 /**
283  * Find if there is a fitting tx for this rx attempt
284  * if there is not, return -1
285  * if there is, return the device number
286  */
find_fitting_tx(rx_status_t * rx_s)287 static int find_fitting_tx(rx_status_t *rx_s){
288   register uint *used = tx_l_c.used;
289   int max_tx = txl_get_max_tx_nbr();
290   for (int i = 0 ; i <= max_tx; i++) {
291     if ((used[i] & TXS_PACKET_ONGOING) &&
292         tx_and_rx_match(&tx_l_c.tx_list[i].tx_s, rx_s) )
293     {
294       return i;
295     }
296   }
297   return -1;
298 }
299 
300 static void f_rx_found(uint d);
301 
rx_possible_abort_recheck(uint d,rx_status_t * rx_st,bool scanning)302 static void rx_possible_abort_recheck(uint d, rx_status_t *rx_st, bool scanning){
303   if ( current_time >= rx_st->rx_s.abort.recheck_time ) {
304     if ( pick_and_validate_abort(d, &(rx_a[d].rx_s.abort), "Rx") != 0 ){
305       return;
306     }
307     if (scanning && (rx_st->rx_s.abort.abort_time < rx_st->scan_end) ) {
308         rx_st->scan_end = rx_st->rx_s.abort.abort_time - 1;
309     }
310   }
311 }
312 
f_rx_search_start(uint d)313 static void f_rx_search_start(uint d) {
314   int tx_d;
315   rx_status_t *rx_status;
316   rx_status = &rx_a[d];
317 
318   rx_possible_abort_recheck(d, rx_status, true);
319 
320   bs_trace_raw_time(8,"Device %u - Starting Rx\n", d);
321 
322   /* Let's check for possible ongoing transmissions we may still catch */
323   tx_d = find_fitting_tx(rx_status);
324 
325   if (tx_d >= 0) {
326     rx_status->tx_nbr = tx_d;
327     rx_status->state = Rx_State_NotSearching;
328     /* Let's call it directly and save an event */
329     f_rx_found(d);
330     return;
331   }
332 
333   /* If we haven't found anything, we just schedule a new event to wait until the end */
334   rx_enqueue_search_reeval(d);
335   return;
336 }
337 
rx_respond_done(uint d,rx_status_t * rx_status)338 static void rx_respond_done(uint d, rx_status_t *rx_status) {
339   if ( rx_status->v1_request ) {
340     p2G4_rx_done_t rx_done_v1;
341     map_rxv2_resp_to_rxv1(&rx_done_v1, &rx_status->rx_done_s);
342     p2G4_phy_resp_rx(d, &rx_done_v1);
343   } else {
344     p2G4_phy_resp_rxv2(d, &rx_status->rx_done_s);
345   }
346 }
347 
rx_resp_addr_found(uint d,rx_status_t * rx_status,uint8_t * packet)348 static void rx_resp_addr_found(uint d,  rx_status_t *rx_status, uint8_t *packet) {
349   if ( rx_status->v1_request ) {
350     p2G4_rx_done_t rx_done_v1;
351     map_rxv2_resp_to_rxv1(&rx_done_v1, &rx_status->rx_done_s);
352     p2G4_phy_resp_rx_addr_found(d, &rx_done_v1, packet);
353   } else {
354     p2G4_phy_resp_rxv2_addr_found(d, &rx_status->rx_done_s, packet);
355   }
356 }
357 
rx_scan_ended(uint d,rx_status_t * rx_status,const char * const state)358 static void rx_scan_ended(uint d, rx_status_t *rx_status, const char * const state){
359   rx_status->rx_done_s.packet_size = 0;
360   rx_status->rx_done_s.rx_time_stamp = current_time;
361   rx_status->rx_done_s.status = P2G4_RXSTATUS_NOSYNC;
362   if ( rx_status->rx_s.abort.abort_time != current_time ) { //if we are not aborting
363     rx_do_RSSI(d);
364   }
365 
366   bs_trace_raw_time(8,"Device %u - RxDone (NoSync during %s)\n", d, state);
367 
368   rx_status->state = Rx_State_NotSearching;
369   rx_status->rx_done_s.end_time = current_time;
370 
371   rx_respond_done(d, rx_status);
372   dump_rx(&rx_a[d],NULL,d);
373   p2G4_handle_next_request(d);
374 }
375 
f_rx_search_reeval(uint d)376 static void f_rx_search_reeval(uint d) {
377   rx_status_t *rx_status;
378   rx_status = &rx_a[d];
379 
380   rx_possible_abort_recheck(d, rx_status, true);
381 
382   if ( current_time > rx_status->scan_end ) {
383     rx_scan_ended(d, rx_status, "Rx Search");
384     return;
385   }
386 
387   /* If we havent found anything yet, we just continue */
388   rx_enqueue_search_reeval(d);
389   return;
390 }
391 
f_rx_found(uint d)392 static void f_rx_found(uint d){
393   rx_status_t *rx_status = &rx_a[d];
394   uint tx_d = rx_status->tx_nbr;
395 
396   /*
397    * Improvement
398    *   There is a minor issue in this design, as rx_search_start will lock to the first matching Tx
399    *   (even if it has way too low power, and lose the option to find other already ongoing Tx).
400    *   And similarly several simultaneously starting Tx's in the same us will always lose to the
401    *   one with the bigger device number
402    *   Having rx_found actually go thru all possible Tx's until it syncs to one instead of
403    *   having its choice preselected would be better.
404    *   (This flaw existed also in the v1 API FSM version)
405    */
406   if ( chm_is_packet_synched( &tx_l_c, tx_d, d,  &rx_status->rx_s, current_time ) )
407   {
408     p2G4_txv2_t *tx_s = &tx_l_c.tx_list[tx_d].tx_s;
409     rx_status->sync_end    = tx_s->start_packet_time + BS_MAX((int)rx_status->rx_s.pream_and_addr_duration - 1,0);
410     rx_status->header_end  = rx_status->sync_end + rx_status->rx_s.header_duration;
411     rx_status->payload_end = tx_s->end_packet_time;
412     rx_status->biterrors = 0;
413     rx_status->rx_done_s.phy_address = tx_s->phy_address;
414     rx_status->sync_start = tx_s->start_packet_time + rx_status->rx_s.acceptable_pre_truncation;
415     bs_trace_raw_time(8,"Device %u - Matched Tx %u\n", d, tx_d);
416 
417     bs_time_t next_time = BS_MIN(rx_status->sync_start, rx_status->rx_s.abort.recheck_time);
418     next_time = BS_MIN(next_time, rx_status->scan_end + 1);
419     fq_add(next_time, Rx_Sync, d);
420     return;
421   }
422 
423   rx_enqueue_search_reeval(d);
424   return;
425 }
426 
427 
rx_bit_error_calc(uint d,uint tx_nbr,rx_status_t * rx_st)428 static int rx_bit_error_calc(uint d, uint tx_nbr, rx_status_t *rx_st) {
429   int biterrors = 0;
430   rx_error_calc_state_t *st = &rx_st->err_calc_state;
431   if (st->us_to_next_calc-- <= 0) {
432     if ( ( tx_l_c.used[tx_nbr] & TXS_PACKET_ONGOING ) == 0 ) {
433       biterrors = st->errorspercalc;
434     } else {
435       biterrors = chm_bit_errors(&tx_l_c, tx_nbr, d, &rx_st->rx_s, current_time, st->errorspercalc);
436     }
437     st->us_to_next_calc  = st->rate_uspercalc - 1;
438   }
439   return biterrors;
440 }
441 
f_rx_sync(uint d)442 static void f_rx_sync(uint d){
443 
444   rx_possible_abort_recheck(d, &rx_a[d], true);
445 
446   if ( current_time > rx_a[d].scan_end ) {
447     rx_scan_ended(d, &rx_a[d], "Rx sync");
448     return;
449   }
450 
451   if ( current_time < rx_a[d].sync_start ) {
452     //we are not yet meant to try to sync, but we got here due to an abort reeval (or abort) being earlier than the sync_start
453     //so we wait until we should
454     bs_time_t next_time = BS_MIN(rx_a[d].sync_start,rx_a[d].rx_s.abort.recheck_time);
455     next_time = BS_MIN(next_time, rx_a[d].scan_end + 1);
456     fq_add(next_time, Rx_Sync, d);
457     return;
458   }
459 
460   if ( ( tx_l_c.used[rx_a[d].tx_nbr] & TXS_PACKET_ONGOING ) == 0 ) { //if the Tx aborted
461     //An abort of the Tx during a sync results in the sync being lost always (even if we are just at the end of the syncword)
462     bs_trace_raw_time(8,"Device %u - Sync lost (Tx disappeared)\n", d);
463     fq_add(current_time + 1, Rx_Search_start, d); //Note that we go to start, to search again in between the ongoing transmissions
464     return;
465   } else {
466     rx_a[d].biterrors += rx_bit_error_calc(d, rx_a[d].tx_nbr, &rx_a[d]);
467   }
468 
469   if ( rx_a[d].biterrors > rx_a[d].rx_s.sync_threshold ) {
470     bs_trace_raw_time(8,"Device %u - Sync lost (errors)\n", d);
471     fq_add(current_time + 1, Rx_Search_start, d); //Note that we go to start, to search again in between the ongoing transmissions
472     return;
473   }
474 
475   if ( current_time >= rx_a[d].sync_end ) {
476     //we have correctly synch'ed:
477     rx_do_RSSI(d);
478     rx_a[d].biterrors = 0;
479     int device_accepted = 0;
480 
481     //Ask from the device if it wants us to continue..
482     rx_a[d].rx_done_s.rx_time_stamp = rx_a[d].sync_end;
483     rx_a[d].rx_done_s.end_time = current_time;
484     rx_a[d].rx_done_s.packet_size = tx_l_c.tx_list[rx_a[d].tx_nbr].tx_s.packet_size;
485     rx_a[d].rx_done_s.status = P2G4_RXSTATUS_INPROGRESS;
486 
487     bs_trace_raw_time(8,"Device %u - Sync done\n", d);
488     rx_resp_addr_found(d, &rx_a[d], tx_l_c.tx_list[rx_a[d].tx_nbr].packet);
489 
490     pc_header_t header;
491     header = p2G4_get_next_request(d);
492     switch (header) {
493     case PB_MSG_DISCONNECT:
494       nbr_active_devs -= 1;
495       bs_trace_raw_time(5,"Device %u disconnected during Rx (minor protocol violation) (%i left)\n", d, nbr_active_devs);
496       device_accepted = 0;
497       fq_remove(d);
498       return;
499       break;
500     case PB_MSG_TERMINATE:
501       bs_trace_raw_time(4,"Device %u terminated the simulation (there was %i left)\n", d, nbr_active_devs-1);
502       nbr_active_devs = 0;
503       return;
504       break;
505     case P2G4_MSG_RXCONT:
506       device_accepted = 1;
507       break;
508     case P2G4_MSG_RXV2CONT:
509       device_accepted = 1;
510       if (pick_and_validate_abort_Rxcont(d, &(rx_a[d].rx_s.abort)) != 0 ){
511         return;
512       }
513       break;
514     case P2G4_MSG_RXSTOP:
515       device_accepted = 0;
516       break;
517     default:
518       bs_trace_error_line("Device %u has violated the protocol during an Rx (%u) => Terminate\n",d, header);
519       break;
520     }
521 
522     if (device_accepted) {
523       uint delta;
524       if ( rx_a[d].rx_s.pream_and_addr_duration == 0 ) {
525         delta = 0; //We pretend we have not spent time here
526       } else {
527         delta = 1;
528       }
529       if ( rx_a[d].rx_s.header_duration == 0 ) {
530         fq_add(current_time + delta, Rx_Payload, d);
531       } else {
532         fq_add(current_time + delta, Rx_Header, d);
533       }
534     } else {
535       dump_rx(&rx_a[d], tx_l_c.tx_list[rx_a[d].tx_nbr].packet, d);
536       p2G4_handle_next_request(d);
537     }
538     return;
539   } else {
540     fq_add(current_time + 1, Rx_Sync, d);
541     return;
542   }
543 }
544 
f_rx_header(uint d)545 static void f_rx_header(uint d){
546 
547   rx_possible_abort_recheck(d, &rx_a[d], false);
548 
549   rx_a[d].biterrors += rx_bit_error_calc(d, rx_a[d].tx_nbr, &rx_a[d]);
550 
551 
552   if ( ( ( current_time >= rx_a[d].header_end )
553         && ( rx_a[d].biterrors > rx_a[d].rx_s.header_threshold ) )
554       ||
555        ( current_time >= rx_a[d].rx_s.abort.abort_time ) ) {
556     rx_a[d].rx_done_s.packet_size = 0;
557     rx_a[d].rx_done_s.status = P2G4_RXSTATUS_HEADER_ERROR;
558     bs_trace_raw_time(8,"Device %u - RxDone (Header error)\n", d);
559     rx_a[d].rx_done_s.end_time = current_time;
560 
561     rx_respond_done(d, &rx_a[d]);
562     dump_rx(&rx_a[d],NULL,d);
563     p2G4_handle_next_request(d);
564     return;
565   } else if ( current_time >= rx_a[d].header_end ) {
566     bs_trace_raw_time(8,"Device %u - Header done\n", d);
567     fq_add(current_time + 1, Rx_Payload, d);
568     return;
569   } else {
570     fq_add(current_time + 1, Rx_Header, d);
571     return;
572   }
573 }
574 
f_rx_payload(uint d)575 static void f_rx_payload(uint d){
576 
577   rx_possible_abort_recheck(d, &rx_a[d], false);
578 
579   rx_a[d].biterrors += rx_bit_error_calc(d, rx_a[d].tx_nbr, &rx_a[d]);
580 
581   if (((current_time >= rx_a[d].payload_end) && (rx_a[d].biterrors > 0))
582       || (current_time >= rx_a[d].rx_s.abort.abort_time)) {
583     if (!args.crcerr_data) {
584         rx_a[d].rx_done_s.packet_size = 0;
585     }
586     rx_a[d].rx_done_s.status = P2G4_RXSTATUS_PACKET_CONTENT_ERROR;
587     bs_trace_raw_time(8,"Device %u - RxDone (CRC error)\n", d);
588     rx_a[d].rx_done_s.end_time = current_time;
589     rx_respond_done(d, &rx_a[d]);
590     dump_rx(&rx_a[d],NULL,d);
591     p2G4_handle_next_request(d);
592     return;
593   } else if ( current_time >= rx_a[d].payload_end ) {
594     rx_a[d].rx_done_s.status = P2G4_RXSTATUS_OK;
595     bs_trace_raw_time(8,"Device %u - RxDone (CRC ok)\n", d);
596     rx_a[d].rx_done_s.end_time = current_time;
597     rx_respond_done(d, &rx_a[d]);
598     dump_rx(&rx_a[d],tx_l_c.tx_list[rx_a[d].tx_nbr].packet,d);
599     p2G4_handle_next_request(d);
600     return;
601   } else {
602     fq_add(current_time + 1, Rx_Payload, d);
603     return;
604   }
605 }
606 
607 
608 /**
609  * Find if there is a compatible modulation for this CCA search
610  * if there is not, return -1
611  * if there is, return the device number
612  *
613  * Note that this search is not the same as for Rx
614  * a) there does not need to be an actual packet in the air
615  * b) we do not check the address
616  * c) we do not check where in the transmittion we may be
617  */
find_fitting_tx_cca(p2G4_cca_t * req)618 static int find_fitting_tx_cca(p2G4_cca_t *req){
619   register uint *used = tx_l_c.used;
620   int max_tx = txl_get_max_tx_nbr();
621   for (int i = 0 ; i <= max_tx; i++) {
622     if (used[i] != TXS_OFF)
623     {
624       p2G4_txv2_t* tx_s = &tx_l_c.tx_list[i].tx_s;
625       if ((tx_s->radio_params.center_freq == req->radio_params.center_freq) &&
626          (tx_s->radio_params.modulation & P2G4_MOD_SIMILAR_MASK) ==
627              (req->radio_params.modulation & P2G4_MOD_SIMILAR_MASK) )
628       {
629         return i;
630       }
631     }
632   }
633   return -1;
634 }
635 
636 
f_cca_meas(uint d)637 static void f_cca_meas(uint d) {
638   cca_status_t *cca_s = &cca_a[d];
639   p2G4_cca_t *req = &cca_a[d].req;
640   p2G4_cca_done_t *resp = &cca_a[d].resp;
641   p2G4_rssi_done_t RSSI_meas;
642 
643   if ( current_time >= req->abort.recheck_time ) {
644     if ( pick_and_validate_abort(d, &(req->abort), "CCA") != 0 ) {
645       return;
646     }
647     if ((req->abort.abort_time < cca_s->scan_end) ) {
648       cca_s->scan_end = req->abort.abort_time;
649     }
650   }
651 
652   if ( current_time >= cca_s->next_meas ) {
653     { //Check RSSI level
654       chm_RSSImeas(&tx_l_c, req->antenna_gain, &req->radio_params, &RSSI_meas, d, current_time);
655 
656       double power = p2G4_RSSI_value_to_dBm(RSSI_meas.RSSI);
657       power = pow(10, power/10);
658       cca_s->RSSI_acc += power;
659 
660       resp->RSSI_max = BS_MAX(resp->RSSI_max, RSSI_meas.RSSI);
661 
662       if (RSSI_meas.RSSI >= req->rssi_threshold) {
663         resp->rssi_overthreshold = true;
664         bs_trace_raw_time(8,"Device %u - RSSI over threshold \n", d);
665         if (req->stop_when_found & 2) {
666           cca_s->scan_end = current_time;
667         }
668       }
669     }
670 
671     { //check for compatible modulation
672       int tx_match;
673       tx_match = find_fitting_tx_cca(req);
674       if (tx_match >= 0){
675         p2G4_power_t power = p2G4_RSSI_value_to_dBm(RSSI_meas.RSSI);
676         resp->mod_rx_power = BS_MAX(resp->mod_rx_power, power);
677         if (power >= req->mod_threshold) {
678           resp->mod_found = true;
679           bs_trace_raw_time(8,"Device %u - Modulated signal over threshold \n", d);
680           if (req->stop_when_found & 1) {
681             cca_s->scan_end = current_time;
682           }
683         }
684       }
685     }
686 
687     cca_s->next_meas += req->scan_period;
688     cca_s->n_meas++;
689   }
690 
691   if ( current_time >= cca_s->scan_end ) {
692     bs_trace_raw_time(8,"Device %u - CCA completed\n", d);
693 
694     double power_dBm = 10*log10(cca_s->RSSI_acc/cca_s->n_meas);
695     resp->RSSI_ave = p2G4_RSSI_value_from_dBm(power_dBm); //average the result
696     resp->end_time = current_time;
697     p2G4_phy_resp_cca(d, resp);
698     dump_cca(cca_s, d);
699     p2G4_handle_next_request(d);
700     return;
701   }
702 
703   /* Otherwise, we just continue */
704   bs_time_t next_time = BS_MIN(cca_s->scan_end, req->abort.recheck_time);
705   next_time = BS_MIN(cca_s->next_meas, next_time);
706   fq_add(next_time, Rx_CCA_meas, d);
707 
708   return;
709 }
710 
711 #define PAST_CHECK(start, d, type) \
712   if (current_time >= start) { \
713     bs_trace_error_time_line("Device %u wants to start a %s in "\
714                              "%"PRItime" which has already passed\n",\
715                              d, type, start); \
716   }
717 
prepare_wait(uint d)718 static void prepare_wait(uint d){
719   pb_wait_t wait;
720 
721   p2G4_phy_get(d, &wait, sizeof(wait));
722 
723   bs_trace_raw_time(8,"Device %u wants to wait until %"PRItime"\n",
724                     d, wait.end);
725 
726   fq_add(wait.end, Wait_Done, d);
727 
728   if (current_time > wait.end) {
729     bs_trace_error_time_line("Device %u wants to start a wait in "
730                              "%"PRItime" which has already passed\n",
731                              d, wait.end);
732   }
733 }
734 
check_valid_abort(p2G4_abort_t * abort,bs_time_t start_time,const char * type,uint d)735 static void check_valid_abort(p2G4_abort_t *abort, bs_time_t start_time, const char* type, uint d){
736   if (current_time >= abort->abort_time){
737     bs_trace_error_time_line("Device %u wants to abort a %s in the past (in %"PRItime")\n",
738                              d, type, abort->abort_time);
739   }
740   if (current_time >= abort->recheck_time){
741     bs_trace_error_time_line("Device %u wants to recheck a %s abort in the past (in %"PRItime")\n",
742                              d, type, abort->recheck_time);
743   }
744 
745   if (start_time > abort->abort_time) {
746     bs_trace_error_time_line("Device %u wants a %s abort before the %s start (in %"PRItime")\n",
747                              d, type, type, abort->abort_time);
748   }
749   if (start_time > abort->recheck_time) {
750     bs_trace_error_time_line("Device %u wants a %s abort recheck before %s start (in %"PRItime")\n",
751                              d, type, type, abort->recheck_time);
752   }
753 }
754 
prepare_tx_common(uint d,p2G4_txv2_t * tx_s)755 static void prepare_tx_common(uint d, p2G4_txv2_t *tx_s){
756   uint8_t *data = NULL;
757 
758   if ( tx_s->packet_size > 0 ){
759     data = bs_malloc(tx_s->packet_size);
760     p2G4_phy_get(d, data, tx_s->packet_size);
761   }
762 
763   PAST_CHECK(tx_s->start_tx_time, d, "Tx");
764 
765   if ( tx_s->start_tx_time >= tx_s->end_tx_time ) {
766     bs_trace_error_time_line("Device %u wants a tx end time <= tx start time (%"PRItime" <= %"PRItime")\n",d, tx_s->end_tx_time, tx_s->start_tx_time);
767   }
768   if ( tx_s->start_packet_time >= tx_s->end_tx_time ) {
769     bs_trace_error_time_line("Device %u wants a tx end time <= tx packet start time (%"PRItime" <= %"PRItime")\n",d, tx_s->end_tx_time, tx_s->start_packet_time);
770   }
771   if ( tx_s->start_packet_time >= tx_s->end_packet_time ) {
772     bs_trace_error_time_line("Device %u wants a packet end time <= tx packet start time (%"PRItime" <= %"PRItime")\n",d, tx_s->end_packet_time, tx_s->start_packet_time);
773   }
774 
775   check_valid_abort(&tx_s->abort, tx_s->start_tx_time , "Tx", d);
776 
777   bs_trace_raw_time(8,"Device %u wants to Tx in: %"PRItime "-%"PRItime ""
778                     " (packet: %"PRItime "-%"PRItime ")"
779                     " (abort,recheck at %"PRItime ",%"PRItime ")"
780                     "\n",
781                     d, tx_s->start_tx_time, tx_s->end_tx_time,
782                     tx_s->start_packet_time, tx_s->end_packet_time,
783                     tx_s->abort.abort_time, tx_s->abort.recheck_time);
784 
785   txl_register(d, tx_s, data);
786 
787   fq_add(tx_s->start_tx_time, Tx_Start, d);
788   /* Note: It is irrelevant if an ideal packet would have started before for the Tx side,
789    * until the Tx starts nothing happens */
790 }
791 
prepare_txv2(uint d)792 static void prepare_txv2(uint d){
793   p2G4_txv2_t tx_s;
794 
795   p2G4_phy_get(d, &tx_s, sizeof(tx_s));
796 
797   prepare_tx_common(d, &tx_s);
798 }
799 
prepare_txv1(uint d)800 static void prepare_txv1(uint d){
801   p2G4_tx_t tx_s;
802   p2G4_txv2_t tx_v2_s;
803 
804   p2G4_phy_get(d, &tx_s, sizeof(tx_s));
805   map_txv1_to_txv2(&tx_v2_s, &tx_s);
806 
807   prepare_tx_common(d, &tx_v2_s);
808 }
809 
prepare_RSSI(uint d)810 static void prepare_RSSI(uint d){
811   p2G4_rssi_t RSSI_s;
812 
813   p2G4_phy_get(d, &RSSI_s, sizeof(RSSI_s));
814 
815   PAST_CHECK(RSSI_s.meas_time, d, "RSSI measurement");
816 
817   bs_trace_raw_time(8,"Device %u want to do a RSSI measurement in %"PRItime "\n", \
818                     d,  RSSI_s.meas_time); \
819 
820   memcpy(&RSSI_a[d],&RSSI_s, sizeof(p2G4_rssi_t));
821 
822   fq_add(RSSI_s.meas_time, RSSI_Meas, d);
823 }
824 
prepare_rx_common(uint d,p2G4_rxv2_t * rxv2_s)825 static void prepare_rx_common(uint d, p2G4_rxv2_t *rxv2_s){
826   PAST_CHECK(rxv2_s->start_time, d, "Rx");
827 
828   check_valid_abort(&rxv2_s->abort, rxv2_s->start_time , "Rx", d);
829 
830   bs_trace_raw_time(8,"Device %u wants to Rx in %"PRItime " (abort,recheck at %"PRItime ",%"PRItime ")\n",
831                     d, rxv2_s->start_time, rxv2_s->abort.abort_time, rxv2_s->abort.recheck_time);
832 
833   if (rxv2_s->prelocked_tx != 0) {
834     bs_trace_error_time_line("Device %u - Prelocked Tx not yet supported, must be set to 0 (was %u)\n",
835                              d, rxv2_s->prelocked_tx);
836   }
837 
838   //Initialize the reception status
839   memcpy(&rx_a[d].rx_s, rxv2_s, sizeof(p2G4_rxv2_t));
840   rx_a[d].scan_end = rx_a[d].rx_s.start_time + rx_a[d].rx_s.scan_duration - 1;
841   rx_a[d].sync_end = 0;
842   rx_a[d].header_end = 0;
843   rx_a[d].payload_end = 0;
844   rx_a[d].tx_nbr = -1;
845   rx_a[d].biterrors = 0;
846   memset(&rx_a[d].rx_done_s, 0, sizeof(p2G4_rxv2_done_t));
847   if ( rxv2_s->abort.abort_time < rx_a[d].scan_end ) {
848     rx_a[d].scan_end = rxv2_s->abort.abort_time - 1;
849   }
850 
851   if (rxv2_s->error_calc_rate % 1000000 == 0) {
852     rx_a[d].err_calc_state.errorspercalc = rxv2_s->error_calc_rate / 1000000;
853     rx_a[d].err_calc_state.rate_uspercalc = 1;
854     rx_a[d].err_calc_state.us_to_next_calc = 0;
855   } else if (1000000 % rxv2_s->error_calc_rate == 0) {
856     rx_a[d].err_calc_state.errorspercalc = 1;
857     rx_a[d].err_calc_state.rate_uspercalc = 1000000 / rxv2_s->error_calc_rate;
858     rx_a[d].err_calc_state.us_to_next_calc = 0;
859   } else {
860     bs_trace_error_time_line("The device %u requested a reception with an error calc rate "
861                              "of %u times per s, but only integer multiples or integer dividers of 1MHz "
862                              "are supported so far (for ex. 3MHz, 1MHz, 250KHz, 62.5KHz)\n",
863                              d, rxv2_s->error_calc_rate);
864   }
865 
866   fq_add(rxv2_s->start_time, Rx_Search_start, d);
867 }
868 
prepare_rxv1(uint d)869 static void prepare_rxv1(uint d){
870   p2G4_rx_t rxv1_s;
871   p2G4_rxv2_t rxv2_s;
872 
873   p2G4_phy_get(d, &rxv1_s, sizeof(p2G4_rx_t));
874   map_rxv1_to_rxv2(&rxv2_s, &rxv1_s);
875   rx_a[d].phy_address[0] = rxv1_s.phy_address;
876   rx_a[d].v1_request = true;
877 
878   prepare_rx_common(d, &rxv2_s);
879 }
880 
prepare_rxv2(uint d)881 static void prepare_rxv2(uint d){
882   p2G4_rxv2_t rxv2_s;
883 
884   p2G4_phy_get(d, &rxv2_s, sizeof(p2G4_rxv2_t));
885 
886   if ( rxv2_s.n_addr > P2G4_RXV2_MAX_ADDRESSES ) {
887     bs_trace_error_time_line("Device %u: Attempting to Rx w more than the allowed number of Rx addresses,"
888         "%i > %i\n",d, rxv2_s.n_addr, P2G4_RXV2_MAX_ADDRESSES);
889   }
890 
891   if ( rxv2_s.resp_type != 0 ){
892     bs_trace_error_time_line("Device %u: Attempting to Rx w resp_type = %i (not yet supported)\n",
893         d, rxv2_s.resp_type);
894   }
895 
896   if ( ( rxv2_s.pream_and_addr_duration > 0 ) &&
897       ( rxv2_s.acceptable_pre_truncation >= rxv2_s.pream_and_addr_duration ) ) {
898     bs_trace_error_time_line("Device %u: Attempting to Rx w acceptable_pre_truncation >= pream_and_addr_duration (%u >= %u)\n",
899         d, rxv2_s.acceptable_pre_truncation, rxv2_s.pream_and_addr_duration);
900   }
901   if ( rxv2_s.acceptable_pre_truncation > rxv2_s.pream_and_addr_duration ) {
902     bs_trace_error_time_line("Device %u: Attempting to Rx w acceptable_pre_truncation > pream_and_addr_duration (%u >= %u)\n",
903         d, rxv2_s.acceptable_pre_truncation, rxv2_s.pream_and_addr_duration);
904   }
905 
906   p2G4_phy_get(d, rx_a[d].phy_address, rxv2_s.n_addr*sizeof(p2G4_address_t));
907   rx_a[d].v1_request = false;
908 
909   prepare_rx_common(d, &rxv2_s);
910 }
911 
prepare_CCA(uint d)912 static void prepare_CCA(uint d){
913   p2G4_cca_t *cca_req = &cca_a[d].req;
914 
915   //Clear status (and response)
916   memset(&cca_a[d], 0, sizeof(cca_status_t));
917 
918   p2G4_phy_get(d, cca_req, sizeof(p2G4_cca_t));
919 
920   PAST_CHECK(cca_req->start_time, d, "CCA");
921 
922   check_valid_abort(&cca_req->abort, cca_req->start_time , "CCA", d);
923 
924   if ( cca_req->scan_period == 0 ){
925     bs_trace_error_time_line("Device %u: scan period must be bigger than 0\n", d);
926   }
927 
928   if ( cca_req->stop_when_found > 3 ){
929     bs_trace_error_time_line("Device %u: Attempting to CCA w stop_when_found %u > 3 (not supported)\n",
930            d, cca_req->stop_when_found);
931   }
932 
933   cca_a[d].scan_end = cca_req->start_time + cca_req->scan_duration -1;
934   cca_a[d].next_meas = cca_req->start_time;
935   cca_a[d].RSSI_acc = 0;
936   cca_a[d].resp.RSSI_max = P2G4_RSSI_POWER_MIN;
937   cca_a[d].resp.mod_rx_power = P2G4_RSSI_POWER_MIN;
938 
939   bs_trace_raw_time(8,"Device %u wants to CCA starting in %"PRItime " every %u us; for %u us (abort,recheck at %"PRItime ",%"PRItime ")\n",
940                     d, cca_req->start_time, cca_req->scan_period, cca_req->scan_duration, cca_req->abort.abort_time, cca_req->abort.recheck_time);
941 
942   fq_add(cca_req->start_time, Rx_CCA_meas, d);
943 }
944 
p2G4_handle_next_request(uint d)945 static void p2G4_handle_next_request(uint d) {
946   pc_header_t header;
947   header = p2G4_get_next_request(d);
948 
949   switch (header) {
950     case PB_MSG_DISCONNECT:
951       nbr_active_devs -= 1;
952       bs_trace_raw_time(3,"Device %u disconnected (%i left)\n", d, nbr_active_devs);
953       fq_remove(d);
954       break;
955     case PB_MSG_TERMINATE:
956       bs_trace_raw_time(4,"Device %u terminated the simulation (there was %i left)\n", d, nbr_active_devs-1);
957       nbr_active_devs = 0;
958       break;
959     case PB_MSG_WAIT:
960       prepare_wait(d);
961       break;
962     case P2G4_MSG_TX:
963       prepare_txv1(d);
964       break;
965     case P2G4_MSG_TXV2:
966       prepare_txv2(d);
967       break;
968     case P2G4_MSG_RSSIMEAS:
969       prepare_RSSI(d);
970       break;
971     case P2G4_MSG_RX:
972       prepare_rxv1(d);
973       break;
974     case P2G4_MSG_RXV2:
975       prepare_rxv2(d);
976       break;
977     case P2G4_MSG_CCA_MEAS:
978       prepare_CCA(d);
979       break;
980     default:
981       bs_trace_error_time_line("The device %u has violated the protocol (%u)\n",d, header);
982       break;
983   }
984 }
985 
p2G4_main_clean_up()986 uint8_t p2G4_main_clean_up(){
987   int return_error;
988   bs_trace_raw(9, "main: Cleaning up...\n");
989   return_error = close_dump_files();
990   if (RSSI_a != NULL)
991     free(RSSI_a);
992   if (rx_a != NULL)
993     free(rx_a);
994   if (cca_a != NULL)
995     free(cca_a);
996   txl_free();
997   channel_and_modem_delete();
998   fq_free();
999   bs_random_free();
1000   p2G4_phy_disconnect_all_devices();
1001   p2G4_clear_args_struct(&args);
1002   return return_error;
1003 }
1004 
p2G4_get_time()1005 static bs_time_t p2G4_get_time(){
1006   return current_time;
1007 }
1008 
main(int argc,char * argv[])1009 int main(int argc, char *argv[]) {
1010 
1011   bs_trace_register_cleanup_function(p2G4_main_clean_up);
1012   bs_trace_set_prefix_phy("???");
1013   bs_trace_register_time_function(p2G4_get_time);
1014 
1015   bs_trace_raw(9,"main: Parsing command line...\n");
1016   p2G4_argsparse(argc, argv, &args);
1017 
1018   channel_and_modem_init(args.channel_argc, args.channel_argv, args.channel_name,
1019                          args.modem_argc, args.modem_argv, args.modem_name, args.n_devs);
1020 
1021   bs_trace_raw(7,"main: Connecting...\n");
1022   p2G4_phy_initcom(args.s_id, args.p_id, args.n_devs);
1023 
1024   fq_init(args.n_devs);
1025   fq_register_func(Wait_Done,      f_wait_done      );
1026   fq_register_func(RSSI_Meas,      f_RSSI_meas      );
1027   fq_register_func(Rx_Search_start,f_rx_search_start);
1028   fq_register_func(Rx_Search_reeval,f_rx_search_reeval);
1029   fq_register_func(Rx_Found,       f_rx_found       );
1030   fq_register_func(Rx_Sync,        f_rx_sync        );
1031   fq_register_func(Rx_Header,      f_rx_header      );
1032   fq_register_func(Rx_Payload,     f_rx_payload     );
1033   fq_register_func(Tx_Abort_Reeval,f_tx_abort_reeval);
1034   fq_register_func(Tx_Start,       f_tx_start       );
1035   fq_register_func(Tx_Packet_Start,f_tx_packet_start);
1036   fq_register_func(Tx_Packet_End,  f_tx_packet_end  );
1037   fq_register_func(Tx_End,         f_tx_end         );
1038   fq_register_func(Rx_CCA_meas,    f_cca_meas       );
1039 
1040   bs_random_init(args.rseed);
1041   txl_create(args.n_devs);
1042   RSSI_a = bs_calloc(args.n_devs, sizeof(p2G4_rssi_t));
1043   rx_a = bs_calloc(args.n_devs, sizeof(rx_status_t));
1044   cca_a = bs_calloc(args.n_devs, sizeof(cca_status_t));
1045 
1046   if (args.dont_dump == 0) open_dump_files(args.compare, args.stop_on_diff, args.dump_imm, args.s_id, args.p_id, args.n_devs);
1047 
1048   nbr_active_devs = args.n_devs;
1049 
1050   for (uint d = 0; d < args.n_devs && nbr_active_devs > 0; d ++) {
1051     p2G4_handle_next_request(d);
1052   }
1053 
1054   fq_find_next();
1055   current_time = fq_get_next_time();
1056   while ((nbr_active_devs > 0) && (current_time < args.sim_length)) {
1057     fq_call_next();
1058     fq_find_next();
1059     current_time = fq_get_next_time();
1060   }
1061 
1062   if (current_time >= args.sim_length) {
1063     bs_trace_raw(9, "main: @%"PRItime" simulation ended\n", args.sim_length);
1064   }
1065 
1066   return p2G4_main_clean_up();
1067 }
1068 
1069 /*
1070  * TODO:
1071  *
1072  * Enable Txv2, Rxv2 & CCA dumps
1073  *
1074  * Future features (see doc/Current_API_shortcommings.txt):
1075  * implement prelocked_tx
1076  * implement forced_packet_duration
1077  * implement support for != coding_rate in Tx and Rx
1078  * implement support for immediate bit error masks
1079  */
1080