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