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 ¢er_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 ¢er_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 ¢er_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