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