blob: 3f875f5c97c922afa761287938b1265cbe05bbb4 [file] [log] [blame]
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +01001/*
Pau Espin Pedrole9ce77b2019-06-25 12:29:01 +02002 * Copyright (C) 2018-2019 sysmocom - s.f.m.c. GmbH
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +01003 * All Rights Reserved
4 *
Pau Espin Pedrole9ce77b2019-06-25 12:29:01 +02005 * SPDX-License-Identifier: AGPL-3.0+
6 *
7 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010012 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Pau Espin Pedrole9ce77b2019-06-25 12:29:01 +020017 * GNU Affero General Public License for more details.
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010018 *
Pau Espin Pedrole9ce77b2019-06-25 12:29:01 +020019 * You should have received a copy of the GNU Affero General Public License
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010020 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Pau Espin Pedrole9ce77b2019-06-25 12:29:01 +020021 * See the COPYING file in the main directory for details.
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010022 */
23
24#include <string.h>
25#include <stdint.h>
26#include <inttypes.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/utils.h>
32#include <osmocom/core/rate_ctr.h>
33
34#include <osmocom/vty/command.h>
Pau Espin Pedrolaebbfe02020-01-02 16:39:11 +010035#include <osmocom/vty/logging.h>
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010036#include <osmocom/vty/vty.h>
37#include <osmocom/vty/misc.h>
38
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +020039#include "trx_rate_ctr.h"
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010040#include "trx_vty.h"
41#include "../config.h"
42
43static struct trx_ctx* g_trx_ctx;
44
Pau Espin Pedrola7bf6cd2020-01-14 17:52:15 +010045const struct value_string clock_ref_names[] = {
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010046 { REF_INTERNAL, "internal" },
47 { REF_EXTERNAL, "external" },
Pau Espin Pedrolaae403f2018-08-27 16:50:19 +020048 { REF_GPS, "gpsdo" },
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010049 { 0, NULL }
50};
51
Alexander Chemeris9a87d902019-10-15 00:33:07 +030052const struct value_string filler_names[] = {
53 { FILLER_DUMMY, "Dummy bursts (C0 only)" },
54 { FILLER_ZERO, "Empty bursts" },
55 { FILLER_NORM_RAND, "GMSK Normal Bursts with random payload" },
56 { FILLER_EDGE_RAND, "8-PSK Normal Bursts with random payload" },
57 { FILLER_ACCESS_RAND, "Access Bursts with random payload" },
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010058 { 0, NULL }
59};
60
Alexander Chemeris9a87d902019-10-15 00:33:07 +030061static const struct value_string filler_types[] = {
62 { FILLER_DUMMY, "dummy" },
63 { FILLER_ZERO, "zero" },
64 { FILLER_NORM_RAND, "random-nb-gmsk" },
65 { FILLER_EDGE_RAND, "random-nb-8psk" },
66 { FILLER_ACCESS_RAND, "random-ab" },
67 { 0, NULL }
68};
69
70
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010071struct trx_ctx *trx_from_vty(struct vty *v)
72{
73 /* It can't hurt to force callers to continue to pass the vty instance
74 * to this function, in case we'd like to retrieve the global
75 * trx instance from the vty at some point in the future. But
76 * until then, just return the global pointer, which should have been
77 * initialized by trx_vty_init().
78 */
79 OSMO_ASSERT(g_trx_ctx);
80 return g_trx_ctx;
81}
82
83enum trx_vty_node {
84 TRX_NODE = _LAST_OSMOVTY_NODE + 1,
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010085 CHAN_NODE,
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010086};
87
88static struct cmd_node trx_node = {
89 TRX_NODE,
90 "%s(config-trx)# ",
91 1,
92};
93
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010094static struct cmd_node chan_node = {
95 CHAN_NODE,
96 "%s(config-trx-chan)# ",
97 1,
98};
99
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100100DEFUN(cfg_trx, cfg_trx_cmd,
101 "trx",
102 "Configure the TRX\n")
103{
104 struct trx_ctx *trx = trx_from_vty(vty);
105
106 if (!trx)
107 return CMD_WARNING;
108
109 vty->node = TRX_NODE;
110
111 return CMD_SUCCESS;
112}
113
114DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
115 "bind-ip A.B.C.D",
116 "Set the IP address for the local bind\n"
117 "IPv4 Address\n")
118{
119 struct trx_ctx *trx = trx_from_vty(vty);
120
121 osmo_talloc_replace_string(trx, &trx->cfg.bind_addr, argv[0]);
122
123 return CMD_SUCCESS;
124}
125
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100126DEFUN(cfg_remote_ip, cfg_remote_ip_cmd,
127 "remote-ip A.B.C.D",
128 "Set the IP address for the remote BTS\n"
129 "IPv4 Address\n")
130{
131 struct trx_ctx *trx = trx_from_vty(vty);
132
133 osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, argv[0]);
134
135 return CMD_SUCCESS;
136}
137
138DEFUN(cfg_base_port, cfg_base_port_cmd,
139 "base-port <1-65535>",
140 "Set the TRX Base Port\n"
141 "TRX Base Port\n")
142{
143 struct trx_ctx *trx = trx_from_vty(vty);
144
145 trx->cfg.base_port = atoi(argv[0]);
146
147 return CMD_SUCCESS;
148}
149
150DEFUN(cfg_dev_args, cfg_dev_args_cmd,
151 "dev-args DESC",
152 "Set the device-specific arguments to pass to the device\n"
153 "Device-specific arguments\n")
154{
155 struct trx_ctx *trx = trx_from_vty(vty);
156
157 osmo_talloc_replace_string(trx, &trx->cfg.dev_args, argv[0]);
158
159 return CMD_SUCCESS;
160}
161
162DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
163 "tx-sps (1|4)",
164 "Set the Tx Samples-per-Symbol\n"
165 "Tx Samples-per-Symbol\n")
166{
167 struct trx_ctx *trx = trx_from_vty(vty);
168
169 trx->cfg.tx_sps = atoi(argv[0]);
170
171 return CMD_SUCCESS;
172}
173
174DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
175 "rx-sps (1|4)",
176 "Set the Rx Samples-per-Symbol\n"
177 "Rx Samples-per-Symbol\n")
178{
179 struct trx_ctx *trx = trx_from_vty(vty);
180
181 trx->cfg.rx_sps = atoi(argv[0]);
182
183 return CMD_SUCCESS;
184}
185
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100186DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
187 "clock-ref (internal|external|gpsdo)",
188 "Set the Reference Clock\n"
Martin Hauke066fd042019-10-13 19:08:00 +0200189 "Enable internal reference (default)\n"
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100190 "Enable external 10 MHz reference\n"
191 "Enable GPSDO reference\n")
192{
193 struct trx_ctx *trx = trx_from_vty(vty);
194
195 trx->cfg.clock_ref = get_string_value(clock_ref_names, argv[0]);
196
197 return CMD_SUCCESS;
198}
199
200DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd,
201 "multi-arfcn (disable|enable)",
202 "Enable multi-ARFCN transceiver (default=disable)\n")
203{
204 struct trx_ctx *trx = trx_from_vty(vty);
205
206 if (strcmp("disable", argv[0]) == 0) {
207 trx->cfg.multi_arfcn = false;
Tom Tsoud2800452019-04-01 07:55:48 +0700208 return CMD_SUCCESS;
209 }
210
211 if (trx->cfg.num_chans > TRX_MCHAN_MAX) {
212 vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
213 TRX_MCHAN_MAX, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100214 return CMD_WARNING;
215 }
216
Tom Tsoud2800452019-04-01 07:55:48 +0700217 trx->cfg.multi_arfcn = true;
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100218 return CMD_SUCCESS;
219}
220
221DEFUN(cfg_offset, cfg_offset_cmd,
222 "offset FLOAT",
223 "Set the baseband frequency offset (default=0, auto)\n"
224 "Baseband Frequency Offset\n")
225{
226 struct trx_ctx *trx = trx_from_vty(vty);
227
228 trx->cfg.offset = atof(argv[0]);
229
230 return CMD_SUCCESS;
231}
232
233DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd,
234 "rssi-offset FLOAT",
235 "Set the RSSI to dBm offset in dB (default=0)\n"
236 "RSSI to dBm offset in dB\n")
237{
238 struct trx_ctx *trx = trx_from_vty(vty);
239
240 trx->cfg.rssi_offset = atof(argv[0]);
241
242 return CMD_SUCCESS;
243}
244
245DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
246 "swap-channels (disable|enable)",
247 "Swap channels (default=disable)\n")
248{
249 struct trx_ctx *trx = trx_from_vty(vty);
250
251 if (strcmp("disable", argv[0]) == 0) {
252 trx->cfg.swap_channels = false;
253 } else if (strcmp("enable", argv[0]) == 0) {
254 trx->cfg.swap_channels = true;
255 } else {
256 return CMD_WARNING;
257 }
258
259 return CMD_SUCCESS;
260}
261
262DEFUN(cfg_egprs, cfg_egprs_cmd,
263 "egprs (disable|enable)",
264 "Enable EDGE receiver (default=disable)\n")
265{
266 struct trx_ctx *trx = trx_from_vty(vty);
267
268 if (strcmp("disable", argv[0]) == 0) {
269 trx->cfg.egprs = false;
270 } else if (strcmp("enable", argv[0]) == 0) {
271 trx->cfg.egprs = true;
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100272 } else {
273 return CMD_WARNING;
274 }
275
276 return CMD_SUCCESS;
277}
278
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200279DEFUN(cfg_ext_rach, cfg_ext_rach_cmd,
280 "ext-rach (disable|enable)",
281 "Enable extended (11-bit) RACH (default=disable)\n")
282{
283 struct trx_ctx *trx = trx_from_vty(vty);
284
285 if (strcmp("disable", argv[0]) == 0)
286 trx->cfg.ext_rach = false;
287
288 if (strcmp("enable", argv[0]) == 0)
289 trx->cfg.ext_rach = true;
290
291 return CMD_SUCCESS;
292}
293
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100294DEFUN(cfg_rt_prio, cfg_rt_prio_cmd,
295 "rt-prio <1-32>",
296 "Set the SCHED_RR real-time priority\n"
297 "Real time priority\n")
298{
299 struct trx_ctx *trx = trx_from_vty(vty);
300
301 trx->cfg.sched_rr = atoi(argv[0]);
302
303 return CMD_SUCCESS;
304}
305
Eric Wildac0487e2019-06-17 13:02:44 +0200306DEFUN(cfg_stack_size, cfg_stack_size_cmd,
307 "stack-size <0-2147483647>",
308 "Set the stack size per thread in BYTE, 0 = OS default\n"
309 "Stack size per thread in BYTE\n")
310{
311 struct trx_ctx *trx = trx_from_vty(vty);
312
313 trx->cfg.stack_size = atoi(argv[0]);
314
315 return CMD_SUCCESS;
316}
317
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300318DEFUN(cfg_filler, cfg_filler_type_cmd,
319 "filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)",
320 "Filler burst settings\n"
321 "Filler burst type (default=zero)\n"
322 "Send an empty burst when there is nothing to send (default)\n"
323 "Send a dummy burst when there is nothing to send on C0 (TRX0) and empty burst on other channels."
324 " Use for OpenBTS compatibility only, don't use with OsmoBTS as it breaks encryption.\n"
325 "Send a GMSK modulated Normal Burst with random bits when there is nothing to send."
326 " Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
327 "Send an 8-PSK modulated Normal Burst with random bits when there is nothing to send."
328 " Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
329 "Send an Access Burst with random bits when there is nothing to send. Use for Rx/Tx alignment."
330 " Configure 'filler access-burst-delay' to introduce artificial delay.\n"
331)
332{
333 struct trx_ctx *trx = trx_from_vty(vty);
334 // trx->cfg.filler is unsigned, so we need an interim int var to detect errors
335 int type = get_string_value(filler_types, argv[0]);
336
337 if (type < 0) {
338 trx->cfg.filler = FILLER_ZERO;
339 return CMD_WARNING;
340 }
341 trx->cfg.filler = type;
342
343 return CMD_SUCCESS;
344}
345
346DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
347 "filler tsc <0-7>",
348 "Filler burst settings\n"
349 "Set the TSC for GMSK/8-PSK Normal Burst random fillers. Used only with 'random-nb-gmsk' and"
350 " 'random-nb-8psk' filler types. (default=0)\n"
351 "TSC\n")
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100352{
353 struct trx_ctx *trx = trx_from_vty(vty);
354
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300355 trx->cfg.rtsc = atoi(argv[0]);
356
357 return CMD_SUCCESS;
358}
359
360DEFUN(cfg_test_rach_delay, cfg_filler_rach_delay_cmd,
361 "filler access-burst-delay <0-68>",
362 "Filler burst settings\n"
363 "Set the delay for Access Burst random fillers. Used only with 'random-ab' filler type. (default=0)\n"
364 "RACH delay in symbols\n")
365{
366 struct trx_ctx *trx = trx_from_vty(vty);
367
368 trx->cfg.rach_delay = atoi(argv[0]);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100369
370 return CMD_SUCCESS;
371}
372
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200373static int vty_ctr_name_2_id(const char* str) {
374 size_t i;
375 for (i = 0; trx_chan_ctr_names[i].str; i++) {
376 if (strstr(trx_chan_ctr_names[i].str, str)) {
377 return i;
378 }
379 }
380 return -1;
381}
382
383static int vty_intv_name_2_id(const char* str) {
384 size_t i;
385 for (i = 0; rate_ctr_intv[i].str; i++) {
386 if (strcmp(rate_ctr_intv[i].str, str) == 0) {
387 return i;
388 }
389 }
390 return -1;
391}
392
Pau Espin Pedrol68a78092019-07-29 20:11:25 +0200393#define THRESHOLD_ARGS "(rx_overruns|tx_underruns|rx_drop_events|rx_drop_samples|tx_drop_events|tx_drop_samples)"
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200394#define THRESHOLD_STR_VAL(s) "Set threshold value for rate_ctr device:" OSMO_STRINGIFY_VAL(s) "\n"
395#define THRESHOLD_STRS \
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200396 THRESHOLD_STR_VAL(rx_overruns) \
397 THRESHOLD_STR_VAL(tx_underruns) \
398 THRESHOLD_STR_VAL(rx_drop_events) \
Pau Espin Pedrol68a78092019-07-29 20:11:25 +0200399 THRESHOLD_STR_VAL(rx_drop_samples) \
400 THRESHOLD_STR_VAL(tx_drop_events) \
401 THRESHOLD_STR_VAL(tx_drop_samples)
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200402#define INTV_ARGS "(per-second|per-minute|per-hour|per-day)"
403#define INTV_STR_VAL(s) "Threshold value sampled " OSMO_STRINGIFY_VAL(s) "\n"
404#define INTV_STRS \
405 INTV_STR_VAL(per-second) \
406 INTV_STR_VAL(per-minute) \
407 INTV_STR_VAL(per-hour) \
408 INTV_STR_VAL(per-day)
409
410DEFUN(cfg_ctr_error_threshold, cfg_ctr_error_threshold_cmd,
411 "ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
412 "Threshold rate for error counter\n"
413 THRESHOLD_STRS
414 "Value to set for threshold\n"
415 INTV_STRS)
416{
417 int rc;
418 struct ctr_threshold ctr;
419
420 struct trx_ctx *trx = trx_from_vty(vty);
421 rc = vty_ctr_name_2_id(argv[0]);
422 if (rc < 0) {
423 vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
424 argv[0], VTY_NEWLINE);
425 return CMD_WARNING;
426 }
427 ctr.ctr_id = (enum TrxCtr)rc;
428 ctr.val = atoi(argv[1]);
429 rc = vty_intv_name_2_id(argv[2]);
430 if (rc < 0) {
431 vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
432 argv[0], ctr.val, argv[2], VTY_NEWLINE);
433 return CMD_WARNING;
434 }
435 ctr.intv = (enum rate_ctr_intv) rc;
436 trx_rate_ctr_threshold_add(&ctr);
437
438 return CMD_SUCCESS;
439}
440
441DEFUN(cfg_no_ctr_error_threshold, cfg_no_ctr_error_threshold_cmd,
442 "no ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
443 NO_STR "Threshold rate for error counter\n"
444 THRESHOLD_STRS
445 "Value to set for threshold\n"
446 INTV_STRS)
447{
448 int rc;
449 struct ctr_threshold ctr;
450
451 struct trx_ctx *trx = trx_from_vty(vty);
452 rc = vty_ctr_name_2_id(argv[0]);
453 if (rc < 0) {
454 vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
455 argv[0], VTY_NEWLINE);
456 return CMD_WARNING;
457 }
458 ctr.ctr_id = (enum TrxCtr)rc;
459 ctr.val = atoi(argv[1]);
460 rc = vty_intv_name_2_id(argv[2]);
461 if (rc < 0) {
462 vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
463 argv[0], ctr.val, argv[2], VTY_NEWLINE);
464 return CMD_WARNING;
465 }
466 ctr.intv = (enum rate_ctr_intv) rc;
467 if (trx_rate_ctr_threshold_del(&ctr) < 0) {
468 vty_out(vty, "no ctr-error-threshold: Entry to delete not found%s", VTY_NEWLINE);
469 return CMD_WARNING;
470 }
471
472 return CMD_SUCCESS;
473}
474
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100475DEFUN(cfg_chan, cfg_chan_cmd,
476 "chan <0-100>",
477 "Select a channel to configure\n"
478 "Channel index\n")
479{
480 struct trx_ctx *trx = trx_from_vty(vty);
481 int idx = atoi(argv[0]);
482
483 if (idx >= TRX_CHAN_MAX) {
484 vty_out(vty, "Chan list full.%s", VTY_NEWLINE);
485 return CMD_WARNING;
Tom Tsoud2800452019-04-01 07:55:48 +0700486 } else if (trx->cfg.multi_arfcn && trx->cfg.num_chans >= TRX_MCHAN_MAX) {
487 vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
488 TRX_MCHAN_MAX, VTY_NEWLINE);
489 return CMD_WARNING;
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100490 }
Tom Tsoud2800452019-04-01 07:55:48 +0700491
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100492 if (trx->cfg.num_chans < idx) { /* Unexisting or creating non-consecutive */
493 vty_out(vty, "Non-existent or non-consecutive chan %d.%s",
494 idx, VTY_NEWLINE);
495 return CMD_WARNING;
496 } else if (trx->cfg.num_chans == idx) { /* creating it */
497 trx->cfg.num_chans++;
498 trx->cfg.chans[idx].trx = trx;
499 trx->cfg.chans[idx].idx = idx;
500 }
501
502 vty->node = CHAN_NODE;
503 vty->index = &trx->cfg.chans[idx];
504
505 return CMD_SUCCESS;
506}
507
508DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd,
509 "rx-path NAME",
510 "Set the Rx Path\n"
511 "Rx Path name\n")
512{
513 struct trx_chan *chan = vty->index;
514
515 osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]);
516
517 return CMD_SUCCESS;
518}
519
520DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd,
521 "tx-path NAME",
522 "Set the Tx Path\n"
523 "Tx Path name\n")
524{
525 struct trx_chan *chan = vty->index;
526
527 osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]);
528
529 return CMD_SUCCESS;
530}
531
532static int dummy_config_write(struct vty *v)
533{
534 return CMD_SUCCESS;
535}
536
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100537static int config_write_trx(struct vty *vty)
538{
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100539 struct trx_chan *chan;
540 int i;
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100541 struct trx_ctx *trx = trx_from_vty(vty);
542
543 vty_out(vty, "trx%s", VTY_NEWLINE);
544 if (trx->cfg.bind_addr)
545 vty_out(vty, " bind-ip %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100546 if (trx->cfg.remote_addr)
547 vty_out(vty, " remote-ip %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
548 if (trx->cfg.base_port != DEFAULT_TRX_PORT)
549 vty_out(vty, " base-port %u%s", trx->cfg.base_port, VTY_NEWLINE);
550 if (trx->cfg.dev_args)
551 vty_out(vty, " dev-args %s%s", trx->cfg.dev_args, VTY_NEWLINE);
552 if (trx->cfg.tx_sps != DEFAULT_TX_SPS)
553 vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
554 if (trx->cfg.rx_sps != DEFAULT_RX_SPS)
555 vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100556 if (trx->cfg.clock_ref != REF_INTERNAL)
557 vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
558 vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE);
559 if (trx->cfg.offset != 0)
560 vty_out(vty, " offset %f%s", trx->cfg.offset, VTY_NEWLINE);
561 if (trx->cfg.rssi_offset != 0)
562 vty_out(vty, " rssi-offset %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
563 vty_out(vty, " swap-channels %s%s", trx->cfg.swap_channels ? "enable" : "disable", VTY_NEWLINE);
564 vty_out(vty, " egprs %s%s", trx->cfg.egprs ? "enable" : "disable", VTY_NEWLINE);
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200565 vty_out(vty, " ext-rach %s%s", trx->cfg.ext_rach ? "enable" : "disable", VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100566 if (trx->cfg.sched_rr != 0)
567 vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE);
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300568 if (trx->cfg.filler != FILLER_ZERO)
569 vty_out(vty, " filler type %s%s", get_value_string(filler_types, trx->cfg.filler), VTY_NEWLINE);
570 if (trx->cfg.rtsc > 0)
571 vty_out(vty, " filler tsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
572 if (trx->cfg.rach_delay > 0)
573 vty_out(vty, " filler access-burst-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
Eric Wildac0487e2019-06-17 13:02:44 +0200574 if (trx->cfg.stack_size != 0)
575 vty_out(vty, " stack-size %u%s", trx->cfg.stack_size, VTY_NEWLINE);
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200576 trx_rate_ctr_threshold_write_config(vty, " ");
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100577
578 for (i = 0; i < trx->cfg.num_chans; i++) {
579 chan = &trx->cfg.chans[i];
580 vty_out(vty, " chan %u%s", chan->idx, VTY_NEWLINE);
581 if (chan->rx_path)
Harald Welte03b3c302018-07-31 15:48:18 +0200582 vty_out(vty, " rx-path %s%s", chan->rx_path, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100583 if (chan->tx_path)
Harald Welte03b3c302018-07-31 15:48:18 +0200584 vty_out(vty, " tx-path %s%s", chan->tx_path, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100585 }
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100586
587 return CMD_SUCCESS;
588}
589
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100590static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx)
591{
592 struct trx_chan *chan;
593 int i;
594 vty_out(vty, "TRX Config:%s", VTY_NEWLINE);
595 vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
596 vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
597 vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE);
598 vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
599 vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
600 vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300601 vty_out(vty, " Filler Burst Type: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
602 vty_out(vty, " Filler Burst TSC: %u%s", trx->cfg.rtsc, VTY_NEWLINE);
603 vty_out(vty, " Filler Burst RACH Delay: %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100604 vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
605 vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE);
606 vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE);
607 vty_out(vty, " RSSI to dBm offset: %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
608 vty_out(vty, " Swap channels: %s%s", trx->cfg.swap_channels ? "Enabled" : "Disabled", VTY_NEWLINE);
609 vty_out(vty, " EDGE support: %s%s", trx->cfg.egprs ? "Enabled" : "Disabled", VTY_NEWLINE);
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200610 vty_out(vty, " Extended RACH support: %s%s", trx->cfg.ext_rach ? "Enabled" : "Disabled", VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100611 vty_out(vty, " Real Time Priority: %u (%s)%s", trx->cfg.sched_rr,
612 trx->cfg.sched_rr ? "Enabled" : "Disabled", VTY_NEWLINE);
Eric Wildac0487e2019-06-17 13:02:44 +0200613 vty_out(vty, " Stack size per Thread in BYTE (0 = OS default): %u%s", trx->cfg.stack_size, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100614 vty_out(vty, " Channels: %u%s", trx->cfg.num_chans, VTY_NEWLINE);
615 for (i = 0; i < trx->cfg.num_chans; i++) {
616 chan = &trx->cfg.chans[i];
617 vty_out(vty, " Channel %u:%s", chan->idx, VTY_NEWLINE);
618 if (chan->rx_path)
619 vty_out(vty, " Rx Path: %s%s", chan->rx_path, VTY_NEWLINE);
620 if (chan->tx_path)
621 vty_out(vty, " Tx Path: %s%s", chan->tx_path, VTY_NEWLINE);
622 }
623}
624
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100625DEFUN(show_trx, show_trx_cmd,
626 "show trx",
627 SHOW_STR "Display information on the TRX\n")
628{
629 struct trx_ctx *trx = trx_from_vty(vty);
630
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100631 trx_dump_vty(vty, trx);
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100632
633 return CMD_SUCCESS;
634}
635
636static int trx_vty_is_config_node(struct vty *vty, int node)
637{
638 switch (node) {
639 case TRX_NODE:
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100640 case CHAN_NODE:
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100641 return 1;
642 default:
643 return 0;
644 }
645}
646
647static int trx_vty_go_parent(struct vty *vty)
648{
649 switch (vty->node) {
650 case TRX_NODE:
651 vty->node = CONFIG_NODE;
652 vty->index = NULL;
653 vty->index_sub = NULL;
654 break;
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100655 case CHAN_NODE:
656 vty->node = TRX_NODE;
657 vty->index = NULL;
658 vty->index_sub = NULL;
659 break;
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100660 default:
Vadim Yanitskiy01eea0a2018-05-09 15:19:48 +0700661 vty->node = CONFIG_NODE;
662 vty->index = NULL;
663 vty->index_sub = NULL;
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100664 }
665
666 return vty->node;
667}
668
669static const char trx_copyright[] =
670 "Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
671 "Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300672 "Copyright (C) 2013-2019 Fairwaves, Inc.\r\n"
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100673 "Copyright (C) 2015 Ettus Research LLC\r\n"
674 "Copyright (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
675 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
676 "This is free software: you are free to change and redistribute it.\r\n"
677 "There is NO WARRANTY, to the extent permitted by law.\r\n";
678
679struct vty_app_info g_vty_info = {
680 .name = "OsmoTRX",
681 .version = PACKAGE_VERSION,
682 .copyright = trx_copyright,
683 .go_parent_cb = trx_vty_go_parent,
684 .is_config_node = trx_vty_is_config_node,
685};
686
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100687struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx)
688{
689 struct trx_ctx * trx = talloc_zero(talloc_ctx, struct trx_ctx);
690
691 trx->cfg.bind_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
692 trx->cfg.remote_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
693 trx->cfg.base_port = DEFAULT_TRX_PORT;
694 trx->cfg.tx_sps = DEFAULT_TX_SPS;
695 trx->cfg.rx_sps = DEFAULT_RX_SPS;
696 trx->cfg.filler = FILLER_ZERO;
697
698 return trx;
699}
700
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100701int trx_vty_init(struct trx_ctx* trx)
702{
703 g_trx_ctx = trx;
704 install_element_ve(&show_trx_cmd);
705
706 install_element(CONFIG_NODE, &cfg_trx_cmd);
707
708 install_node(&trx_node, config_write_trx);
709 install_element(TRX_NODE, &cfg_bind_ip_cmd);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100710 install_element(TRX_NODE, &cfg_remote_ip_cmd);
711 install_element(TRX_NODE, &cfg_base_port_cmd);
712 install_element(TRX_NODE, &cfg_dev_args_cmd);
713 install_element(TRX_NODE, &cfg_tx_sps_cmd);
714 install_element(TRX_NODE, &cfg_rx_sps_cmd);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100715 install_element(TRX_NODE, &cfg_clock_ref_cmd);
716 install_element(TRX_NODE, &cfg_multi_arfcn_cmd);
717 install_element(TRX_NODE, &cfg_offset_cmd);
718 install_element(TRX_NODE, &cfg_rssi_offset_cmd);
719 install_element(TRX_NODE, &cfg_swap_channels_cmd);
720 install_element(TRX_NODE, &cfg_egprs_cmd);
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200721 install_element(TRX_NODE, &cfg_ext_rach_cmd);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100722 install_element(TRX_NODE, &cfg_rt_prio_cmd);
Alexander Chemeris9a87d902019-10-15 00:33:07 +0300723 install_element(TRX_NODE, &cfg_filler_type_cmd);
724 install_element(TRX_NODE, &cfg_filler_tsc_cmd);
725 install_element(TRX_NODE, &cfg_filler_rach_delay_cmd);
Pau Espin Pedrol6a305fe2019-05-24 19:58:20 +0200726 install_element(TRX_NODE, &cfg_ctr_error_threshold_cmd);
727 install_element(TRX_NODE, &cfg_no_ctr_error_threshold_cmd);
Eric Wildac0487e2019-06-17 13:02:44 +0200728 install_element(TRX_NODE, &cfg_stack_size_cmd);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100729
730 install_element(TRX_NODE, &cfg_chan_cmd);
731 install_node(&chan_node, dummy_config_write);
732 install_element(CHAN_NODE, &cfg_chan_rx_path_cmd);
733 install_element(CHAN_NODE, &cfg_chan_tx_path_cmd);
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100734
Pau Espin Pedrolaebbfe02020-01-02 16:39:11 +0100735 logging_vty_add_deprecated_subsys(g_trx_ctx, "lms");
736
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100737 return 0;
738}