From a3ab8c263de793586e615e23185a44402723685c Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Wed, 21 Feb 2018 15:41:03 +0100 Subject: vty: Implement VTY cfg parsing for current parameters At this stage, osmo-trx still uses the cmdline parameters top run the device, but it is already able to parse all the same parameters from a cfg file through the VTY and filling a trx_ctx structure which will be later used to drive the device. Device config can be printed in the VTY with "show trx". Change-Id: Ie084c1b30b63f91c6e7640832ec1797d9e813832 --- CommonLibs/trx_vty.c | 414 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 413 insertions(+), 1 deletion(-) (limited to 'CommonLibs/trx_vty.c') diff --git a/CommonLibs/trx_vty.c b/CommonLibs/trx_vty.c index b16cd24..843d19f 100644 --- a/CommonLibs/trx_vty.c +++ b/CommonLibs/trx_vty.c @@ -36,6 +36,22 @@ static struct trx_ctx* g_trx_ctx; +static const struct value_string clock_ref_names[] = { + { REF_INTERNAL, "internal" }, + { REF_EXTERNAL, "external" }, + { REF_GPS, "gspdo" }, + { 0, NULL } +}; + +static const struct value_string filler_names[] = { + { FILLER_DUMMY, "Dummy bursts" }, + { FILLER_ZERO, "Disabled" }, + { FILLER_NORM_RAND, "Normal bursts with random payload" }, + { FILLER_EDGE_RAND, "EDGE bursts with random payload" }, + { FILLER_ACCESS_RAND, "Access bursts with random payload" }, + { 0, NULL } +}; + struct trx_ctx *trx_from_vty(struct vty *v) { /* It can't hurt to force callers to continue to pass the vty instance @@ -50,6 +66,7 @@ struct trx_ctx *trx_from_vty(struct vty *v) enum trx_vty_node { TRX_NODE = _LAST_OSMOVTY_NODE + 1, + CHAN_NODE, }; static struct cmd_node trx_node = { @@ -58,6 +75,12 @@ static struct cmd_node trx_node = { 1, }; +static struct cmd_node chan_node = { + CHAN_NODE, + "%s(config-trx-chan)# ", + 1, +}; + DEFUN(cfg_trx, cfg_trx_cmd, "trx", "Configure the TRX\n") @@ -84,24 +107,373 @@ DEFUN(cfg_bind_ip, cfg_bind_ip_cmd, return CMD_SUCCESS; } +DEFUN(cfg_remote_ip, cfg_remote_ip_cmd, + "remote-ip A.B.C.D", + "Set the IP address for the remote BTS\n" + "IPv4 Address\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_base_port, cfg_base_port_cmd, + "base-port <1-65535>", + "Set the TRX Base Port\n" + "TRX Base Port\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.base_port = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_dev_args, cfg_dev_args_cmd, + "dev-args DESC", + "Set the device-specific arguments to pass to the device\n" + "Device-specific arguments\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + osmo_talloc_replace_string(trx, &trx->cfg.dev_args, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_tx_sps, cfg_tx_sps_cmd, + "tx-sps (1|4)", + "Set the Tx Samples-per-Symbol\n" + "Tx Samples-per-Symbol\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.tx_sps = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_rx_sps, cfg_rx_sps_cmd, + "rx-sps (1|4)", + "Set the Rx Samples-per-Symbol\n" + "Rx Samples-per-Symbol\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.rx_sps = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_test_rtsc, cfg_test_rtsc_cmd, + "test rtsc <0-7>", + "Set the Random Normal Burst test mode with TSC\n" + "TSC\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + if (trx->cfg.rach_delay_set) { + vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + trx->cfg.rtsc_set = true; + trx->cfg.rtsc = atoi(argv[0]); + if (!trx->cfg.egprs) /* Don't override egprs which sets different filler */ + trx->cfg.filler = FILLER_NORM_RAND; + + return CMD_SUCCESS; +} + +DEFUN(cfg_test_rach_delay, cfg_test_rach_delay_cmd, + "test rach-delay <0-68>", + "Set the Random Access Burst test mode with delay\n" + "RACH delay\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + if (trx->cfg.rtsc_set) { + vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (trx->cfg.egprs) { + vty_out(vty, "rach-delay and egprs options are mutual-exclusive%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + trx->cfg.rach_delay_set = true; + trx->cfg.rach_delay = atoi(argv[0]); + trx->cfg.filler = FILLER_ACCESS_RAND; + + return CMD_SUCCESS; +} + +DEFUN(cfg_clock_ref, cfg_clock_ref_cmd, + "clock-ref (internal|external|gpsdo)", + "Set the Reference Clock\n" + "Enable internal referece (default)\n" + "Enable external 10 MHz reference\n" + "Enable GPSDO reference\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.clock_ref = get_string_value(clock_ref_names, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd, + "multi-arfcn (disable|enable)", + "Enable multi-ARFCN transceiver (default=disable)\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + if (strcmp("disable", argv[0]) == 0) { + trx->cfg.multi_arfcn = false; + } else if (strcmp("enable", argv[0]) == 0) { + trx->cfg.multi_arfcn = true; + } else { + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_offset, cfg_offset_cmd, + "offset FLOAT", + "Set the baseband frequency offset (default=0, auto)\n" + "Baseband Frequency Offset\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.offset = atof(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd, + "rssi-offset FLOAT", + "Set the RSSI to dBm offset in dB (default=0)\n" + "RSSI to dBm offset in dB\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.rssi_offset = atof(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_swap_channels, cfg_swap_channels_cmd, + "swap-channels (disable|enable)", + "Swap channels (default=disable)\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + if (strcmp("disable", argv[0]) == 0) { + trx->cfg.swap_channels = false; + } else if (strcmp("enable", argv[0]) == 0) { + trx->cfg.swap_channels = true; + } else { + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_egprs, cfg_egprs_cmd, + "egprs (disable|enable)", + "Enable EDGE receiver (default=disable)\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + if (strcmp("disable", argv[0]) == 0) { + trx->cfg.egprs = false; + } else if (strcmp("enable", argv[0]) == 0) { + trx->cfg.egprs = true; + trx->cfg.filler = FILLER_EDGE_RAND; + } else { + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_rt_prio, cfg_rt_prio_cmd, + "rt-prio <1-32>", + "Set the SCHED_RR real-time priority\n" + "Real time priority\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.sched_rr = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_filler, cfg_filler_cmd, + "filler dummy", + "Enable C0 filler table\n" + "Dummy method\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + + trx->cfg.filler = FILLER_DUMMY; + + return CMD_SUCCESS; +} + +DEFUN(cfg_chan, cfg_chan_cmd, + "chan <0-100>", + "Select a channel to configure\n" + "Channel index\n") +{ + struct trx_ctx *trx = trx_from_vty(vty); + int idx = atoi(argv[0]); + + if (idx >= TRX_CHAN_MAX) { + vty_out(vty, "Chan list full.%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (trx->cfg.num_chans < idx) { /* Unexisting or creating non-consecutive */ + vty_out(vty, "Non-existent or non-consecutive chan %d.%s", + idx, VTY_NEWLINE); + return CMD_WARNING; + } else if (trx->cfg.num_chans == idx) { /* creating it */ + trx->cfg.num_chans++; + trx->cfg.chans[idx].trx = trx; + trx->cfg.chans[idx].idx = idx; + } + + vty->node = CHAN_NODE; + vty->index = &trx->cfg.chans[idx]; + + return CMD_SUCCESS; +} + +DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd, + "rx-path NAME", + "Set the Rx Path\n" + "Rx Path name\n") +{ + struct trx_chan *chan = vty->index; + + osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd, + "tx-path NAME", + "Set the Tx Path\n" + "Tx Path name\n") +{ + struct trx_chan *chan = vty->index; + + osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]); + + return CMD_SUCCESS; +} + +static int dummy_config_write(struct vty *v) +{ + return CMD_SUCCESS; +} + static int config_write_trx(struct vty *vty) { + struct trx_chan *chan; + int i; struct trx_ctx *trx = trx_from_vty(vty); vty_out(vty, "trx%s", VTY_NEWLINE); if (trx->cfg.bind_addr) vty_out(vty, " bind-ip %s%s", trx->cfg.bind_addr, VTY_NEWLINE); + if (trx->cfg.remote_addr) + vty_out(vty, " remote-ip %s%s", trx->cfg.remote_addr, VTY_NEWLINE); + if (trx->cfg.base_port != DEFAULT_TRX_PORT) + vty_out(vty, " base-port %u%s", trx->cfg.base_port, VTY_NEWLINE); + if (trx->cfg.dev_args) + vty_out(vty, " dev-args %s%s", trx->cfg.dev_args, VTY_NEWLINE); + if (trx->cfg.tx_sps != DEFAULT_TX_SPS) + vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE); + if (trx->cfg.rx_sps != DEFAULT_RX_SPS) + vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE); + if (trx->cfg.rtsc_set) + vty_out(vty, " test rtsc %u%s", trx->cfg.rtsc, VTY_NEWLINE); + if (trx->cfg.rach_delay_set) + vty_out(vty, " test rach-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE); + if (trx->cfg.clock_ref != REF_INTERNAL) + vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE); + vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE); + if (trx->cfg.offset != 0) + vty_out(vty, " offset %f%s", trx->cfg.offset, VTY_NEWLINE); + if (trx->cfg.rssi_offset != 0) + vty_out(vty, " rssi-offset %f%s", trx->cfg.rssi_offset, VTY_NEWLINE); + vty_out(vty, " swap-channels %s%s", trx->cfg.swap_channels ? "enable" : "disable", VTY_NEWLINE); + vty_out(vty, " egprs %s%s", trx->cfg.egprs ? "enable" : "disable", VTY_NEWLINE); + if (trx->cfg.sched_rr != 0) + vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE); + + for (i = 0; i < trx->cfg.num_chans; i++) { + chan = &trx->cfg.chans[i]; + vty_out(vty, " chan %u%s", chan->idx, VTY_NEWLINE); + if (chan->rx_path) + vty_out(vty, " rx-path %s%s", chan->rx_path, VTY_NEWLINE); + if (chan->tx_path) + vty_out(vty, " tx-path %s%s", chan->tx_path, VTY_NEWLINE); + } return CMD_SUCCESS; } +static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx) +{ + struct trx_chan *chan; + int i; + vty_out(vty, "TRX Config:%s", VTY_NEWLINE); + vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE); + vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE); + vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE); + vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE); + vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE); + vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE); + vty_out(vty, " Test Mode: TSC: %u (%s)%s", trx->cfg.rtsc, + trx->cfg.rtsc_set ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " Test Mode: RACH Delay: %u (%s)%s", trx->cfg.rach_delay, + trx->cfg.rach_delay_set ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " C0 Filler Table: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE); + vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE); + vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE); + vty_out(vty, " RSSI to dBm offset: %f%s", trx->cfg.rssi_offset, VTY_NEWLINE); + vty_out(vty, " Swap channels: %s%s", trx->cfg.swap_channels ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " EDGE support: %s%s", trx->cfg.egprs ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " Real Time Priority: %u (%s)%s", trx->cfg.sched_rr, + trx->cfg.sched_rr ? "Enabled" : "Disabled", VTY_NEWLINE); + vty_out(vty, " Channels: %u%s", trx->cfg.num_chans, VTY_NEWLINE); + for (i = 0; i < trx->cfg.num_chans; i++) { + chan = &trx->cfg.chans[i]; + vty_out(vty, " Channel %u:%s", chan->idx, VTY_NEWLINE); + if (chan->rx_path) + vty_out(vty, " Rx Path: %s%s", chan->rx_path, VTY_NEWLINE); + if (chan->tx_path) + vty_out(vty, " Tx Path: %s%s", chan->tx_path, VTY_NEWLINE); + } +} + DEFUN(show_trx, show_trx_cmd, "show trx", SHOW_STR "Display information on the TRX\n") { struct trx_ctx *trx = trx_from_vty(vty); - vty_out(vty, "TRX: Bound to %s%s", trx->cfg.bind_addr, VTY_NEWLINE); + trx_dump_vty(vty, trx); return CMD_SUCCESS; } @@ -110,6 +482,7 @@ static int trx_vty_is_config_node(struct vty *vty, int node) { switch (node) { case TRX_NODE: + case CHAN_NODE: return 1; default: return 0; @@ -124,6 +497,11 @@ static int trx_vty_go_parent(struct vty *vty) vty->index = NULL; vty->index_sub = NULL; break; + case CHAN_NODE: + vty->node = TRX_NODE; + vty->index = NULL; + vty->index_sub = NULL; + break; default: OSMO_ASSERT(0); } @@ -148,6 +526,20 @@ struct vty_app_info g_vty_info = { .is_config_node = trx_vty_is_config_node, }; +struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx) +{ + struct trx_ctx * trx = talloc_zero(talloc_ctx, struct trx_ctx); + + trx->cfg.bind_addr = talloc_strdup(trx, DEFAULT_TRX_IP); + trx->cfg.remote_addr = talloc_strdup(trx, DEFAULT_TRX_IP); + trx->cfg.base_port = DEFAULT_TRX_PORT; + trx->cfg.tx_sps = DEFAULT_TX_SPS; + trx->cfg.rx_sps = DEFAULT_RX_SPS; + trx->cfg.filler = FILLER_ZERO; + + return trx; +} + int trx_vty_init(struct trx_ctx* trx) { g_trx_ctx = trx; @@ -157,6 +549,26 @@ int trx_vty_init(struct trx_ctx* trx) install_node(&trx_node, config_write_trx); install_element(TRX_NODE, &cfg_bind_ip_cmd); + install_element(TRX_NODE, &cfg_remote_ip_cmd); + install_element(TRX_NODE, &cfg_base_port_cmd); + install_element(TRX_NODE, &cfg_dev_args_cmd); + install_element(TRX_NODE, &cfg_tx_sps_cmd); + install_element(TRX_NODE, &cfg_rx_sps_cmd); + install_element(TRX_NODE, &cfg_test_rtsc_cmd); + install_element(TRX_NODE, &cfg_test_rach_delay_cmd); + install_element(TRX_NODE, &cfg_clock_ref_cmd); + install_element(TRX_NODE, &cfg_multi_arfcn_cmd); + install_element(TRX_NODE, &cfg_offset_cmd); + install_element(TRX_NODE, &cfg_rssi_offset_cmd); + install_element(TRX_NODE, &cfg_swap_channels_cmd); + install_element(TRX_NODE, &cfg_egprs_cmd); + install_element(TRX_NODE, &cfg_rt_prio_cmd); + install_element(TRX_NODE, &cfg_filler_cmd); + + install_element(TRX_NODE, &cfg_chan_cmd); + install_node(&chan_node, dummy_config_write); + install_element(CHAN_NODE, &cfg_chan_rx_path_cmd); + install_element(CHAN_NODE, &cfg_chan_tx_path_cmd); return 0; } -- cgit v1.2.3