blob: 2e84ca812fe75fad652208c7e104fa3573cf349d [file] [log] [blame]
/*
* 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();
}