1 /*
2 * Copyright 2018 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <string.h>
7 #include <stdio.h>
8 #include "bs_tracing.h"
9 #include "bs_oswrap.h"
10 #include "bs_results.h"
11 #include "bs_pc_2G4_types.h"
12 #include "bs_pc_2G4_utils.h"
13 #include "p2G4_channel_and_modem_priv.h"
14 #include "bs_rand_main.h"
15 #include "p2G4_pending_tx_rx_list.h"
16
17 /*Max number of errors before ignoring a given file*/
18 #define MAX_ERRORS 15
19
20 static bool comp, stop_on_diff;
21 static uint n_dev = 0;
22
23 /* statistics per device and file */
24 typedef struct {
25 //Number of lines with errors:
26 uint32_t nbr_rxv1_er;
27 uint32_t nbr_txv1_er;
28 uint32_t nbr_rxv2_er;
29 uint32_t nbr_txv2_er;
30 uint32_t nbr_RSSI_er;
31 uint32_t nbr_CCA_er;
32 uint32_t nbr_modemrx_er;
33 //Number lines dumped:
34 uint32_t nbr_rxv1;
35 uint32_t nbr_txv1;
36 uint32_t nbr_rxv2;
37 uint32_t nbr_txv2;
38 uint32_t nbr_RSSI;
39 uint32_t nbr_CCA;
40 uint32_t nbr_modemrx;
41 } t_dump_check_stats;
42
43 static t_dump_check_stats *stats = NULL;
44
45 static FILE **txv1_f = NULL;
46 static FILE **rxv1_f = NULL;
47 static FILE **txv2_f = NULL;
48 static FILE **rxv2_f = NULL;
49 static FILE **RSSI_f = NULL;
50 static FILE **CCA_f = NULL;
51 static FILE **modemrx_f = NULL;
52
dump_txv1_heading(FILE * file)53 static void dump_txv1_heading(FILE *file){
54 if (file == NULL) {
55 return;
56 }
57 fprintf(file,
58 "start_time,end_time,center_freq,"
59 "phy_address,modulation,power_level,abort_time,"
60 "recheck_time,packet_size,packet\n");
61 }
62
dump_txv2_heading(FILE * file)63 static void dump_txv2_heading(FILE *file){
64 if (file == NULL) {
65 return;
66 }
67 fprintf(file,
68 "start_tx_time,end_tx_time,"
69 "start_packet_time, end_packet_time, center_freq,"
70 "phy_address,modulation,coding_rate,power_level,abort_time,"
71 "recheck_time,packet_size,packet\n");
72 }
73
dump_rxv1_heading(FILE * file)74 static void dump_rxv1_heading(FILE *file){
75 if (file == NULL) {
76 return;
77 }
78 fprintf(file,"start_time,scan_duration,phy_address,modulation,"
79 "center_freq,antenna_gain,sync_threshold,header_threshold,"
80 "pream_and_addr_duration,"
81 "header_duration,bps,abort_time,recheck_time,"
82 "tx_nbr,biterrors,sync_end,header_end,"
83 "payload_end,rx_time_stamp,status,RSSI,"
84 "packet_size,packet\n");
85 }
86
dump_rxv2_heading(FILE * file)87 static void dump_rxv2_heading(FILE *file){
88 if (file == NULL) {
89 return;
90 }
91 fprintf(file,"start_time,scan_duration,n_addr,phy_address[],modulation,"
92 "center_freq,antenna_gain,"
93 "acceptable_pre_truncation,sync_threshold,header_threshold,"
94 "pream_and_addr_duration,"
95 "header_duration,error_calc_rate,"
96 "forced_packet_duration,coding_rate,prelocked_tx,"
97 "resp_type,"
98 "abort_time,recheck_time,"
99 "tx_nbr,matched_addr,tx_coding_rate,biterrors,sync_end,header_end,"
100 "payload_end,rx_time_stamp,status,RSSI,"
101 "packet_size,packet\n");
102 }
103
dump_CCA_heading(FILE * file)104 static void dump_CCA_heading(FILE *file){
105 if (file == NULL) {
106 return;
107 }
108 fprintf(file,"start_time,scan_duration,scan_period,"
109 "modulation,center_freq,antenna_gain,"
110 "threshold_mod,threshold_rssi,stop_when_found,"
111 "abort_time,recheck_time,"
112 "end_time, RSSI_ave, RSSI_max, mod_rx_power,"
113 "mod_found, rssi_overthreshold\n");
114 }
115
116
dump_RSSI_heading(FILE * file)117 static void dump_RSSI_heading(FILE *file){
118 if (file == NULL) {
119 return;
120 }
121 fprintf(file,"meas_time,modulation,center_freq,antenna_gain,RSSI\n");
122 }
123
dump_modemrx_heading(FILE * file)124 static void dump_modemrx_heading(FILE *file){
125 if (file == NULL) {
126 return;
127 }
128 fprintf(file,"time,tx_nbr,CalNotRecal,center_freq,modulation,"
129 "coding_rate,"
130 "BER,syncprob,SNR,anaSNR,ISISNR,att[i],rxpow[i]\n");
131 }
132
133 /**
134 * Compare 2 strings, return 0 if they match,
135 * or -(the position of the 1st difference if they don't)
136 */
compare(const char * a,const char * b,size_t size)137 static int compare(const char* a,const char* b, size_t size){
138 int i = 0;
139 while ( i < size && ( ( a[i] != 0 ) || ( b[i]!= 0 ) ) ){
140 if (a[i] != b[i]){
141 return -(i+1);
142 }
143 i++;
144 }
145 return 0;
146 }
147
generate_cursor(char * o,const uint n)148 static void generate_cursor(char *o, const uint n){
149 int i = 0;
150 while (i < n-1){
151 o[i++] =' ';
152 }
153 o[i++]='^';
154 o[i]=0;
155 }
156
open_file(size_t fname_len,const char * results_path,const char * type,const char * p_id,int dev_nbr)157 static FILE* open_file(size_t fname_len, const char* results_path, const char* type,
158 const char* p_id, int dev_nbr) {
159 FILE *file;
160 char filename[fname_len];
161 sprintf(filename,"%s/d_%s_%02i.%s.csv",results_path, p_id, dev_nbr, type);
162
163 if (comp == 1) {
164 file = bs_fopen(filename, "r");
165 bs_skipline(file); //Skip heading
166 if ( feof(file) ){
167 bs_trace_warning_line("%s file for device %i empty => won't be checked\n",type, dev_nbr);
168 fclose(file);
169 file = NULL;
170 }
171 } else {
172 file = bs_fopen(filename, "w");
173 }
174 return file;
175 }
176
177 /**
178 * Prepare dumping
179 */
open_dump_files(uint8_t comp_i,uint8_t stop,uint8_t dump_imm,const char * s,const char * p,const uint n_dev_i)180 void open_dump_files(uint8_t comp_i, uint8_t stop, uint8_t dump_imm, const char* s,
181 const char* p, const uint n_dev_i){
182 char* path;
183
184 comp = comp_i;
185 stop_on_diff = stop;
186 n_dev = n_dev_i;
187
188 path = bs_create_result_folder(s);
189
190 stats = bs_calloc(n_dev, sizeof(t_dump_check_stats));
191 txv1_f = bs_calloc(n_dev, sizeof(FILE *));
192 rxv1_f = bs_calloc(n_dev, sizeof(FILE *));
193 txv2_f = bs_calloc(n_dev, sizeof(FILE *));
194 rxv2_f = bs_calloc(n_dev, sizeof(FILE *));
195 RSSI_f = bs_calloc(n_dev, sizeof(FILE *));
196 CCA_f = bs_calloc(n_dev, sizeof(FILE *));
197 modemrx_f = bs_calloc(n_dev, sizeof(FILE *));
198
199 int fname_len = 26 + strlen(path) + strlen(p);
200 for (int i = 0; i < n_dev; i++) {
201 txv1_f[i] = open_file(fname_len, path, "Tx", p, i);
202 rxv1_f[i] = open_file(fname_len, path, "Rx", p, i);
203 txv2_f[i] = open_file(fname_len, path, "Txv2", p, i);
204 rxv2_f[i] = open_file(fname_len, path, "Rxv2", p, i);
205 CCA_f[i] = open_file(fname_len, path, "CCA", p, i);
206 RSSI_f[i] = open_file(fname_len, path, "RSSI", p, i);
207 modemrx_f[i] = open_file(fname_len, path, "ModemRx", p, i);
208
209 if (comp == 0) {
210 if (dump_imm) {
211 if (txv1_f[i]) setvbuf(txv1_f[i], NULL, _IOLBF, 0);
212 if (rxv1_f[i]) setvbuf(rxv1_f[i], NULL, _IOLBF, 0);
213 if (txv2_f[i]) setvbuf(txv2_f[i], NULL, _IOLBF, 0);
214 if (rxv2_f[i]) setvbuf(rxv2_f[i], NULL, _IOLBF, 0);
215 if (RSSI_f[i]) setvbuf(RSSI_f[i], NULL, _IOLBF, 0);
216 if (CCA_f[i]) setvbuf(CCA_f[i] , NULL, _IOLBF, 0);
217 if (modemrx_f[i]) setvbuf(modemrx_f[i], NULL, _IOLBF, 0);
218 }
219 dump_txv1_heading(txv1_f[i]);
220 dump_rxv1_heading(rxv1_f[i]);
221 dump_txv2_heading(txv2_f[i]);
222 dump_rxv2_heading(rxv2_f[i]);
223 dump_RSSI_heading(RSSI_f[i]);
224 dump_CCA_heading(CCA_f[i]);
225 dump_modemrx_heading(modemrx_f[i]);
226 }
227 }
228
229 free(path);
230 }
231
print_stats(const char * type,int i,uint32_t n_op,uint32_t n_err,FILE * f)232 static int print_stats(const char* type, int i, uint32_t n_op, uint32_t n_err, FILE *f) {
233 int tracel;
234
235 if (n_op > 0) {
236 if (n_err == 0) {
237 tracel = 4;
238 } else {
239 tracel = 1;
240 }
241 bs_trace_raw(tracel, "Check: Device %2i, %s: found %i/%i differences (%.1f%%)\n",
242 i, type, n_err, n_op, n_err*100.0/(float)n_op);
243 }
244 if (f == NULL) {
245 bs_trace_raw(1, "Check: Device %2i, %s: comparison stopped before end of simulation\n",
246 i, type);
247 }
248 return (n_err!=0);
249 }
250
close_dump_files()251 int close_dump_files() {
252 int i;
253 int ret_error = 0;
254
255 if (stats != NULL) {
256 if (comp) {
257 for ( i = 0 ; i < n_dev; i ++) {
258 ret_error |= print_stats("Tx", i, stats[i].nbr_txv1, stats[i].nbr_txv1_er, txv1_f[i]);
259 ret_error |= print_stats("Rx", i, stats[i].nbr_rxv1, stats[i].nbr_rxv1_er, rxv1_f[i]);
260 ret_error |= print_stats("Txv2", i, stats[i].nbr_txv2, stats[i].nbr_txv2_er, txv2_f[i]);
261 ret_error |= print_stats("Rxv2", i, stats[i].nbr_rxv2, stats[i].nbr_rxv2_er, rxv2_f[i]);
262 ret_error |= print_stats("RSSI", i, stats[i].nbr_RSSI, stats[i].nbr_RSSI_er, RSSI_f[i]);
263 ret_error |= print_stats("CCA" , i, stats[i].nbr_CCA, stats[i].nbr_CCA_er, CCA_f[i]);
264 ret_error |= print_stats("ModemRx", i, stats[i].nbr_modemrx, stats[i].nbr_modemrx_er, modemrx_f[i]);
265 }
266 }
267 free(stats);
268 stats = NULL;
269 }
270
271 if ((txv1_f != NULL) && (rxv1_f != NULL) &&
272 (txv2_f != NULL) && (rxv2_f != NULL) &&
273 (RSSI_f != NULL) && (modemrx_f != NULL) &&
274 (CCA_f != NULL) ) {
275 for (i = 0; i < n_dev; i ++) {
276 if (txv1_f[i] != NULL)
277 fclose(txv1_f[i]);
278 if (rxv1_f[i] != NULL)
279 fclose(rxv1_f[i]);
280 if (txv2_f[i] != NULL)
281 fclose(txv2_f[i]);
282 if (rxv2_f[i] != NULL)
283 fclose(rxv2_f[i]);
284 if (RSSI_f[i] != NULL)
285 fclose(RSSI_f[i]);
286 if (CCA_f[i] != NULL)
287 fclose(CCA_f[i]);
288 if (modemrx_f[i] != NULL)
289 fclose(modemrx_f[i]);
290 }
291 free(txv1_f);
292 free(rxv1_f);
293 free(txv2_f);
294 free(rxv2_f);
295 free(RSSI_f);
296 free(CCA_f);
297 free(modemrx_f);
298 txv1_f = NULL;
299 rxv1_f = NULL;
300 txv2_f = NULL;
301 rxv2_f = NULL;
302 RSSI_f = NULL;
303 CCA_f = NULL;
304 modemrx_f = NULL;
305 }
306
307 return ret_error;
308 }
309
print_or_compare(FILE ** file,char * produced,size_t str_size,uint dev_nbr,const char * type,uint32_t * err_count,uint32_t op_nbr)310 void print_or_compare(FILE** file, char *produced, size_t str_size, uint dev_nbr,
311 const char* type, uint32_t *err_count, uint32_t op_nbr) {
312
313 if ( comp == 0 ) {
314 fprintf(*file,"%s\n",produced);
315 return;
316 }
317
318 int result ;
319 char file_content[str_size];
320
321 bs_readline(file_content, str_size, *file);
322 result = compare(produced, file_content,str_size);
323 if (result == 0)
324 return;
325
326 char cursor[-result+1];
327 if (file_content[0] == 0) {
328 strcpy(file_content,"<eof>[End of file reached]");
329 fclose(*file);
330 *file = NULL;
331 }
332 *err_count +=1;
333 bs_trace_raw(1,"Comp: Device %i, %s %i differs\n", dev_nbr, type, op_nbr);
334 bs_trace_raw(2,"Comp: Read:\"%s\"\n", file_content);
335 bs_trace_raw(2,"Comp: \"%s\"\n", produced);
336 generate_cursor(cursor, -result);
337 bs_trace_raw(2,"Comp: %s\n", cursor);
338
339 if (stop_on_diff) {
340 bs_trace_error("Simulation terminated due to differences in kill mode\n");
341 }
342
343 if (*err_count > MAX_ERRORS) {
344 fclose(*file);
345 *file = NULL;
346 bs_trace_warning_line("Too many errors in %s file for device %i. It won't be checked anymore\n", type, dev_nbr);
347 }
348 }
349
dump_txv1(tx_el_t * tx,uint dev_nbr)350 void dump_txv1(tx_el_t *tx, uint dev_nbr) {
351 if ( ( txv1_f == NULL ) || ( txv1_f[dev_nbr] == NULL ) ){
352 return;
353 }
354
355 stats[dev_nbr].nbr_txv1++;
356
357 size_t size = 1024 + tx->tx_s.packet_size*3+1;
358 p2G4_txv2_t *txs = &tx->tx_s;
359 char to_print[size];
360 int printed;
361 printed = snprintf(to_print, 1024,
362 "%"PRItime",%"PRItime","
363 "%.6f,"
364 "0x%08X,%u,"
365 "%.6f,"
366 "%"PRItime",%"PRItime","
367 "%u,",
368 txs->start_tx_time, txs->end_tx_time,
369 p2G4_freq_to_d(txs->radio_params.center_freq),
370 (uint32_t)txs->phy_address, txs->radio_params.modulation,
371 p2G4_power_to_d(txs->power_level),
372 txs->abort.abort_time, txs->abort.recheck_time,
373 txs->packet_size);
374
375 if ( tx->tx_s.packet_size > 0 ) {
376 char packetstr[tx->tx_s.packet_size*3+1];
377 bs_hex_dump(packetstr, tx->packet, tx->tx_s.packet_size);
378 sprintf(&to_print[printed],"%s",packetstr);
379 }
380
381 print_or_compare(&txv1_f[dev_nbr],
382 to_print, size, dev_nbr, "Tx",
383 &stats[dev_nbr].nbr_txv1_er,
384 stats[dev_nbr].nbr_txv1);
385 }
386
dump_txv2(tx_el_t * tx,uint dev_nbr)387 void dump_txv2(tx_el_t *tx, uint dev_nbr) {
388 if ( ( txv2_f == NULL ) || ( txv2_f[dev_nbr] == NULL ) ){
389 return;
390 }
391
392 stats[dev_nbr].nbr_txv2++;
393
394 size_t size = 1024 + tx->tx_s.packet_size*3+1;
395 p2G4_txv2_t *txs = &tx->tx_s;
396 char to_print[size];
397 int printed;
398 printed = snprintf(to_print, 1024,
399 "%"PRItime",%"PRItime","
400 "%"PRItime",%"PRItime","
401 "%.6f,"
402 "0x%08X,%u,"
403 "%u,"
404 "%.6f,"
405 "%"PRItime",%"PRItime","
406 "%u,",
407 txs->start_tx_time, txs->end_tx_time,
408 txs->start_packet_time, txs->end_packet_time,
409 p2G4_freq_to_d(txs->radio_params.center_freq),
410 (uint32_t)txs->phy_address, txs->radio_params.modulation,
411 txs->coding_rate,
412 p2G4_power_to_d(txs->power_level),
413 txs->abort.abort_time, txs->abort.recheck_time,
414 txs->packet_size);
415
416 if ( tx->tx_s.packet_size > 0 ) {
417 char packetstr[tx->tx_s.packet_size*3+1];
418 bs_hex_dump(packetstr, tx->packet, tx->tx_s.packet_size);
419 sprintf(&to_print[printed],"%s",packetstr);
420 }
421
422 print_or_compare(&txv2_f[dev_nbr],
423 to_print, size, dev_nbr, "Tx",
424 &stats[dev_nbr].nbr_txv2_er,
425 stats[dev_nbr].nbr_txv2);
426 }
427
428
dump_tx(tx_el_t * tx,uint dev_nbr)429 void dump_tx(tx_el_t *tx, uint dev_nbr){
430 dump_txv1(tx, dev_nbr);
431 dump_txv2(tx, dev_nbr);
432 }
433
dump_rxv1(rx_status_t * rx_st,uint8_t * packet,uint dev_nbr)434 void dump_rxv1(rx_status_t *rx_st, uint8_t* packet, uint dev_nbr){
435 if ( ( rxv1_f == NULL ) || ( rxv1_f[dev_nbr] == NULL ) ) {
436 return;
437 }
438
439 stats[dev_nbr].nbr_rxv1++;
440
441 const uint dbufsi = 2048;
442 size_t size = dbufsi + rx_st->rx_done_s.packet_size*3;
443
444 char to_print[ size + 1];
445 p2G4_rxv2_t *req = &rx_st->rx_s;
446 p2G4_rxv2_done_t *resp = &rx_st->rx_done_s;
447 int printed;
448
449 printed = snprintf(to_print, dbufsi,
450 "%"PRItime",%u,"
451 "0x%08X,%u,"
452 "%.6f,"
453 "%.6f,"
454 "%u,%u,"
455 "%u,"
456 "%u,%u,%"PRItime",%"PRItime","
457 "%i,%u,%"PRItime",%"PRItime","
458 "%"PRItime",%"PRItime",%u,"
459 "%.6f,"
460 "%u,",
461 req->start_time, req->scan_duration,
462 (uint32_t)rx_st->phy_address[0], req->radio_params.modulation,
463 p2G4_freq_to_d(req->radio_params.center_freq),
464 p2G4_power_to_d(req->antenna_gain),
465 req->sync_threshold, req->header_threshold,
466 req->pream_and_addr_duration,
467 req->header_duration, req->error_calc_rate, req->abort.abort_time, req->abort.recheck_time,
468
469 rx_st->tx_nbr,
470 rx_st->biterrors,
471 rx_st->sync_end,
472 rx_st->header_end,
473
474 rx_st->payload_end,
475 resp->rx_time_stamp,
476 resp->status,
477 p2G4_RSSI_value_to_dBm(resp->rssi.RSSI),
478
479 resp->packet_size);
480
481 if ( ( resp->packet_size > 0 ) && ( packet != NULL ) ) {
482 char packetstr[resp->packet_size*3+1];
483 bs_hex_dump(packetstr, packet, resp->packet_size);
484 sprintf(&to_print[printed],"%s",packetstr);
485 }
486
487 print_or_compare(&rxv1_f[dev_nbr],
488 to_print, size, dev_nbr, "Rx",
489 &stats[dev_nbr].nbr_rxv1_er,
490 stats[dev_nbr].nbr_rxv1);
491 }
492
dump_rxv2(rx_status_t * rx_st,uint8_t * packet,uint dev_nbr)493 void dump_rxv2(rx_status_t *rx_st, uint8_t* packet, uint dev_nbr){
494 if ( ( rxv2_f == NULL ) || ( rxv2_f[dev_nbr] == NULL ) ) {
495 return;
496 }
497
498 stats[dev_nbr].nbr_rxv2++;
499
500 const uint dbufsi = 2048; //The print below adds to 623 + commas, + a lot of margin for careless expansion
501 size_t size = dbufsi + rx_st->rx_done_s.packet_size*3;
502
503 char to_print[ size + 1];
504 p2G4_rxv2_t *req = &rx_st->rx_s;
505 p2G4_rxv2_done_t *resp = &rx_st->rx_done_s;
506 int printed;
507
508 printed = snprintf(to_print, dbufsi,
509 "%"PRItime",%u," //20chars + 10chars
510 "%u,\"[", //3 + (4+16*18)
511 req->start_time, req->scan_duration,
512 req->n_addr);
513
514 for (int i = 0 ; i < req->n_addr ; i++) {
515 printed += snprintf(&to_print[printed], dbufsi - printed,
516 "0x%08"PRIx64, (uint64_t)rx_st->phy_address[i]);
517 if (i < (int)req->n_addr - 1) {
518 printed += snprintf(&to_print[printed], dbufsi - printed,
519 ",");
520 }
521 }
522
523 printed += snprintf(&to_print[printed], dbufsi - printed,
524 "]\", %u," //+4
525 "%.6f," //10
526 "%.6f," //10
527
528 "%u," //10
529 "%u,%u," //10+10
530 "%u," //10
531 "%u,%u," //10+10
532
533 "%u," //10
534 "%u," //10
535 "%u," //3"
536
537 "%u," //3
538 "%"PRItime",%"PRItime"," //20+20
539
540 "%i," //10
541 "0x%08"PRIx64"," //16
542 "%u," //10
543 "%u," //10
544 "%"PRItime"," //20
545 "%"PRItime"," //20
546
547 "%"PRItime"," //20
548 "%"PRItime"," //20
549 "%u," //3
550 "%.6f," //10
551
552 "%u,", //10
553 req->radio_params.modulation,
554 p2G4_freq_to_d(req->radio_params.center_freq),
555 p2G4_power_to_d(req->antenna_gain),
556
557 req->acceptable_pre_truncation,
558 req->sync_threshold, req->header_threshold,
559 req->pream_and_addr_duration,
560 req->header_duration, req->error_calc_rate,
561
562 req->forced_packet_duration,
563 req->coding_rate,
564 req->prelocked_tx,
565
566 req->resp_type,
567 req->abort.abort_time, req->abort.recheck_time,
568
569 rx_st->tx_nbr,
570 resp->phy_address,
571 resp->coding_rate,
572 rx_st->biterrors,
573 rx_st->sync_end,
574 rx_st->header_end,
575
576 rx_st->payload_end,
577 resp->rx_time_stamp,
578 resp->status,
579 p2G4_RSSI_value_to_dBm(resp->rssi.RSSI),
580
581 resp->packet_size);
582
583 if ( ( resp->packet_size > 0 ) && ( packet != NULL ) ) {
584 char packetstr[resp->packet_size*3+1];
585 bs_hex_dump(packetstr, packet, resp->packet_size);
586 sprintf(&to_print[printed],"%s",packetstr);
587 }
588
589 print_or_compare(&rxv2_f[dev_nbr],
590 to_print, size, dev_nbr, "Rxv2",
591 &stats[dev_nbr].nbr_rxv2_er,
592 stats[dev_nbr].nbr_rxv2);
593 }
594
dump_rx(rx_status_t * rx_st,uint8_t * packet,uint dev_nbr)595 void dump_rx(rx_status_t *rx_st, uint8_t* packet, uint dev_nbr) {
596 dump_rxv1(rx_st, packet, dev_nbr);
597 dump_rxv2(rx_st, packet, dev_nbr);
598 }
599
dump_RSSImeas(p2G4_rssi_t * RSSI_req,p2G4_rssi_done_t * RSSI_res,uint dev_nbr)600 void dump_RSSImeas(p2G4_rssi_t *RSSI_req, p2G4_rssi_done_t* RSSI_res, uint dev_nbr){
601 if ( ( RSSI_f == NULL ) || ( RSSI_f[dev_nbr] == NULL ) ){
602 return;
603 }
604
605 stats[dev_nbr].nbr_RSSI++;
606
607 size_t size = 512; //size below adds to a max of 53 chars + commas + a lot of margin for careless expansion
608 char to_print[size +1];
609
610 snprintf(to_print, size,
611 "%"PRItime"," //20 chars
612 "%u,%.6f," //3+10
613 "%.6f," //10
614 "%.6f", //10
615 RSSI_req->meas_time,
616 RSSI_req->radio_params.modulation,
617 p2G4_freq_to_d(RSSI_req->radio_params.center_freq),
618 p2G4_power_to_d(RSSI_req->antenna_gain),
619 p2G4_RSSI_value_to_dBm(RSSI_res->RSSI));
620
621 print_or_compare(&RSSI_f[dev_nbr],
622 to_print, size, dev_nbr, "RSSI",
623 &stats[dev_nbr].nbr_RSSI_er,
624 stats[dev_nbr].nbr_RSSI);
625 }
626
627
dump_cca(cca_status_t * cca,uint dev_nbr)628 void dump_cca(cca_status_t *cca, uint dev_nbr) {
629 if ( ( CCA_f == NULL ) || ( CCA_f[dev_nbr] == NULL ) ){
630 return;
631 }
632
633 stats[dev_nbr].nbr_CCA++;
634
635 size_t size = 512; //size below adds to a max of 180chars + commas + a lot of margin for careless expansion
636 char to_print[size +1];
637
638 snprintf(to_print, size,
639 "%"PRItime"," //20
640 "%u," //10
641 "%u," //10
642
643 "%u," //3
644 "%.6f," //10
645 "%.6f," //10
646
647 "%.6f," //10
648 "%.6f," //10
649 "%u," //3
650
651 "%"PRItime",%"PRItime"," //20+20
652
653 "%"PRItime"," //20
654 "%.6f," //10
655 "%.6f," //10
656 "%.6f," //10
657 "%u,%u" //2+2
658 ,
659
660 cca->req.start_time,
661 cca->req.scan_duration,
662 cca->req.scan_period,
663
664 cca->req.radio_params.modulation,
665 p2G4_freq_to_d(cca->req.radio_params.center_freq),
666 p2G4_power_to_d(cca->req.antenna_gain),
667
668 p2G4_RSSI_value_to_dBm(cca->req.mod_threshold),
669 p2G4_RSSI_value_to_dBm(cca->req.rssi_threshold),
670 cca->req.stop_when_found,
671
672 cca->req.abort.abort_time, cca->req.abort.recheck_time,
673
674 cca->resp.end_time,
675 p2G4_RSSI_value_to_dBm(cca->resp.RSSI_ave),
676 p2G4_RSSI_value_to_dBm(cca->resp.RSSI_max),
677 p2G4_RSSI_value_to_dBm(cca->resp.mod_rx_power),
678 cca->resp.mod_found, cca->resp.rssi_overthreshold
679 );
680
681
682
683 print_or_compare(&CCA_f[dev_nbr],
684 to_print, size, dev_nbr, "CCA",
685 &stats[dev_nbr].nbr_CCA_er,
686 stats[dev_nbr].nbr_CCA);
687 }
688
dump_ModemRx(bs_time_t CurrentTime,uint tx_nbr,uint dev_nbr,uint ndev,uint CalNotRecal,p2G4_modemdigparams_t * modem_p,rec_status_t * rx_st,tx_l_c_t * tx_l)689 void dump_ModemRx(bs_time_t CurrentTime, uint tx_nbr, uint dev_nbr, uint ndev, uint CalNotRecal, p2G4_modemdigparams_t *modem_p, rec_status_t *rx_st, tx_l_c_t *tx_l ){
690 if ( ( modemrx_f == NULL ) || ( modemrx_f[dev_nbr] == NULL ) ) {
691 return;
692 }
693
694 stats[dev_nbr].nbr_modemrx++;
695
696 #define _ModemRxStrSize 4096
697 size_t size = _ModemRxStrSize;
698 char to_print[_ModemRxStrSize +1];
699
700 uint printed = snprintf(to_print, _ModemRxStrSize,
701 "%"PRItime",%u,"
702 "%u,%f,%u,"
703 "%u,"
704 "%e,%e,"
705 "%f,%f,%f",
706 CurrentTime,
707 tx_nbr,
708
709 CalNotRecal,
710 p2G4_freq_to_d(modem_p->center_freq),
711 modem_p->modulation,
712
713 modem_p->coding_rate,
714
715 rx_st->BER/(double)RAND_PROB_1,
716 rx_st->sync_prob/(double)RAND_PROB_1,
717
718 rx_st->SNR_total,
719 rx_st->SNR_analog_o,
720 rx_st->SNR_ISI);
721
722 for ( uint tx = 0 ; tx< ndev; tx++){
723 if ( tx_l->used[tx] ){
724 printed += snprintf(&to_print[printed], _ModemRxStrSize-printed, ",%f,%f", rx_st->att[tx], rx_st->rx_pow[tx]);
725 } else {
726 printed += snprintf(&to_print[printed], _ModemRxStrSize-printed, ",NaN, NaN");
727 }
728 if (printed >= _ModemRxStrSize){
729 bs_trace_warning_line("Too many devices, ModemRx dumping disabled\n");
730 fclose(modemrx_f[dev_nbr]);
731 modemrx_f[dev_nbr] = NULL;
732 }
733 }
734
735 print_or_compare(&modemrx_f[dev_nbr],
736 to_print, size, dev_nbr, "ModemRx",
737 &stats[dev_nbr].nbr_modemrx_er,
738 stats[dev_nbr].nbr_modemrx);
739 }
740