blob: 843d19fcaf25f42edb27702afbc1d21d0c10e859 [file] [log] [blame]
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +01001/*
2 * Copyright (C) 2012-2017 sysmocom - s.f.m.c. GmbH
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20#include <string.h>
21#include <stdint.h>
22#include <inttypes.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25
26#include <osmocom/core/talloc.h>
27#include <osmocom/core/utils.h>
28#include <osmocom/core/rate_ctr.h>
29
30#include <osmocom/vty/command.h>
31#include <osmocom/vty/vty.h>
32#include <osmocom/vty/misc.h>
33
34#include "trx_vty.h"
35#include "../config.h"
36
37static struct trx_ctx* g_trx_ctx;
38
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010039static const struct value_string clock_ref_names[] = {
40 { REF_INTERNAL, "internal" },
41 { REF_EXTERNAL, "external" },
42 { REF_GPS, "gspdo" },
43 { 0, NULL }
44};
45
46static const struct value_string filler_names[] = {
47 { FILLER_DUMMY, "Dummy bursts" },
48 { FILLER_ZERO, "Disabled" },
49 { FILLER_NORM_RAND, "Normal bursts with random payload" },
50 { FILLER_EDGE_RAND, "EDGE bursts with random payload" },
51 { FILLER_ACCESS_RAND, "Access bursts with random payload" },
52 { 0, NULL }
53};
54
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010055struct trx_ctx *trx_from_vty(struct vty *v)
56{
57 /* It can't hurt to force callers to continue to pass the vty instance
58 * to this function, in case we'd like to retrieve the global
59 * trx instance from the vty at some point in the future. But
60 * until then, just return the global pointer, which should have been
61 * initialized by trx_vty_init().
62 */
63 OSMO_ASSERT(g_trx_ctx);
64 return g_trx_ctx;
65}
66
67enum trx_vty_node {
68 TRX_NODE = _LAST_OSMOVTY_NODE + 1,
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010069 CHAN_NODE,
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010070};
71
72static struct cmd_node trx_node = {
73 TRX_NODE,
74 "%s(config-trx)# ",
75 1,
76};
77
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +010078static struct cmd_node chan_node = {
79 CHAN_NODE,
80 "%s(config-trx-chan)# ",
81 1,
82};
83
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +010084DEFUN(cfg_trx, cfg_trx_cmd,
85 "trx",
86 "Configure the TRX\n")
87{
88 struct trx_ctx *trx = trx_from_vty(vty);
89
90 if (!trx)
91 return CMD_WARNING;
92
93 vty->node = TRX_NODE;
94
95 return CMD_SUCCESS;
96}
97
98DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
99 "bind-ip A.B.C.D",
100 "Set the IP address for the local bind\n"
101 "IPv4 Address\n")
102{
103 struct trx_ctx *trx = trx_from_vty(vty);
104
105 osmo_talloc_replace_string(trx, &trx->cfg.bind_addr, argv[0]);
106
107 return CMD_SUCCESS;
108}
109
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100110DEFUN(cfg_remote_ip, cfg_remote_ip_cmd,
111 "remote-ip A.B.C.D",
112 "Set the IP address for the remote BTS\n"
113 "IPv4 Address\n")
114{
115 struct trx_ctx *trx = trx_from_vty(vty);
116
117 osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, argv[0]);
118
119 return CMD_SUCCESS;
120}
121
122DEFUN(cfg_base_port, cfg_base_port_cmd,
123 "base-port <1-65535>",
124 "Set the TRX Base Port\n"
125 "TRX Base Port\n")
126{
127 struct trx_ctx *trx = trx_from_vty(vty);
128
129 trx->cfg.base_port = atoi(argv[0]);
130
131 return CMD_SUCCESS;
132}
133
134DEFUN(cfg_dev_args, cfg_dev_args_cmd,
135 "dev-args DESC",
136 "Set the device-specific arguments to pass to the device\n"
137 "Device-specific arguments\n")
138{
139 struct trx_ctx *trx = trx_from_vty(vty);
140
141 osmo_talloc_replace_string(trx, &trx->cfg.dev_args, argv[0]);
142
143 return CMD_SUCCESS;
144}
145
146DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
147 "tx-sps (1|4)",
148 "Set the Tx Samples-per-Symbol\n"
149 "Tx Samples-per-Symbol\n")
150{
151 struct trx_ctx *trx = trx_from_vty(vty);
152
153 trx->cfg.tx_sps = atoi(argv[0]);
154
155 return CMD_SUCCESS;
156}
157
158DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
159 "rx-sps (1|4)",
160 "Set the Rx Samples-per-Symbol\n"
161 "Rx Samples-per-Symbol\n")
162{
163 struct trx_ctx *trx = trx_from_vty(vty);
164
165 trx->cfg.rx_sps = atoi(argv[0]);
166
167 return CMD_SUCCESS;
168}
169
170DEFUN(cfg_test_rtsc, cfg_test_rtsc_cmd,
171 "test rtsc <0-7>",
172 "Set the Random Normal Burst test mode with TSC\n"
173 "TSC\n")
174{
175 struct trx_ctx *trx = trx_from_vty(vty);
176
177 if (trx->cfg.rach_delay_set) {
178 vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s",
179 VTY_NEWLINE);
180 return CMD_WARNING;
181 }
182
183 trx->cfg.rtsc_set = true;
184 trx->cfg.rtsc = atoi(argv[0]);
185 if (!trx->cfg.egprs) /* Don't override egprs which sets different filler */
186 trx->cfg.filler = FILLER_NORM_RAND;
187
188 return CMD_SUCCESS;
189}
190
191DEFUN(cfg_test_rach_delay, cfg_test_rach_delay_cmd,
192 "test rach-delay <0-68>",
193 "Set the Random Access Burst test mode with delay\n"
194 "RACH delay\n")
195{
196 struct trx_ctx *trx = trx_from_vty(vty);
197
198 if (trx->cfg.rtsc_set) {
199 vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s",
200 VTY_NEWLINE);
201 return CMD_WARNING;
202 }
203
204 if (trx->cfg.egprs) {
205 vty_out(vty, "rach-delay and egprs options are mutual-exclusive%s",
206 VTY_NEWLINE);
207 return CMD_WARNING;
208 }
209
210 trx->cfg.rach_delay_set = true;
211 trx->cfg.rach_delay = atoi(argv[0]);
212 trx->cfg.filler = FILLER_ACCESS_RAND;
213
214 return CMD_SUCCESS;
215}
216
217DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
218 "clock-ref (internal|external|gpsdo)",
219 "Set the Reference Clock\n"
220 "Enable internal referece (default)\n"
221 "Enable external 10 MHz reference\n"
222 "Enable GPSDO reference\n")
223{
224 struct trx_ctx *trx = trx_from_vty(vty);
225
226 trx->cfg.clock_ref = get_string_value(clock_ref_names, argv[0]);
227
228 return CMD_SUCCESS;
229}
230
231DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd,
232 "multi-arfcn (disable|enable)",
233 "Enable multi-ARFCN transceiver (default=disable)\n")
234{
235 struct trx_ctx *trx = trx_from_vty(vty);
236
237 if (strcmp("disable", argv[0]) == 0) {
238 trx->cfg.multi_arfcn = false;
239 } else if (strcmp("enable", argv[0]) == 0) {
240 trx->cfg.multi_arfcn = true;
241 } else {
242 return CMD_WARNING;
243 }
244
245 return CMD_SUCCESS;
246}
247
248DEFUN(cfg_offset, cfg_offset_cmd,
249 "offset FLOAT",
250 "Set the baseband frequency offset (default=0, auto)\n"
251 "Baseband Frequency Offset\n")
252{
253 struct trx_ctx *trx = trx_from_vty(vty);
254
255 trx->cfg.offset = atof(argv[0]);
256
257 return CMD_SUCCESS;
258}
259
260DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd,
261 "rssi-offset FLOAT",
262 "Set the RSSI to dBm offset in dB (default=0)\n"
263 "RSSI to dBm offset in dB\n")
264{
265 struct trx_ctx *trx = trx_from_vty(vty);
266
267 trx->cfg.rssi_offset = atof(argv[0]);
268
269 return CMD_SUCCESS;
270}
271
272DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
273 "swap-channels (disable|enable)",
274 "Swap channels (default=disable)\n")
275{
276 struct trx_ctx *trx = trx_from_vty(vty);
277
278 if (strcmp("disable", argv[0]) == 0) {
279 trx->cfg.swap_channels = false;
280 } else if (strcmp("enable", argv[0]) == 0) {
281 trx->cfg.swap_channels = true;
282 } else {
283 return CMD_WARNING;
284 }
285
286 return CMD_SUCCESS;
287}
288
289DEFUN(cfg_egprs, cfg_egprs_cmd,
290 "egprs (disable|enable)",
291 "Enable EDGE receiver (default=disable)\n")
292{
293 struct trx_ctx *trx = trx_from_vty(vty);
294
295 if (strcmp("disable", argv[0]) == 0) {
296 trx->cfg.egprs = false;
297 } else if (strcmp("enable", argv[0]) == 0) {
298 trx->cfg.egprs = true;
299 trx->cfg.filler = FILLER_EDGE_RAND;
300 } else {
301 return CMD_WARNING;
302 }
303
304 return CMD_SUCCESS;
305}
306
307DEFUN(cfg_rt_prio, cfg_rt_prio_cmd,
308 "rt-prio <1-32>",
309 "Set the SCHED_RR real-time priority\n"
310 "Real time priority\n")
311{
312 struct trx_ctx *trx = trx_from_vty(vty);
313
314 trx->cfg.sched_rr = atoi(argv[0]);
315
316 return CMD_SUCCESS;
317}
318
319DEFUN(cfg_filler, cfg_filler_cmd,
320 "filler dummy",
321 "Enable C0 filler table\n"
322 "Dummy method\n")
323{
324 struct trx_ctx *trx = trx_from_vty(vty);
325
326 trx->cfg.filler = FILLER_DUMMY;
327
328 return CMD_SUCCESS;
329}
330
331DEFUN(cfg_chan, cfg_chan_cmd,
332 "chan <0-100>",
333 "Select a channel to configure\n"
334 "Channel index\n")
335{
336 struct trx_ctx *trx = trx_from_vty(vty);
337 int idx = atoi(argv[0]);
338
339 if (idx >= TRX_CHAN_MAX) {
340 vty_out(vty, "Chan list full.%s", VTY_NEWLINE);
341 return CMD_WARNING;
342 }
343 if (trx->cfg.num_chans < idx) { /* Unexisting or creating non-consecutive */
344 vty_out(vty, "Non-existent or non-consecutive chan %d.%s",
345 idx, VTY_NEWLINE);
346 return CMD_WARNING;
347 } else if (trx->cfg.num_chans == idx) { /* creating it */
348 trx->cfg.num_chans++;
349 trx->cfg.chans[idx].trx = trx;
350 trx->cfg.chans[idx].idx = idx;
351 }
352
353 vty->node = CHAN_NODE;
354 vty->index = &trx->cfg.chans[idx];
355
356 return CMD_SUCCESS;
357}
358
359DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd,
360 "rx-path NAME",
361 "Set the Rx Path\n"
362 "Rx Path name\n")
363{
364 struct trx_chan *chan = vty->index;
365
366 osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]);
367
368 return CMD_SUCCESS;
369}
370
371DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd,
372 "tx-path NAME",
373 "Set the Tx Path\n"
374 "Tx Path name\n")
375{
376 struct trx_chan *chan = vty->index;
377
378 osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]);
379
380 return CMD_SUCCESS;
381}
382
383static int dummy_config_write(struct vty *v)
384{
385 return CMD_SUCCESS;
386}
387
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100388static int config_write_trx(struct vty *vty)
389{
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100390 struct trx_chan *chan;
391 int i;
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100392 struct trx_ctx *trx = trx_from_vty(vty);
393
394 vty_out(vty, "trx%s", VTY_NEWLINE);
395 if (trx->cfg.bind_addr)
396 vty_out(vty, " bind-ip %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100397 if (trx->cfg.remote_addr)
398 vty_out(vty, " remote-ip %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
399 if (trx->cfg.base_port != DEFAULT_TRX_PORT)
400 vty_out(vty, " base-port %u%s", trx->cfg.base_port, VTY_NEWLINE);
401 if (trx->cfg.dev_args)
402 vty_out(vty, " dev-args %s%s", trx->cfg.dev_args, VTY_NEWLINE);
403 if (trx->cfg.tx_sps != DEFAULT_TX_SPS)
404 vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
405 if (trx->cfg.rx_sps != DEFAULT_RX_SPS)
406 vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
407 if (trx->cfg.rtsc_set)
408 vty_out(vty, " test rtsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
409 if (trx->cfg.rach_delay_set)
410 vty_out(vty, " test rach-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
411 if (trx->cfg.clock_ref != REF_INTERNAL)
412 vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
413 vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE);
414 if (trx->cfg.offset != 0)
415 vty_out(vty, " offset %f%s", trx->cfg.offset, VTY_NEWLINE);
416 if (trx->cfg.rssi_offset != 0)
417 vty_out(vty, " rssi-offset %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
418 vty_out(vty, " swap-channels %s%s", trx->cfg.swap_channels ? "enable" : "disable", VTY_NEWLINE);
419 vty_out(vty, " egprs %s%s", trx->cfg.egprs ? "enable" : "disable", VTY_NEWLINE);
420 if (trx->cfg.sched_rr != 0)
421 vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE);
422
423 for (i = 0; i < trx->cfg.num_chans; i++) {
424 chan = &trx->cfg.chans[i];
425 vty_out(vty, " chan %u%s", chan->idx, VTY_NEWLINE);
426 if (chan->rx_path)
427 vty_out(vty, " rx-path %s%s", chan->rx_path, VTY_NEWLINE);
428 if (chan->tx_path)
429 vty_out(vty, " tx-path %s%s", chan->tx_path, VTY_NEWLINE);
430 }
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100431
432 return CMD_SUCCESS;
433}
434
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100435static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx)
436{
437 struct trx_chan *chan;
438 int i;
439 vty_out(vty, "TRX Config:%s", VTY_NEWLINE);
440 vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
441 vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
442 vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE);
443 vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
444 vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
445 vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
446 vty_out(vty, " Test Mode: TSC: %u (%s)%s", trx->cfg.rtsc,
447 trx->cfg.rtsc_set ? "Enabled" : "Disabled", VTY_NEWLINE);
448 vty_out(vty, " Test Mode: RACH Delay: %u (%s)%s", trx->cfg.rach_delay,
449 trx->cfg.rach_delay_set ? "Enabled" : "Disabled", VTY_NEWLINE);
450 vty_out(vty, " C0 Filler Table: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
451 vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
452 vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE);
453 vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE);
454 vty_out(vty, " RSSI to dBm offset: %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
455 vty_out(vty, " Swap channels: %s%s", trx->cfg.swap_channels ? "Enabled" : "Disabled", VTY_NEWLINE);
456 vty_out(vty, " EDGE support: %s%s", trx->cfg.egprs ? "Enabled" : "Disabled", VTY_NEWLINE);
457 vty_out(vty, " Real Time Priority: %u (%s)%s", trx->cfg.sched_rr,
458 trx->cfg.sched_rr ? "Enabled" : "Disabled", VTY_NEWLINE);
459 vty_out(vty, " Channels: %u%s", trx->cfg.num_chans, VTY_NEWLINE);
460 for (i = 0; i < trx->cfg.num_chans; i++) {
461 chan = &trx->cfg.chans[i];
462 vty_out(vty, " Channel %u:%s", chan->idx, VTY_NEWLINE);
463 if (chan->rx_path)
464 vty_out(vty, " Rx Path: %s%s", chan->rx_path, VTY_NEWLINE);
465 if (chan->tx_path)
466 vty_out(vty, " Tx Path: %s%s", chan->tx_path, VTY_NEWLINE);
467 }
468}
469
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100470DEFUN(show_trx, show_trx_cmd,
471 "show trx",
472 SHOW_STR "Display information on the TRX\n")
473{
474 struct trx_ctx *trx = trx_from_vty(vty);
475
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100476 trx_dump_vty(vty, trx);
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100477
478 return CMD_SUCCESS;
479}
480
481static int trx_vty_is_config_node(struct vty *vty, int node)
482{
483 switch (node) {
484 case TRX_NODE:
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100485 case CHAN_NODE:
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100486 return 1;
487 default:
488 return 0;
489 }
490}
491
492static int trx_vty_go_parent(struct vty *vty)
493{
494 switch (vty->node) {
495 case TRX_NODE:
496 vty->node = CONFIG_NODE;
497 vty->index = NULL;
498 vty->index_sub = NULL;
499 break;
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100500 case CHAN_NODE:
501 vty->node = TRX_NODE;
502 vty->index = NULL;
503 vty->index_sub = NULL;
504 break;
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100505 default:
506 OSMO_ASSERT(0);
507 }
508
509 return vty->node;
510}
511
512static const char trx_copyright[] =
513 "Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
514 "Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
515 "Copyright (C) 2015 Ettus Research LLC\r\n"
516 "Copyright (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
517 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
518 "This is free software: you are free to change and redistribute it.\r\n"
519 "There is NO WARRANTY, to the extent permitted by law.\r\n";
520
521struct vty_app_info g_vty_info = {
522 .name = "OsmoTRX",
523 .version = PACKAGE_VERSION,
524 .copyright = trx_copyright,
525 .go_parent_cb = trx_vty_go_parent,
526 .is_config_node = trx_vty_is_config_node,
527};
528
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100529struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx)
530{
531 struct trx_ctx * trx = talloc_zero(talloc_ctx, struct trx_ctx);
532
533 trx->cfg.bind_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
534 trx->cfg.remote_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
535 trx->cfg.base_port = DEFAULT_TRX_PORT;
536 trx->cfg.tx_sps = DEFAULT_TX_SPS;
537 trx->cfg.rx_sps = DEFAULT_RX_SPS;
538 trx->cfg.filler = FILLER_ZERO;
539
540 return trx;
541}
542
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100543int trx_vty_init(struct trx_ctx* trx)
544{
545 g_trx_ctx = trx;
546 install_element_ve(&show_trx_cmd);
547
548 install_element(CONFIG_NODE, &cfg_trx_cmd);
549
550 install_node(&trx_node, config_write_trx);
551 install_element(TRX_NODE, &cfg_bind_ip_cmd);
Pau Espin Pedrola3ab8c22018-02-21 15:41:03 +0100552 install_element(TRX_NODE, &cfg_remote_ip_cmd);
553 install_element(TRX_NODE, &cfg_base_port_cmd);
554 install_element(TRX_NODE, &cfg_dev_args_cmd);
555 install_element(TRX_NODE, &cfg_tx_sps_cmd);
556 install_element(TRX_NODE, &cfg_rx_sps_cmd);
557 install_element(TRX_NODE, &cfg_test_rtsc_cmd);
558 install_element(TRX_NODE, &cfg_test_rach_delay_cmd);
559 install_element(TRX_NODE, &cfg_clock_ref_cmd);
560 install_element(TRX_NODE, &cfg_multi_arfcn_cmd);
561 install_element(TRX_NODE, &cfg_offset_cmd);
562 install_element(TRX_NODE, &cfg_rssi_offset_cmd);
563 install_element(TRX_NODE, &cfg_swap_channels_cmd);
564 install_element(TRX_NODE, &cfg_egprs_cmd);
565 install_element(TRX_NODE, &cfg_rt_prio_cmd);
566 install_element(TRX_NODE, &cfg_filler_cmd);
567
568 install_element(TRX_NODE, &cfg_chan_cmd);
569 install_node(&chan_node, dummy_config_write);
570 install_element(CHAN_NODE, &cfg_chan_rx_path_cmd);
571 install_element(CHAN_NODE, &cfg_chan_tx_path_cmd);
Pau Espin Pedrol5ea18172018-02-20 16:48:15 +0100572
573 return 0;
574}