1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "bs_tracing.h"
7 #include "bs_oswrap.h"
8 #include "bs_pc_2G4.h"
9 #include "bs_pc_2G4_types.h"
10 #include "bs_pc_2G4_utils.h"
11 #include "bs_playback_args.h"
12 #include <stdio.h>
13 #include <string.h>
14 #include <inttypes.h>
15 
16 /**
17  * This devices plays back the activity of another device as it was recorded
18  * by the phy in a previous simulation
19  * (Note that powers and antenna gains will have minor roundings)
20  */
21 
22 static FILE* tx_f= NULL, *rx_f= NULL, *RSSI_f = NULL;
23 
24 static p2G4_tx_t tx_s;
25 uint8_t *tx_packet = NULL;
26 static p2G4_rssi_t RSSI_s;
27 static p2G4_rx_t rx_s;
28 
open_one_input_file(const char * inputf,const char * type,char * filename,FILE ** file)29 static void open_one_input_file(const char* inputf, const char *type,
30                                 char *filename, FILE **file){
31   sprintf(filename,"%s.%s.csv",inputf, type);
32   *file = bs_fopen(filename, "r");
33   bs_skipline(*file); //skip heading
34   if ( feof(*file) ){
35     bs_trace_raw(3,"%s file %s is empty => will not use it\n",type, filename);
36     fclose(*file);
37     *file = NULL;
38   }
39 }
40 
open_input_files(const char * inputf,playback_args_t * args)41 static void open_input_files(const char* inputf, playback_args_t* args){
42   char *filename;
43   filename = bs_calloc(strlen(inputf) + 10,sizeof(char));
44 
45   if ( args->rxoff == false ) {
46     open_one_input_file(inputf, "Rx", filename, &rx_f);
47   }
48   if ( args->txoff == false ) {
49     open_one_input_file(inputf, "Tx", filename, &tx_f);
50   }
51   if ( args->rssioff == false ) {
52     open_one_input_file(inputf, "RSSI", filename, &RSSI_f);
53   }
54 
55   free(filename);
56 
57   if ((RSSI_f == NULL) && (tx_f == NULL) && (rx_f == NULL)) {
58     bs_trace_warning_line("No input in any of the files??\n");
59   }
60 }
61 
close_input_files()62 void close_input_files(){
63   if (tx_f !=NULL)
64     fclose(tx_f);
65   if (rx_f !=NULL)
66     fclose(rx_f);
67   if (RSSI_f !=NULL)
68     fclose(RSSI_f);
69 }
70 
read_next_tx()71 void read_next_tx(){
72 
73   if (!tx_f) {
74     ;
75   } else if (feof(tx_f)) {
76     fclose(tx_f);
77     tx_f = NULL;
78   } else {
79     int read;
80     double center_freq = 0;
81     double power = 0;
82     p2G4_freq_t freq;
83     p2G4_tx_t *txs = &tx_s;
84     read = fscanf(tx_f,
85         "%"SCNtime",%"SCNtime",\
86         %lf,\
87         0x%X,%"SCNu16",\
88         %lf,\
89         %"SCNtime",%"SCNtime",\
90         %"SCNu16",",
91         &txs->start_time,
92         &txs->end_time,
93 
94         &center_freq,
95 
96         &txs->phy_address,
97         &txs->radio_params.modulation,
98 
99         &power,
100 
101         &txs->abort.abort_time,
102         &txs->abort.recheck_time,
103 
104         &txs->packet_size);
105 
106     p2G4_freq_from_d(center_freq, 0, &freq);
107 
108     txs->radio_params.center_freq = freq;
109     txs->power_level = p2G4_power_from_d(power);
110 
111     if (read < 9) {
112       if ((read > 0) || !feof(tx_f)) //otherwise it was probably an empty trailing line
113         bs_trace_warning_line("Corrupted input Tx file disabling it\n");
114       fclose(tx_f);
115       tx_f = NULL;
116     } else {
117       if (txs->packet_size > 0) {
118         char buffer[txs->packet_size*3 + 1];
119         if ( tx_packet != NULL ) free(tx_packet);
120         tx_packet = bs_calloc(txs->packet_size, sizeof(char));
121         bs_readline(buffer, txs->packet_size*3 + 1, tx_f);
122         bs_read_hex_dump(buffer,tx_packet, txs->packet_size);
123       } else {
124         bs_skipline(tx_f); //skip \n
125       }
126     }
127   }
128 
129   if (tx_f == NULL){
130     tx_s.start_time = TIME_NEVER;
131   }
132 }
133 
read_next_rx()134 void read_next_rx(){
135 
136   if ( !rx_f ){
137     ;
138   } else if (feof(rx_f)) {
139     fclose(rx_f);
140     rx_f = NULL;
141   } else {
142     int read;
143     double center_freq = 0;
144     double ant_gain = 0;
145     p2G4_freq_t freq;
146     p2G4_rx_t *Req = &rx_s;
147     read = fscanf(rx_f,
148         "%"SCNtime",%"SCNu32",%"SCNx32",%"SCNu16",\
149         %lf,%lf,"
150         "%"SCNu16",%"SCNu16"\
151         ,%"SCNu16",\
152         %"SCNu16",%"SCNu32",%"SCNtime",%"SCNtime"",
153         &Req->start_time,
154         &Req->scan_duration,
155         &Req->phy_address,
156         &Req->radio_params.modulation,
157 
158         &center_freq,
159         &ant_gain,
160 
161         &Req->sync_threshold,
162         &Req->header_threshold,
163 
164         &Req->pream_and_addr_duration,
165 
166         &Req->header_duration,
167         &Req->bps,
168         &Req->abort.abort_time,
169         &Req->abort.recheck_time
170         );
171 
172     p2G4_freq_from_d(center_freq, 0, &freq);
173 
174     Req->radio_params.center_freq = freq;
175     Req->antenna_gain = p2G4_power_from_d(ant_gain);
176 
177     if ( read < 12 ){
178       if ( ( read > 0 ) || !feof(rx_f) ) //otherwise it was probably an empty trailing line
179         bs_trace_warning_line("Corrupted input Rx file disabling it (%i %i)\n",read, feof(rx_f));
180       fclose(rx_f);
181       rx_f = NULL;
182     } else {
183       bs_skipline(rx_f); //skip remainder of the line
184     }
185   }
186 
187   if (rx_f == NULL){
188     rx_s.start_time = TIME_NEVER;
189   }
190 }
191 
read_next_RSSI()192 void read_next_RSSI() {
193 
194   if (!RSSI_f){
195     ;
196   } else if (feof(RSSI_f)) {
197     fclose(RSSI_f);
198     RSSI_f = NULL;
199   } else {
200     int read;
201     double center_freq = 0;
202     double ant_gain = 0;
203     p2G4_rssi_t *Req = &RSSI_s;
204     p2G4_freq_t freq;
205     read = fscanf(RSSI_f,
206         "%"SCNtime","
207         "%"SCNu16","
208         "%lf,"
209         "%lf",
210         &Req->meas_time,
211         &Req->radio_params.modulation,
212         &center_freq,
213         &ant_gain
214         );
215 
216     p2G4_freq_from_d(center_freq, 0, &freq);
217 
218     Req->radio_params.center_freq = freq;
219     Req->antenna_gain = p2G4_power_from_d(ant_gain);
220 
221     if ( read < 3 ){
222       if ( ( read > 0 ) || !feof(RSSI_f) ) //otherwise it was probably an empty trailing line
223         bs_trace_warning_line("Corrupted input RSSI file disabling it\n");
224       fclose(RSSI_f);
225       RSSI_f = NULL;
226     } else {
227       bs_skipline(RSSI_f); //skip remainder of the line
228     }
229   }
230 
231   if (RSSI_f == NULL){
232     RSSI_s.meas_time = TIME_NEVER;
233   }
234 }
235 
main(int argc,char * argv[])236 int main(int argc, char *argv[]) {
237   playback_args_t args;
238   uint8_t *packet_ptr;
239 
240   bs_playback_argsparse(argc, argv, &args);
241 
242   open_input_files(args.inputf, &args);
243 
244   p2G4_dev_initcom_c(args.device_nbr, args.s_id, args.p_id, NULL);
245 
246   read_next_tx();
247   read_next_rx();
248   read_next_RSSI();
249 
250   while ((tx_f !=  NULL) || (rx_f!= NULL) || (RSSI_f != NULL)) {
251     int result = -1;
252     if ((tx_f !=  NULL) &&
253         (tx_s.start_time < rx_s.start_time) &&
254         (tx_s.start_time < RSSI_s.meas_time)) {
255       p2G4_tx_done_t tx_done_s;
256       result =  p2G4_dev_req_tx_c_b(&tx_s, tx_packet, &tx_done_s);
257       read_next_tx();
258     } else if ((rx_f !=  NULL) &&
259               (rx_s.start_time < tx_s.start_time) &&
260               (rx_s.start_time < RSSI_s.meas_time)) {
261       p2G4_rx_done_t rx_done_s;
262       packet_ptr = NULL;
263       result = p2G4_dev_req_rx_c_b(&rx_s, &rx_done_s, &packet_ptr, 0, NULL);
264       free(packet_ptr);
265       read_next_rx();
266     } else if ((RSSI_f !=  NULL) &&
267               (RSSI_s.meas_time < rx_s.start_time) &&
268               (RSSI_s.meas_time < tx_s.start_time)) {
269       p2G4_rssi_done_t RSSI_done_s;
270       result = p2G4_dev_req_RSSI_c_b(&RSSI_s, &RSSI_done_s);
271       read_next_RSSI();
272     }
273     if (result == -1) {
274       bs_trace_raw(3,"We have been disconnected\n");
275       break;
276     }
277   }
278 
279   close_input_files();
280   if (tx_packet != NULL) free(tx_packet);
281 
282   p2G4_dev_disconnect_c();
283   return 0;
284 }
285