1 /*
2 * Copyright 2018 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "p2G4_args.h"
7 #include <stdlib.h>
8 #include <string.h>
9 #include <limits.h>
10 #include "bs_tracing.h"
11 #include "bs_types.h"
12 #include "bs_oswrap.h"
13
14 char executable_name[] = "bs_2G4_phy_v1";
15
component_print_post_help()16 void component_print_post_help(){
17 fprintf(stdout,"\n"
18 " Note regarding multiple modems: the default modem (and the default modem arguments)\n"
19 " are assigned to any modem which does not get assigned any other modem with\n"
20 " -modem<nbr>=<modem>.\n"
21 "\n"
22 "bs_2G4_phy_v1: Emulates the physical layer, including all devices modem's and the radio channel\n");
23 }
24
25 #define MAXPARAMS_LIBRARIES 1024
26
27 static char default_channel[] = "NtNcable";
28 static char default_modem[] = "Magic";
29
allocate_modems_params(p2G4_args_t * args)30 static inline void allocate_modems_params(p2G4_args_t *args){
31 args->modem_name = (char **)bs_calloc(args->n_devs, sizeof(char*));
32 args->modem_argc = (uint *)bs_calloc(args->n_devs, sizeof(uint));
33 args->modem_argv = (char ***)bs_calloc(args->n_devs, sizeof(char**));
34 }
35
36 p2G4_args_t *args_g;
37
cmd_trace_lvl_found(char * argv,int offset)38 static void cmd_trace_lvl_found(char * argv, int offset){
39 bs_trace_set_level(args_g->verb);
40 }
phy_id_found(char * argv,int offset)41 static void phy_id_found(char * argv, int offset){
42 bs_trace_set_prefix_phy(args_g->p_id);
43 }
44 double sim_length;
sim_length_found(char * argv,int offset)45 static void sim_length_found(char * argv, int offset){
46 args_g->sim_length = sim_length;
47 bs_trace_raw(9,"cmdarg: sim_length set to %"PRItime"\n", args_g->sim_length);
48 }
stop_found(char * argv,int offset)49 static void stop_found(char * argv, int offset){
50 args_g->compare = true;
51 }
dump_found(char * argv,int offset)52 static void dump_found(char * argv, int offset){
53 args_g->dont_dump = false;
54 bs_trace_raw(9,"cmdarg: dump mode set\n");
55 }
channel_found(char * argv,int offset)56 static void channel_found(char * argv, int offset){
57 bs_trace_raw(9,"cmdarg: channel set to libChannel_%s.so\n",args_g->channel_name);
58 }
defmodem_found(char * argv,int offset)59 static void defmodem_found(char * argv, int offset){
60 bs_trace_raw(9,"cmdarg: defmodem set to libModem_%s.so\n",args_g->defmodem_name);
61 }
62 /**
63 * Check the arguments provided in the command line: set args based on it
64 * or defaults, and check they are correct
65 */
p2G4_argsparse(int argc,char * argv[],p2G4_args_t * args)66 void p2G4_argsparse(int argc, char *argv[], p2G4_args_t *args)
67 {
68
69 args_g = args;
70 bs_args_struct_t args_struct[] = {
71 ARG_TABLE_S_ID,
72 { false, false , false, "p_id", "phy_id", 's', (void*)&args->p_id, phy_id_found, "(2G4) String which uniquely identifies the phy inside the simulation"},
73 /*manual,mandatory,switch,option, name , type, destination, callback, , description*/
74 { true, true , false, "D", "number_devices", 'u', (void*)&args->n_devs, NULL, "Number of devices which will connect in this phy"},
75 { false, false , false, "sim_length", "sim_length", 'f', (void*)&sim_length, sim_length_found,"In us, length of the simulation"},
76 ARG_TABLE_VERB,
77 ARG_TABLE_SEED,
78 ARG_TABLE_COLOR,
79 ARG_TABLE_NOCOLOR,
80 ARG_TABLE_FORCECOLOR,
81 { false, false , true, "nodump", "no_dump", 'b', (void*)&args->dont_dump, NULL, "Will not dump (or compare) any files"},
82 { false, false , true, "dump_imm", "dump_imm", 'b', (void*)&args->dump_imm, NULL, "When dumping, do not buffer more than a line"},
83 { false, false , true, "dump", "dump", 'b', (void*)NULL, dump_found, "Revert -nodump option (note that the last -nodump/dump set in the command line prevails)"},
84 { false, false , true, "crcerr_data","crcerr", 'b', (void*)&args->crcerr_data, NULL, "Provide uncorrupted packet to device attempting to receive even if packet has a CRC error or reception is aborted midway (disabled by default)"},
85 { false, false , true, "c", "compare", 'b', (void*)&args->compare, NULL, "Run in compare mode: will compare instead of dumping"},
86 { false, false , true, "stop_on_diff","stop", 'b', (void*)&args->stop_on_diff, stop_found, "Run in compare mode, but stop as soon as a difference is found"},
87 { false, false , false, "channel", "channel", 's', (void*)&args->channel_name, channel_found, "Which channel will be used ( lib/lib_2G4Channel_<channel>.so ). By default NtNcable"},
88 { false, false , false, "defmodem", "modem", 's', (void*)&args->defmodem_name, defmodem_found,"Which modem will be used by default for all devices ( lib/lib_2G4Modem_<modem>.so ). By default Magic"},
89 { true, false , false, "modem<nbr>", "modem", 's', (void*)NULL, NULL, "Which modem will be used for the device <nbr> ( lib/lib_2G4Modem_<modem>.so )"},
90 { true, false , false, "argschannel","arg", 'l', (void*)NULL, NULL, "Following arguments (until end or new -args*) will be passed to the channel"},
91 { true, false , false, "argsdefmodem","arg", 'l', (void*)NULL, NULL, "Following arguments (until end or new -args*) will be passed to the modems set to be the default modem"},
92 { true, false , false, "argsmodem<nbr>","arg", 'l', (void*)NULL, NULL, "Following arguments (until end or new -args*) will be passed to the modem of the device <nbr>"},
93 { true, false , false, "argsmain","arg", 'l', (void*)NULL, NULL, "Following arguments (until end or new -args*) will be passed to the phy itself (default)"},
94 ARG_TABLE_ENDMARKER
95 };
96
97 #define MAIN 0
98 #define CHANNEL 1
99 #define DEFMODEM 2
100 #define MODEM 1000
101
102 uint parsing = MAIN;
103 static char default_phy[] ="2G4";
104
105 args->verb = 2;
106 bs_trace_set_level(args->verb);
107 args->rseed = 0xFFFF;
108 args->sim_length = TIME_NEVER - 1000000000 ; //1Ksecond before never by default
109
110 args->channel_argv = bs_calloc(MAXPARAMS_LIBRARIES*2, sizeof(char *));
111 args->channel_argc = 0;
112 args->channel_name = default_channel;
113
114 args->defmodem_argv = args->channel_argv + MAXPARAMS_LIBRARIES;
115 args->defmodem_argc = 0;
116 args->defmodem_name = default_modem;
117
118 args->modem_argv = NULL;
119 args->modem_argc = NULL;
120 args->modem_name = NULL;
121
122 char trace_prefix[] = "cmdarg: ";
123 bs_args_set_trace_prefix(trace_prefix);
124
125 int offset;
126 uint modem_nbr;
127
128 for (int i=1; i<argc; i++){
129
130 //First we check if we are getting the option to switch the type of args:
131 if ((strncmp(argv[i], "-args",5)==0) || (strncmp(argv[i], "--args",6)==0)) {
132 if (bs_is_option(argv[i], "argschannel", 0)) {
133 parsing = CHANNEL;
134 } else if ( bs_is_option(argv[i], "argsdefmodem", 0)) {
135 parsing = DEFMODEM;
136 } else if ( bs_is_option(argv[i], "argsmain", 0)) {
137 parsing = MAIN;
138 } else if (bs_is_multi_opt(argv[i], "argsmodem", &modem_nbr ,0)) {
139 if ( args->n_devs == 0 ) {
140 bs_trace_error_line("cmdarg: tried to set the modem args for a device"
141 " (%i) before setting the number of devices (-D="
142 "<nbr>) (%s)\n\n""\n",
143 modem_nbr, args->n_devs, argv[i]);
144 }
145 if ( modem_nbr >= args->n_devs ) {
146 bs_trace_error_line("cmdarg: tried to set the modem args for a device "
147 "%i >= %i number of avaliable devices (%s)\n\n""\n",
148 modem_nbr, args->n_devs, argv[i]);
149 }
150 if ( args->modem_name[modem_nbr] == NULL ) {
151 bs_trace_error_line("cmdarg: tried to set the modem args for a modem "
152 "(%i) not yet specified (%s)\n\n""\n",
153 modem_nbr, argv[i]);
154 }
155 parsing = MODEM + modem_nbr;
156 } else {
157 bs_args_print_switches_help(args_struct);
158 bs_trace_error_line("Incorrect args option '%s'\n",argv[i]);
159 }
160 continue;
161 }
162
163 //Otherwise, depending on what we are parsing now, we handle things:
164 if ( parsing == MAIN ){
165 if ( !bs_args_parse_one_arg(argv[i], args_struct) ){
166 if ((offset = bs_is_option(argv[i], "D", 1)) > 0) {
167 if (args->n_devs != 0) {
168 bs_trace_error_line("The number of devices (-D) can only be "
169 "specified once, found as argument %i: %s\n",
170 i, argv[i]);
171 }
172 bs_read_optionparam(&argv[i][offset], (void*)&(args->n_devs), 'u', "nbr_devices");
173 allocate_modems_params(args);
174
175 } else if ((offset = bs_is_multi_opt(argv[i], "modem", &modem_nbr, 1))>0) {
176 if ( args->n_devs == 0 ) {
177 bs_trace_error_line("cmdarg: tried to set the modem for a device "
178 "(%i) before setting the number of devices (-D"
179 "=<nbr>) (%s)\n",
180 modem_nbr, args->n_devs, argv[i]);
181 }
182 if ( modem_nbr >= args->n_devs ) {
183 bs_trace_error_line("cmdarg: tried to set the modem for a device "
184 "%i >= %i number of avaliable devices (%s)\n",
185 modem_nbr, args->n_devs, argv[i]);
186 }
187 args->modem_name[modem_nbr] = &argv[i][offset];
188 bs_trace_raw(9, "cmdarg: modem[%u] set to libModem_%s.so\n",
189 modem_nbr, args->modem_name[modem_nbr]);
190 }
191 else {
192 bs_args_print_switches_help(args_struct);
193 bs_trace_error_line("Incorrect phy main option %s\n",argv[i]);
194 }
195 }
196
197 } else if ( parsing == CHANNEL ){
198 if ( args->channel_argc >= MAXPARAMS_LIBRARIES ) {
199 bs_trace_error_line("Too many channel command line parameters (at '%s'), maximum is %i\n", argv[i],MAXPARAMS_LIBRARIES);
200 } else {
201 args->channel_argv[ args->channel_argc ] = argv[i];
202 bs_trace_raw(9,"cmdarg: adding '%s' to channel args[%i]\n", argv[i], args->channel_argc);
203 args->channel_argc++;
204 }
205
206 } else if ( parsing == DEFMODEM ){
207 if ( args->channel_argc >= MAXPARAMS_LIBRARIES ) {
208 bs_trace_error_line("Too many defmodem command line parameters (at '%s'), maximum is %i\n", argv[i],MAXPARAMS_LIBRARIES);
209 } else {
210 args->defmodem_argv[ args->defmodem_argc ] = argv[i];
211 bs_trace_raw(9,"cmdarg: adding '%s' to defmodem args[%i]\n", argv[i], args->defmodem_argc);
212 args->defmodem_argc++;
213 }
214
215 } else if ( parsing >= MODEM ){
216 uint modem_nbr = parsing - MODEM;
217 if ( args->modem_argc[modem_nbr] >= MAXPARAMS_LIBRARIES ) {
218 bs_trace_error_line("Too many modem%i command line parameters (at '%s'), maximum is %i\n",modem_nbr, argv[i],MAXPARAMS_LIBRARIES);
219 } else {
220 if ( args->modem_argc[modem_nbr] == 0 ){
221 args->modem_argv[modem_nbr] = bs_calloc(MAXPARAMS_LIBRARIES, sizeof(char *));
222 }
223 args->modem_argv[modem_nbr][ args->modem_argc[modem_nbr] ] = argv[i];
224 bs_trace_raw(9,"cmdarg: adding '%s' to modem%i args[%i]\n", argv[i], modem_nbr, args->modem_argc[modem_nbr]);
225 args->modem_argc[modem_nbr]++;
226 }
227 }
228 }
229
230 if ( args->s_id == NULL ) {
231 bs_args_print_switches_help(args_struct);
232 bs_trace_error_line("The command line option <simulation ID> needs to be set\n");
233 }
234 if ( args->p_id == NULL ){
235 args->p_id = default_phy;
236 bs_trace_set_prefix_phy(args->p_id);
237 }
238 if ( args->n_devs == 0 ) {
239 bs_args_print_switches_help(args_struct);
240 bs_trace_error_line("The command line option <number_devices> needs to be set\n");
241 }
242 //for all modems which didn't get set to something else, we set them to the default modem
243 for (uint dev = 0; dev < args->n_devs ; dev ++){
244 if (args->modem_name[dev] == NULL) { //if we didnt set for this modem already
245 args->modem_name[dev] = args->defmodem_name;
246 args->modem_argv[dev] = args->defmodem_argv;
247 args->modem_argc[dev] = args->defmodem_argc;
248 }
249 }
250 }
251
p2G4_clear_args_struct(p2G4_args_t * args)252 void p2G4_clear_args_struct(p2G4_args_t *args){
253 for (uint n = 0; n < args->n_devs ; n++) {
254 if ((args->modem_argv[n] != NULL) && (args->modem_argv[n] != args->defmodem_argv)) {
255 free(args->modem_argv[n]);
256 }
257 }
258
259 if ( args->channel_argv != NULL ){
260 free(args->channel_argv);
261 }
262 if (args->modem_name != NULL) {
263 free(args->modem_name);
264 }
265
266 if (args->modem_argc != NULL) {
267 free(args->modem_argc);
268 }
269
270 if (args->modem_argv != NULL) {
271 free(args->modem_argv);
272 }
273 }
274