1 /*
2  * Copyright (c) 2017 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Common command line arguments and overall command line argument handling
8  * for Zephyr Babblesim boards.
9  *
10  * Note that this is code runs in the native simulator runner context,
11  * and not in any embedded CPU context.
12  * This file should therefore only be built once for all CPUs.
13  */
14 
15 #include <stdint.h>
16 #include <stdbool.h>
17 #include <limits.h>
18 #include "bs_cmd_line.h"
19 #include "bs_cmd_line_typical.h"
20 #include "bs_dynargs.h"
21 #include "bs_tracing.h"
22 #include "bs_dump_files.h"
23 #include "bs_rand_main.h"
24 #include "nsi_cpu_if.h"
25 #include "nsi_tasks.h"
26 #include "nsi_main.h"
27 #include "nsi_cpu_ctrl.h"
28 #include "NRF_HWLowL.h"
29 #include "NHW_misc.h"
30 
31 static bs_args_struct_t *args_struct;
32 /* Direct use of this global is deprecated, use bsim_args_get_global_device_nbr() instead */
33 uint global_device_nbr;
34 
35 #define MAXPARAMS_TESTCASES 1024
36 
37 static struct bsim_global_args_t {
38 	BS_BASIC_DEVICE_OPTIONS_FIELDS
39 } global_args;
40 
41 static bool nosim;
42 
cmd_trace_lvl_found(char * argv,int offset)43 static void cmd_trace_lvl_found(char *argv, int offset)
44 {
45 	bs_trace_set_level(global_args.verb);
46 }
47 
cmd_gdev_nbr_found(char * argv,int offset)48 static void cmd_gdev_nbr_found(char *argv, int offset)
49 {
50 	bs_trace_set_prefix_dev(global_args.global_device_nbr);
51 }
52 
print_no_sim_warning(void)53 static void print_no_sim_warning(void)
54 {
55 	bs_trace_warning("Neither simulation id or the device number "
56 			"have been set. I assume you want to run "
57 			"without a BabbleSim phy (-nosim)\n");
58 	bs_trace_warning("If this is not what you wanted, check with "
59 			"--help how to set them\n");
60 	bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 "
61 			"and nosim\n");
62 }
63 
print_mcus_info(char * argv,int offset)64 static void print_mcus_info(char *argv, int offset)
65 {
66 	(void) argv;
67 	(void) offset;
68 	bs_trace_raw(0, "CPU  #,       Name  , Autostart\n");
69 	bs_trace_raw(0, "-------------------------------\n");
70 	for (int i = 0; i < NSI_N_CPUS; i++) {
71 		bs_trace_raw(0, "CPU %2i, %12s,    %i\n",
72 			     i, nhw_get_core_name(i), nsi_cpu_get_auto_start(i));
73 	}
74 }
75 
bsim_register_basic_args(void)76 static void bsim_register_basic_args(void)
77 {
78 #define args (&global_args)
79 	/* This define allows reusing the definitions provided by the utils library */
80 	static bs_args_struct_t args_struct_toadd[] = {
81 		ARG_TABLE_S_ID,
82 		ARG_TABLE_P_ID_2G4,
83 		ARG_TABLE_DEV_NBR,
84 		ARG_TABLE_GDEV_NBR,
85 		ARG_TABLE_VERB,
86 		ARG_TABLE_SEED,
87 		ARG_TABLE_COLOR,
88 		ARG_TABLE_NOCOLOR,
89 		ARG_TABLE_FORCECOLOR,
90 		{
91 		.is_switch = true,
92 		.option = "nosim",
93 		.type = 'b',
94 		.dest = (void *)&nosim,
95 		.descript = "Do not connect to the Physical layer simulator"
96 		},
97 		BS_DUMP_FILES_ARGS,
98 		{
99 		.manual = true,
100 		.option = "argstest",
101 		.name = "arg",
102 		.type = 'l',
103 		.descript = "The arguments that follow will be passed straight to the testcase "
104 			"init function (Note: If more than 1 MCU is present, argtest corresponds "
105 			"to argstests" NSI_STRINGIFY(NSI_PRIMARY_MCU_N) " )"
106 		},
107 		{
108 		.manual = true,
109 		.option = "argstest<n>",
110 		.name = "arg",
111 		.type = 'l',
112 		.descript = "The arguments that follow will be passed straight to cpu<n>'s "
113 			"testcase init function), where 0 <= n < " NSI_STRINGIFY(NSI_N_CPUS)
114 			" is the cpu number"
115 		},
116 		{
117 		.manual = true,
118 		.option = "argsmain",
119 		.name = "arg",
120 		.type = 'l',
121 		.descript = "The arguments that follow will be passed to main (default)"
122 		},
123 		{
124 		.is_switch = true,
125 		.option = "cpu_print_info",
126 		.call_when_found = print_mcus_info,
127 		.type = 'b',
128 		.descript = "Print information about each MCUs",
129 		},
130 		ARG_TABLE_ENDMARKER
131 	};
132 #undef args
133 
134 	bs_add_dynargs(&args_struct, args_struct_toadd);
135 }
136 
137 NSI_TASK(bsim_register_basic_args, PRE_BOOT_1, 0);
138 
bsim_cleanup_args(void)139 static void bsim_cleanup_args(void)
140 {
141 	bs_cleanup_dynargs(&args_struct);
142 }
143 
144 NSI_TASK(bsim_cleanup_args, ON_EXIT_POST, 0);
145 
bs_add_extra_dynargs(bs_args_struct_t * args_struct_toadd)146 void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd)
147 {
148 	bs_add_dynargs(&args_struct, args_struct_toadd);
149 }
150 
nsif_cpun_save_test_arg(int n,char * c)151 static void nsif_cpun_save_test_arg(int n, char *c)
152 {
153 	F_TRAMP_LIST(NATIVE_SIMULATOR_IF void nsif_cpu, _save_test_arg(char *argv))
154 
155 	void(*fptrs[])(char *) = {
156 		F_TRAMP_TABLE(nsif_cpu, _save_test_arg)
157 	};
158 
159 	fptrs[n](c);
160 }
161 
162 /**
163  * Check the arguments provided in the command line: set args based on it or
164  * defaults, and check they are correct
165  */
nsi_handle_cmd_line(int argc,char * argv[])166 void nsi_handle_cmd_line(int argc, char *argv[])
167 {
168 	const char *bogus_sim_id = "bogus";
169 
170 	bs_args_set_defaults(args_struct);
171 	global_args.verb = 2;
172 	bs_trace_set_level(global_args.verb);
173 
174 	static const char default_phy[] = "2G4";
175 
176 	enum {Main = 0, Test = 1} parsing = Main;
177 	uint test_cpu_n;
178 
179 	for (int i = 1; i < argc; i++) {
180 		if (bs_is_option(argv[i], "argstest", 0)) {
181 			parsing = Test;
182 			test_cpu_n = NSI_PRIMARY_MCU_N;
183 			continue;
184 		} else if (bs_is_multi_opt(argv[i], "argstest", &test_cpu_n, 0)) {
185 			parsing = Test;
186 			continue;
187 		} else if (bs_is_option(argv[i], "argsmain", 0)) {
188 			parsing = Main;
189 			continue;
190 		}
191 
192 		if (parsing == Main) {
193 			if (!bs_args_parse_one_arg(argv[i], args_struct)) {
194 				bs_args_print_switches_help(args_struct);
195 				bs_trace_error_line("Incorrect option %s\n",
196 						    argv[i]);
197 			}
198 		} else if (parsing == Test) {
199 			nsif_cpun_save_test_arg(test_cpu_n, argv[i]);
200 		} else {
201 			bs_trace_error_line("Bad error\n");
202 		}
203 	}
204 
205 	/**
206 	 * If the user did not set the simulation id or device number
207 	 * we assume he wanted to run with nosim (but warn him)
208 	 */
209 	if ((!nosim) && (global_args.s_id == NULL) && (global_args.device_nbr == UINT_MAX)) {
210 		print_no_sim_warning();
211 		nosim = true;
212 	}
213 	if (nosim) {
214 		if (global_args.s_id == NULL) {
215 			global_args.s_id = (char *)bogus_sim_id;
216 		}
217 		if (global_args.device_nbr == UINT_MAX) {
218 			global_args.device_nbr = 0;
219 		}
220 		hwll_set_nosim(true);
221 	}
222 
223 	if (global_args.device_nbr == UINT_MAX) {
224 		bs_args_print_switches_help(args_struct);
225 		bs_trace_error_line("The command line option <device number> "
226 				    "needs to be set\n");
227 	}
228 	if (global_args.global_device_nbr == UINT_MAX) {
229 		global_args.global_device_nbr = global_args.device_nbr;
230 		bs_trace_set_prefix_dev(global_args.global_device_nbr);
231 	}
232 	global_device_nbr = global_args.global_device_nbr;
233 	if (!global_args.s_id) {
234 		bs_args_print_switches_help(args_struct);
235 		bs_trace_error_line("The command line option <simulation ID> "
236 				    "needs to be set\n");
237 	}
238 	if (!global_args.p_id) {
239 		global_args.p_id = (char *)default_phy;
240 	}
241 
242 	if (global_args.rseed == UINT_MAX) {
243 		global_args.rseed = 0x1000 + global_args.device_nbr;
244 	}
245 
246 	bs_random_init(global_args.rseed);
247 }
248 
249 /*
250  * Get the simulation id
251  */
bsim_args_get_simid(void)252 char *bsim_args_get_simid(void)
253 {
254 	return global_args.s_id;
255 }
256 
257 /*
258  * Get this device number in the simulation, as it is
259  * known in the overall simulation.
260  * In general this is the device number you want
261  */
bsim_args_get_global_device_nbr(void)262 unsigned int bsim_args_get_global_device_nbr(void)
263 {
264 	return global_args.global_device_nbr;
265 }
266 
267 /*
268  * Get this device number in the 2G4 Phy simulation
269  */
bsim_args_get_2G4_device_nbr(void)270 unsigned int bsim_args_get_2G4_device_nbr(void)
271 {
272 	return global_args.device_nbr;
273 }
274 
275 /*
276  * Get this device number in the 2G4 Phy simulation
277  */
bsim_args_get_2G4_phy_id(void)278 char *bsim_args_get_2G4_phy_id(void)
279 {
280 	return global_args.p_id;
281 }
282 
get_simid(void)283 char *get_simid(void)
284 {
285 	return bsim_args_get_simid();
286 }
287 
get_device_nbr(void)288 unsigned int get_device_nbr(void)
289 {
290 	return bsim_args_get_global_device_nbr();
291 }
292