/* * 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 #include #include #include #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", .name = "arg", .type = 'l', .descript = "The arguments that follow will be passed straight to cpu'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 " "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 " "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(); }