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