| /* |
| * Copyright (c) 2017 Oticon A/S |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Common command line arguments and overall command line argument handling |
| * for Zephyr Babblesim boards. |
| * |
| * Note that this is code runs in the native simulator runner context, |
| * and not in any embedded CPU context. |
| * This file should therefore only be built once for all CPUs. |
| */ |
| |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <limits.h> |
| #include <string.h> |
| #include "bs_cmd_line.h" |
| #include "bs_cmd_line_typical.h" |
| #include "bs_dynargs.h" |
| #include "bs_tracing.h" |
| #include "bs_dump_files.h" |
| #include "bs_rand_main.h" |
| #include "nsi_cpu_if.h" |
| #include "nsi_tasks.h" |
| #include "nsi_main.h" |
| #include "nsi_cpu_ctrl.h" |
| #include "NRF_HWLowL.h" |
| #include "NHW_misc.h" |
| |
| static bs_args_struct_t *args_struct; |
| /* Direct use of this global is deprecated, use bsim_args_get_global_device_nbr() instead */ |
| uint global_device_nbr; |
| |
| #define MAXPARAMS_TESTCASES 1024 |
| |
| static struct bsim_global_args_t { |
| BS_BASIC_DEVICE_OPTIONS_FIELDS |
| } global_args; |
| |
| static bool nosim; |
| |
| /* Extra "command line options" provided programmatically: */ |
| static int extra_argc; |
| static char **extra_argv; |
| |
| static void cmd_trace_lvl_found(char *argv, int offset) |
| { |
| bs_trace_set_level(global_args.verb); |
| } |
| |
| static void cmd_gdev_nbr_found(char *argv, int offset) |
| { |
| bs_trace_set_prefix_dev(global_args.global_device_nbr); |
| } |
| |
| static void print_no_sim_warning(void) |
| { |
| bs_trace_warning("Neither simulation id or the device number " |
| "have been set. I assume you want to run " |
| "without a BabbleSim phy (-nosim)\n"); |
| bs_trace_warning("If this is not what you wanted, check with " |
| "--help how to set them\n"); |
| bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 " |
| "and nosim\n"); |
| } |
| |
| static void print_mcus_info(char *argv, int offset) |
| { |
| (void) argv; |
| (void) offset; |
| bs_trace_raw(0, "CPU #, Name , Autostart\n"); |
| bs_trace_raw(0, "-------------------------------\n"); |
| for (int i = 0; i < NSI_N_CPUS; i++) { |
| bs_trace_raw(0, "CPU %2i, %12s, %i\n", |
| i, nhw_get_core_name(i), nsi_cpu_get_auto_start(i)); |
| } |
| } |
| |
| static void bsim_register_basic_args(void) |
| { |
| #define args (&global_args) |
| /* This define allows reusing the definitions provided by the utils library */ |
| static bs_args_struct_t args_struct_toadd[] = { |
| ARG_TABLE_S_ID, |
| ARG_TABLE_P_ID_2G4, |
| ARG_TABLE_DEV_NBR, |
| ARG_TABLE_GDEV_NBR, |
| ARG_TABLE_VERB, |
| ARG_TABLE_SEED, |
| ARG_TABLE_COLOR, |
| ARG_TABLE_NOCOLOR, |
| ARG_TABLE_FORCECOLOR, |
| { |
| .is_switch = true, |
| .option = "nosim", |
| .type = 'b', |
| .dest = (void *)&nosim, |
| .descript = "Do not connect to the Physical layer simulator" |
| }, |
| BS_DUMP_FILES_ARGS, |
| { |
| .manual = true, |
| .option = "argstest", |
| .name = "arg", |
| .type = 'l', |
| .descript = "The arguments that follow will be passed straight to the testcase " |
| "init function (Note: If more than 1 MCU is present, argtest corresponds " |
| "to argstests" NSI_STRINGIFY(NSI_PRIMARY_MCU_N) " )" |
| }, |
| { |
| .manual = true, |
| .option = "argstest<n>", |
| .name = "arg", |
| .type = 'l', |
| .descript = "The arguments that follow will be passed straight to cpu<n>'s " |
| "testcase init function), where 0 <= n < " NSI_STRINGIFY(NSI_N_CPUS) |
| " is the cpu number" |
| }, |
| { |
| .manual = true, |
| .option = "argsmain", |
| .name = "arg", |
| .type = 'l', |
| .descript = "The arguments that follow will be passed to main (default)" |
| }, |
| { |
| .is_switch = true, |
| .option = "cpu_print_info", |
| .call_when_found = print_mcus_info, |
| .type = 'b', |
| .descript = "Print information about each MCUs", |
| }, |
| ARG_TABLE_ENDMARKER |
| }; |
| #undef args |
| |
| bs_add_dynargs(&args_struct, args_struct_toadd); |
| } |
| |
| NSI_TASK(bsim_register_basic_args, PRE_BOOT_1, 0); |
| |
| static void bsim_cleanup_args(void) |
| { |
| bs_cleanup_dynargs(&args_struct); |
| } |
| |
| NSI_TASK(bsim_cleanup_args, ON_EXIT_POST, 0); |
| |
| void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd) |
| { |
| bs_add_dynargs(&args_struct, args_struct_toadd); |
| } |
| |
| static void nsif_cpun_save_test_arg(int n, char *c) |
| { |
| F_TRAMP_LIST(NATIVE_SIMULATOR_IF void nsif_cpu, _save_test_arg(char *argv)) |
| |
| void(*fptrs[])(char *) = { |
| F_TRAMP_TABLE(nsif_cpu, _save_test_arg) |
| }; |
| |
| fptrs[n](c); |
| } |
| |
| static void nsi_handle_one_cmdline_argument(char *argv) |
| { |
| static enum {Main = 0, Test = 1} parsing = Main; |
| static uint test_cpu_n; |
| |
| if (bs_is_option(argv, "argstest", 0)) { |
| parsing = Test; |
| test_cpu_n = NSI_PRIMARY_MCU_N; |
| return; |
| } else if (bs_is_multi_opt(argv, "argstest", &test_cpu_n, 0)) { |
| parsing = Test; |
| return; |
| } else if (bs_is_option(argv, "argsmain", 0)) { |
| parsing = Main; |
| return; |
| } |
| |
| if (parsing == Main) { |
| if (!bs_args_parse_one_arg(argv, args_struct)) { |
| bs_args_print_switches_help(args_struct); |
| bs_trace_error_line("Incorrect option %s\n", |
| argv); |
| } |
| } else if (parsing == Test) { |
| nsif_cpun_save_test_arg(test_cpu_n, argv); |
| } else { |
| bs_trace_error_line("Bad error\n"); |
| } |
| } |
| |
| /** |
| * Check the arguments provided in the command line: set args based on it or |
| * defaults, and check they are correct |
| */ |
| void nsi_handle_cmd_line(int argc, char *argv[]) |
| { |
| bs_args_set_defaults(args_struct); |
| global_args.verb = 2; |
| bs_trace_set_level(global_args.verb); |
| |
| for (int i = 0; i < extra_argc; i++) { |
| nsi_handle_one_cmdline_argument(extra_argv[i]); |
| } |
| for (int i = 1; i < argc; i++) { |
| nsi_handle_one_cmdline_argument(argv[i]); |
| } |
| } |
| |
| void nsi_register_extra_args(int argc, char *argv[]) |
| { |
| int new_size = extra_argc + argc; |
| |
| extra_argv = realloc(extra_argv, new_size*sizeof(char *)); |
| for (int i = 0; i < argc; i++) { |
| memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); |
| } |
| extra_argc += argc; |
| } |
| |
| static void clear_extra_args(void) |
| { |
| free(extra_argv); |
| } |
| |
| NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); |
| |
| static void postcheck_cmd_line(void) |
| { |
| static const char *bogus_sim_id = "bogus"; |
| static const char default_phy[] = "2G4"; |
| |
| /** |
| * If the user did not set the simulation id or device number |
| * we assume he wanted to run with nosim (but warn him) |
| */ |
| if ((!nosim) && (global_args.s_id == NULL) && (global_args.device_nbr == UINT_MAX)) { |
| print_no_sim_warning(); |
| nosim = true; |
| } |
| if (nosim) { |
| if (global_args.s_id == NULL) { |
| global_args.s_id = (char *)bogus_sim_id; |
| } |
| if (global_args.device_nbr == UINT_MAX) { |
| global_args.device_nbr = 0; |
| } |
| hwll_set_nosim(true); |
| } |
| |
| if (global_args.device_nbr == UINT_MAX) { |
| bs_args_print_switches_help(args_struct); |
| bs_trace_error_line("The command line option <device number> " |
| "needs to be set\n"); |
| } |
| if (global_args.global_device_nbr == UINT_MAX) { |
| global_args.global_device_nbr = global_args.device_nbr; |
| bs_trace_set_prefix_dev(global_args.global_device_nbr); |
| } |
| global_device_nbr = global_args.global_device_nbr; |
| if (!global_args.s_id) { |
| bs_args_print_switches_help(args_struct); |
| bs_trace_error_line("The command line option <simulation ID> " |
| "needs to be set\n"); |
| } |
| if (!global_args.p_id) { |
| global_args.p_id = (char *)default_phy; |
| } |
| |
| if (global_args.rseed == UINT_MAX) { |
| global_args.rseed = 0x1000 + global_args.device_nbr; |
| } |
| |
| bs_random_init(global_args.rseed); |
| } |
| |
| NSI_TASK(postcheck_cmd_line, PRE_BOOT_2, 0); |
| |
| /* |
| * Get the simulation id |
| */ |
| char *bsim_args_get_simid(void) |
| { |
| return global_args.s_id; |
| } |
| |
| /* |
| * Get this device number in the simulation, as it is |
| * known in the overall simulation. |
| * In general this is the device number you want |
| */ |
| unsigned int bsim_args_get_global_device_nbr(void) |
| { |
| return global_args.global_device_nbr; |
| } |
| |
| /* |
| * Get this device number in the 2G4 Phy simulation |
| */ |
| unsigned int bsim_args_get_2G4_device_nbr(void) |
| { |
| return global_args.device_nbr; |
| } |
| |
| /* |
| * Get this device number in the 2G4 Phy simulation |
| */ |
| char *bsim_args_get_2G4_phy_id(void) |
| { |
| return global_args.p_id; |
| } |
| |
| char *get_simid(void) |
| { |
| return bsim_args_get_simid(); |
| } |
| |
| unsigned int get_device_nbr(void) |
| { |
| return bsim_args_get_global_device_nbr(); |
| } |