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