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