Introduce new phy_link and phy_instance abstraction

This way we can model a flexible mapping between any number of PHYs,
each having multiple instances, and then map BTSs with TRXx on top of
those PHYs.
This commit is contained in:
Harald Welte 2016-01-09 13:13:37 +01:00
parent f58542899a
commit d784e50747
29 changed files with 1429 additions and 559 deletions

View File

@ -20,9 +20,13 @@ log stderr
line vty
no login
!
phy 0
octphy hw-addr 00:0C:90:2e:80:1e
octphy net-device eth0.2342
instance 0
bts 0
band 1800
ipa unit-id 1234 0
oml remote-ip 127.0.0.1
phy-hw-addr 00:0C:90:2e:80:1e
phy-netdev eth0.2342
trx 0
phy 0 instance 0

57
doc/phy_link.txt Normal file
View File

@ -0,0 +1,57 @@
== OsmoBTS PHY interface abstraction
The OsmoBTS PHY interface serves as an abstraction layer between given
PHY hardware and the actual logical transceivers (TRXs) of a BTS inside
the OsmoBTS code base.
=== PHY link
A PHY link is a physical connection / link towards a given PHY. This
might be, for example,
* a set of file descriptors to device nodes in the /dev/ directory
(sysmobts, litecell15)
* a packet socket for sending raw Ethernet frames to an OCTPHY
* a set of UDP sockets for interacting with OsmoTRX
Each PHY interface has a set of attribute/parameters and a list of 1 to
n PHY instances.
PHY links are numbered 0..n globally inside OsmoBTS.
Each PHY link is configured via the VTY using its individual top-level
vty node. Given the different bts-model / phy specific properties, the
VTY configuration options (if any) of the PHY instance differ between
BTS models.
The PHY links and instances must be configured above the BTS/TRX nodes
in the configuration file. If the file is saved via the VTY, the code
automatically ensures this.
=== PHY instance
A PHY instance is an instance of a PHY, accessed via a PHY link.
In the case of osmo-bts-sysmo and osmo-bts-trx, there is only one
instance in every PHY link. This is due to the fact that the API inside
that PHY link does not permit for distinguishing multiple different
logical TRXs.
Other PHY implementations like the OCTPHY however do support addressing
multiple PHY instances via a single PHY link.
PHY instances are numbered 0..n inside each PHY link.
Each PHY instance is configured via the VTY as a separate node beneath each
PHY link. Given the different bts-model / phy specific properties, the
VTY configuration options (if any) of the PHY instance differ between
BTS models.
=== Mapping PHY instances to TRXs
Each TRX node in the VTY must use the 'phy N instance M' command in
order to specify which PHY instance is allocated to this specific TRX.

42
doc/startup.txt Normal file
View File

@ -0,0 +1,42 @@
== start-up / sequencing during OsmoBTS start
The start-up procedure of OsmoBTS can be described as follows:
|===
| bts-specific | main() |
| common | bts_main() | initialization of talloc contexts
| common | bts_log_init() | initialization of logging
| common | handle_options() | common option parsing
| bts-specific | bts_model_handle_options() | model-specific option parsing
| common | gsm_bts_alloc() | allocation of BTS/TRX/TS data structures
| common | vty_init() | Initialziation of VTY core, libosmo-abis and osmo-bts VTY
| common | main() | Setting of scheduler RR priority (if configured)
| common | main() | Initialization of GSMTAP (if configured)
| common | bts_init() | configuration of defaults in bts/trx/s object
| bts-specific | bts_model_init | ?
| common | abis_init() | Initialization of libosmo-abis
| common | vty_read_config_file() | Reading of configuration file
| bts-specific | bts_model_phy_link_set_defaults() | Called for every PHY link created
| bts-specific | bts_model_phy_instance_set_defaults() | Called for every PHY Instance created
| common | bts_controlif_setup() | Initialization of Control Interface
| bts-specific | bts_model_ctrl_cmds_install()
| common | telnet_init() | Initialization of telnet interface
| common | pcu_sock_init() | Initializaiton of PCU socket
| common | main() | Installation of signal handlers
| common | abis_open() | Start of the A-bis connection to BSC
| common | phy_links_open() | Iterate over list of configured PHY links
| bts-specific | bts_model_phy_link_open() | Open each of the configured PHY links
| common | write_pid_file() | Generate the pid file
| common | osmo_daemonize() | Fork as daemon in background (if configured)
| common | bts_main() | Run main loop until global variable quit >= 2
| bts-specific | bts_model_oml_estab() | Called by core once OML link is established
| bts-specific | bts_model_check_oml() | called each time OML sets some attributes on a MO, checks if attributes are valid
| bts-specific | bts_model_apply_oml() | called each time OML sets some attributes on a MO, stores attribute contents in data structures
| bts-specific | bts_model_opstart() | for NM_OC_BTS, NM_OC_SITE_MANAGER, NM_OC_GPRS_NSE, NM_OC_GPRS_CELL, NMO_OC_GPRS_NSVC
| bts-specific | bts_model_opstart() | for NM_OC_RADIO_CARRIER for each trx
| bts-specific | bts_model_opstart() | for NM_OC_BASEB_TRANSC for each trx
| bts-specific | bts_model_opstart() | for NM_OC_CHANNEL for each timeslot on each trx
| bts-specific | bts_model_change_power() | change transmit power for each trx (power ramp-up/ramp-down
| bts-specific | bts_model_abis_close() | called when either one of the RSL links or the OML link are down

View File

@ -1,4 +1,4 @@
noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \
oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \
handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \
power_control.h scheduler.h scheduler_backend.h
power_control.h scheduler.h scheduler_backend.h phy_link.h

View File

@ -21,12 +21,12 @@ void destroy_bts(struct gsm_bts *bts);
int work_bts(struct gsm_bts *bts);
int bts_link_estab(struct gsm_bts *bts);
int trx_link_estab(struct gsm_bts_trx *trx);
int trx_set_available(struct gsm_bts_trx *trx, int avail);
void bts_new_si(void *arg);
void bts_setup_slot(struct gsm_bts_trx_ts *slot, uint8_t comb);
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg);
struct msgb *bts_agch_dequeue(struct gsm_bts *bts);
void bts_update_agch_max_queue_length(struct gsm_bts *bts);
int bts_agch_max_queue_length(int T, int bcch_conf);
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
int is_ag_res);

View File

@ -8,6 +8,9 @@
#include <osmo-bts/gsm_data.h>
struct phy_link;
struct phy_instance;
/* BTS model specific functions needed by the common code */
int bts_model_init(struct gsm_bts *bts);
@ -32,6 +35,8 @@ int bts_model_vty_init(struct gsm_bts *bts);
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts);
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink);
void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst);
int bts_model_oml_estab(struct gsm_bts *bts);
@ -47,4 +52,7 @@ int bts_model_ctrl_cmds_install(struct gsm_bts *bts);
int bts_model_handle_options(int argc, char **argv);
void bts_model_print_help();
void bts_model_phy_link_set_defaults(struct phy_link *plink);
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst);
#endif

View File

@ -119,21 +119,6 @@ enum lchan_ciph_state {
#include "openbsc/gsm_data_shared.h"
struct femtol1_hdl;
static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx)
{
return trx->role_bts.l1h;
}
struct trx_l1h;
static inline struct trx_l1h *trx_l1h_hdl(struct gsm_bts_trx *trx)
{
return trx->role_bts.l1h;
}
void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state);
/* cipher code */

115
include/osmo-bts/phy_link.h Normal file
View File

@ -0,0 +1,115 @@
#pragma once
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmo-bts/scheduler.h>
#include <linux/if_packet.h>
struct gsm_bts_trx;
enum phy_link_type {
PHY_LINK_T_NONE,
PHY_LINK_T_SYSMOBTS,
PHY_LINK_T_OSMOTRX,
};
enum phy_link_state {
PHY_LINK_SHUTDOWN,
PHY_LINK_CONNECTING,
PHY_LINK_CONNECTED,
};
/* A PHY link represents the connection to a given PHYsical layer
* implementation. That PHY link contains 1...N PHY instances, one for
* each TRX */
struct phy_link {
struct llist_head list;
int num;
enum phy_link_type type;
enum phy_link_state state;
struct llist_head instances;
char *description;
union {
struct {
} sysmobts;
struct {
char *transceiver_ip;
uint16_t base_port_local;
uint16_t base_port_remote;
struct osmo_fd trx_ofd_clk;
uint32_t clock_advance;
uint32_t rts_advance;
int rxgain_valid;
int rxgain;
int rxgain_sent;
int power_valid;
int power;
int power_oml;
int power_sent;
} osmotrx;
struct {
/* MAC address of the PHY */
struct sockaddr_ll phy_addr;
/* Network device name */
char *netdev_name;
/* configuration */
uint32_t rf_port_index;
uint32_t rx_gain_db;
uint32_t tx_atten_db;
struct octphy_hdl *hdl;
} octphy;
} u;
};
struct phy_instance {
/* liked inside phy_link.linstances */
struct llist_head list;
int num;
char *description;
/* pointer to the PHY link to which we belong */
struct phy_link *phy_link;
/* back-pointer to the TRX to which we're associated */
struct gsm_bts_trx *trx;
union {
struct {
} sysmobts;
struct {
struct trx_l1h *hdl;
} osmotrx;
struct {
/* logical transceiver number within one PHY */
uint32_t trx_id;
} octphy;
} u;
};
struct phy_link *phy_link_by_num(int num);
struct phy_link *phy_link_create(void *ctx, int num);
void phy_link_destroy(struct phy_link *plink);
void phy_link_state_set(struct phy_link *plink, enum phy_link_state state);
int phy_links_open(void);
struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num);
struct phy_instance *phy_instance_create(struct phy_link *plink, int num);
void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx);
void phy_instance_destroy(struct phy_instance *pinst);
const char *phy_instance_name(struct phy_instance *pinst);
void phy_user_statechg_notif(struct phy_instance *pinst, enum phy_link_state link_state);
static inline struct phy_instance *trx_phy_instance(struct gsm_bts_trx *trx)
{
return trx->role_bts.l1h;
}
int bts_model_phy_link_open(struct phy_link *plink);

View File

@ -1,6 +1,8 @@
#ifndef TRX_SCHEDULER_H
#define TRX_SCHEDULER_H
#include <osmo-bts/gsm_data.h>
/* These types define the different channels on a multiframe.
* Each channel has queues and can be activated individually.
*/
@ -133,7 +135,7 @@ extern uint32_t transceiver_last_fn;
/*! \brief Initialize the scheudler data structures */
int trx_sched_init(struct l1sched_trx *l1t);
int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx);
/*! \brief De-initialize the scheudler data structures */
void trx_sched_exit(struct l1sched_trx *l1t);

View File

@ -5,7 +5,12 @@
#include <osmocom/vty/command.h>
enum bts_vty_node {
BTS_NODE = _LAST_OSMOVTY_NODE + 1,
/* PHY_NODE must come before BTS node to ensure the phy
* instances are created at the time the TRX nodes want to refer
* to them */
PHY_NODE = _LAST_OSMOVTY_NODE + 1,
PHY_INST_NODE,
BTS_NODE,
TRX_NODE,
};

View File

@ -8,6 +8,6 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
load_indication.c pcu_sock.c handover.c msg_utils.c \
load_indication.c pcu_sock.c handover.c msg_utils.c \
tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
l1sap.c cbch.c power_control.c main.c
l1sap.c cbch.c power_control.c main.c phy_link.c
libl1sched_a_SOURCES = scheduler.c

View File

@ -44,6 +44,7 @@
#include <osmo-bts/oml.h>
#include <osmo-bts/signal.h>
static void bts_update_agch_max_queue_length(struct gsm_bts *bts);
struct gsm_network bts_gsmnet = {
.bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list },
@ -72,6 +73,8 @@ static int bts_signal_cbfn(unsigned int subsys, unsigned int signal,
return 0;
}
/* Initialize the BTS (and TRX) data structures, called before config
* file reading */
int bts_init(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb;
@ -255,6 +258,31 @@ int trx_link_estab(struct gsm_bts_trx *trx)
return 0;
}
/* set the availability of the TRX (used by PHY driver) */
int trx_set_available(struct gsm_bts_trx *trx, int avail)
{
int tn;
LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n",
trx->nr, avail);
if (avail) {
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->mo);
oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
} else {
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE);
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
}
return 0;
}
int lchan_init_lapdm(struct gsm_lchan *lchan)
{
struct lapdm_channel *lc = &lchan->lapdm_ch;
@ -310,7 +338,7 @@ int bts_agch_max_queue_length(int T, int bcch_conf)
return (T + 2 * S) * ccch_rach_ratio256 / 256;
}
void bts_update_agch_max_queue_length(struct gsm_bts *bts)
static void bts_update_agch_max_queue_length(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
struct gsm48_system_information_type_3 *si3;

View File

@ -42,6 +42,7 @@
#include <osmocom/core/gsmtap.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
@ -284,6 +285,19 @@ int bts_main(int argc, char **argv)
exit(1);
}
if (!phy_link_by_num(0)) {
fprintf(stderr, "You need to configure at last phy0\n");
exit(1);
}
llist_for_each_entry(trx, &bts->trx_list, list) {
if (!trx->role_bts.l1h) {
fprintf(stderr, "TRX %u has no associated PHY instance\n",
trx->nr);
exit(1);
}
}
write_pid_file("osmo-bts");
bts_controlif_setup(bts);
@ -317,6 +331,12 @@ int bts_main(int argc, char **argv)
exit(2);
}
rc = phy_links_open();
if (rc < 0) {
fprintf(stderr, "unable ot open PHY link(s)\n");
exit(2);
}
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {

159
src/common/phy_link.c Normal file
View File

@ -0,0 +1,159 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/logging.h>
static LLIST_HEAD(g_phy_links);
struct phy_link *phy_link_by_num(int num)
{
struct phy_link *plink;
llist_for_each_entry(plink, &g_phy_links, list) {
if (plink->num == num)
return plink;
}
return NULL;
}
struct phy_link *phy_link_create(void *ctx, int num)
{
struct phy_link *plink;
if (phy_link_by_num(num))
return NULL;
plink = talloc_zero(ctx, struct phy_link);
plink->num = num;
plink->state = PHY_LINK_SHUTDOWN;
INIT_LLIST_HEAD(&plink->instances);
llist_add_tail(&plink->list, &g_phy_links);
bts_model_phy_link_set_defaults(plink);
return plink;
}
const struct value_string phy_link_state_vals[] = {
{ PHY_LINK_SHUTDOWN, "shutdown" },
{ PHY_LINK_CONNECTING, "connectiong" },
{ PHY_LINK_CONNECTED, "connected" },
{ 0, NULL }
};
void phy_link_state_set(struct phy_link *plink, enum phy_link_state state)
{
struct phy_instance *pinst;
LOGP(DL1C, LOGL_INFO, "PHY link state change %s -> %s\n",
get_value_string(phy_link_state_vals, plink->state),
get_value_string(phy_link_state_vals, state));
/* notify all TRX associated with this phy */
llist_for_each_entry(pinst, &plink->instances, list) {
struct gsm_bts_trx *trx = pinst->trx;
if (!trx)
continue;
switch (state) {
case PHY_LINK_CONNECTED:
LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n");
trx_set_available(trx, 1);
break;
default:
LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n");
trx_set_available(trx, 0);
break;
}
}
plink->state = state;
}
struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num)
{
struct phy_instance *pinst;
llist_for_each_entry(pinst, &plink->instances, list) {
if (pinst->num == num)
return pinst;
}
return NULL;
}
struct phy_instance *phy_instance_create(struct phy_link *plink, int num)
{
struct phy_instance *pinst;
if (phy_instance_by_num(plink, num))
return NULL;
pinst = talloc_zero(plink, struct phy_instance);
pinst->num = num;
pinst->phy_link = plink;
llist_add_tail(&pinst->list, &plink->instances);
bts_model_phy_instance_set_defaults(pinst);
return pinst;
}
void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx)
{
trx->role_bts.l1h = pinst;
pinst->trx = trx;
}
void phy_instance_destroy(struct phy_instance *pinst)
{
/* remove from list of instances in the link */
llist_del(&pinst->list);
/* remove reverse link from TRX */
OSMO_ASSERT(pinst->trx->role_bts.l1h == pinst);
pinst->trx->role_bts.l1h = NULL;
pinst->trx = NULL;
talloc_free(pinst);
}
void phy_link_destroy(struct phy_link *plink)
{
struct phy_instance *pinst, *pinst2;
llist_for_each_entry_safe(pinst, pinst2, &plink->instances, list)
phy_instance_destroy(pinst);
talloc_free(plink);
}
int phy_links_open(void)
{
struct phy_link *plink;
llist_for_each_entry(plink, &g_phy_links, list) {
int rc;
rc = bts_model_phy_link_open(plink);
if (rc < 0)
return rc;
}
return 0;
}
const char *phy_instance_name(struct phy_instance *pinst)
{
static char buf[32];
snprintf(buf, sizeof(buf), "phy%u.%u", pinst->phy_link->num,
pinst->num);
return buf;
}

View File

@ -134,11 +134,13 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
* init / exit
*/
int trx_sched_init(struct l1sched_trx *l1t)
int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx)
{
uint8_t tn;
int i;
l1t->trx = trx;
LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr);
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
@ -191,7 +193,7 @@ void trx_sched_exit(struct l1sched_trx *l1t)
void trx_sched_reset(struct l1sched_trx *l1t)
{
trx_sched_exit(l1t);
trx_sched_init(l1t);
trx_sched_init(l1t, l1t->trx);
}
struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn,

View File

@ -40,6 +40,7 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
@ -53,6 +54,13 @@
int bts_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case PHY_INST_NODE:
vty->node = PHY_NODE;
{
struct phy_instance *pinst = vty->index;
vty->index = pinst->phy_link;
}
break;
case TRX_NODE:
vty->node = BTS_NODE;
{
@ -60,6 +68,7 @@ int bts_vty_go_parent(struct vty *vty)
vty->index = trx->bts;
}
break;
case PHY_NODE:
default:
vty->node = CONFIG_NODE;
}
@ -71,6 +80,8 @@ int bts_vty_is_config_node(struct vty *vty, int node)
switch (node) {
case TRX_NODE:
case BTS_NODE:
case PHY_NODE:
case PHY_INST_NODE:
return 1;
default:
return 0;
@ -81,6 +92,17 @@ gDEFUN(ournode_exit, ournode_exit_cmd, "exit",
"Exit current node, go down to provious node")
{
switch (vty->node) {
case PHY_INST_NODE:
vty->node = PHY_NODE;
{
struct phy_instance *pinst = vty->index;
vty->index = pinst->phy_link;
}
break;
case PHY_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
case TRX_NODE:
vty->node = BTS_NODE;
{
@ -141,6 +163,7 @@ static struct cmd_node trx_node = {
1,
};
DEFUN(cfg_bts_trx, cfg_bts_trx_cmd,
"trx <0-254>",
"Select a TRX to configure\n" "TRX number\n")
@ -151,7 +174,7 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd,
trx = gsm_bts_trx_num(bts, trx_nr);
if (!trx) {
vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%d%s",
vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%u%s",
trx_nr, bts->num_trx - 1, VTY_NEWLINE);
return CMD_WARNING;
}
@ -232,6 +255,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
llist_for_each_entry(trx, &bts->trx_list, list) {
struct trx_power_params *tpp = &trx->power_params;
struct phy_instance *pinst = trx_phy_instance(trx);
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
if (trx->power_params.user_gain_mdB)
@ -246,6 +270,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " ms-power-control %s%s",
trx->ms_power_control == 0 ? "dsp" : "osmo",
VTY_NEWLINE);
vty_out(vty, " phy %u instance %u%s", pinst->phy_link->num,
pinst->num, VTY_NEWLINE);
bts_model_config_write_trx(vty, trx);
}
@ -262,6 +288,35 @@ static int config_write_bts(struct vty *vty)
return CMD_SUCCESS;
}
static void config_write_phy_single(struct vty *vty, struct phy_link *plink)
{
int i;
vty_out(vty, "phy %u%s", plink->num, VTY_NEWLINE);
bts_model_config_write_phy(vty, plink);
for (i = 0; i < 255; i++) {
struct phy_instance *pinst = phy_instance_by_num(plink, i);
if (!pinst)
break;
vty_out(vty, " instance %u%s", pinst->num, VTY_NEWLINE);
}
}
static int config_write_phy(struct vty *vty)
{
int i;
for (i = 0; i < 255; i++) {
struct phy_link *plink = phy_link_by_num(i);
if (!plink)
break;
config_write_phy_single(vty, plink);
}
return CMD_SUCCESS;
}
static int config_write_dummy(struct vty *vty)
{
return CMD_SUCCESS;
@ -532,6 +587,33 @@ DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_phy, cfg_trx_phy_cmd,
"phy <0-255> instance <0-255>",
"Configure PHY Link+Instance for this TRX\n"
"PHY Link number\n" "PHY instance\n" "PHY Instance number")
{
struct gsm_bts_trx *trx = vty->index;
struct phy_link *plink = phy_link_by_num(atoi(argv[0]));
struct phy_instance *pinst;
if (!plink) {
vty_out(vty, "phy%s does not exist%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
pinst = phy_instance_by_num(plink, atoi(argv[1]));
if (!pinst) {
vty_out(vty, "phy%s instance %s does not exit%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
trx->role_bts.l1h = pinst;
pinst->trx = trx;
return CMD_SUCCESS;
}
/* ======================================================================
* SHOW
@ -702,6 +784,106 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd,
return CMD_SUCCESS;
}
static struct cmd_node phy_node = {
PHY_NODE,
"%s(phy)#",
1,
};
static struct cmd_node phy_inst_node = {
PHY_INST_NODE,
"%s(phy-inst)#",
1,
};
DEFUN(cfg_phy, cfg_phy_cmd,
"phy <0-255>",
"Select a PHY to configure\n" "PHY number\n")
{
int phy_nr = atoi(argv[0]);
struct phy_link *plink;
plink = phy_link_by_num(phy_nr);
if (!plink)
plink = phy_link_create(tall_bts_ctx, phy_nr);
if (!plink)
return CMD_WARNING;
vty->index = plink;
vty->index_sub = &plink->description;
vty->node = PHY_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_phy_inst, cfg_phy_inst_cmd,
"instance <0-255>",
"Select a PHY instance to configure\n" "PHY Instance number\n")
{
int inst_nr = atoi(argv[0]);
struct phy_link *plink = vty->index;
struct phy_instance *pinst;
pinst = phy_instance_by_num(plink, inst_nr);
if (!pinst) {
pinst = phy_instance_create(plink, inst_nr);
if (!pinst) {
vty_out(vty, "Unable to create phy%u instance %u%s",
plink->num, inst_nr, VTY_NEWLINE);
return CMD_WARNING;
}
}
vty->index = pinst;
vty->index_sub = &pinst->description;
vty->node = PHY_INST_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_phy_no_inst, cfg_phy_no_inst_cmd,
"no instance <0-255>"
NO_STR "Select a PHY instance to remove\n", "PHY Instance number\n")
{
int inst_nr = atoi(argv[0]);
struct phy_link *plink = vty->index;
struct phy_instance *pinst;
pinst = phy_instance_by_num(plink, inst_nr);
if (!pinst) {
vty_out(vty, "No such instance %u%s", inst_nr, VTY_NEWLINE);
return CMD_WARNING;
}
phy_instance_destroy(pinst);
return CMD_SUCCESS;
}
#if 0
DEFUN(cfg_phy_type, cfg_phy_type_cmd,
"type (sysmobts|osmo-trx|virtual)",
"configure the type of the PHY\n"
"sysmocom sysmoBTS PHY\n"
"OsmoTRX based PHY\n"
"Virtual PHY (GSMTAP based)\n")
{
struct phy_link *plink = vty->index;
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Cannot change type of active PHY%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (!strcmp(argv[0], "sysmobts"))
plink->type = PHY_LINK_T_SYSMOBTS;
else if (!strcmp(argv[0], "osmo-trx"))
plink->type = PHY_LINK_T_OSMOTRX;
else if (!strcmp(argv[0], "virtual"))
plink->type = PHY_LINK_T_VIRTUAL;
}
#endif
DEFUN(bts_t_t_l_jitter_buf,
bts_t_t_l_jitter_buf_cmd,
"bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>",
@ -813,10 +995,20 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat)
install_element(TRX_NODE, &cfg_trx_pr_step_size_cmd);
install_element(TRX_NODE, &cfg_trx_pr_step_interval_cmd);
install_element(TRX_NODE, &cfg_trx_ms_power_control_cmd);
install_element(TRX_NODE, &cfg_trx_phy_cmd);
install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd);
install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd);
install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd);
install_element(CONFIG_NODE, &cfg_phy_cmd);
install_node(&phy_node, config_write_phy);
install_default(PHY_NODE);
install_element(PHY_NODE, &cfg_phy_inst_cmd);
install_element(PHY_NODE, &cfg_phy_no_inst_cmd);
install_node(&phy_inst_node, config_write_dummy);
install_default(PHY_INST_NODE);
return 0;
}

View File

@ -38,6 +38,7 @@
#include <osmocom/core/socket.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/l1sap.h>
@ -109,6 +110,17 @@ osmocom_to_octphy_band(enum gsm_band osmo_band, unsigned int arfcn)
}
};
struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id)
{
struct phy_instance *pinst;
pinst = phy_instance_by_num(fl1h->phy_link, trx_id);
if (!pinst)
return NULL;
return pinst->trx;
}
struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx,
tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id)
{
@ -282,10 +294,9 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg,
}
/* For OctPHY, this only about sending state changes to BSC */
int l1if_activate_rf(struct octphy_hdl *fl1h, int on)
int l1if_activate_rf(struct gsm_bts_trx *trx, int on)
{
int i;
struct gsm_bts_trx *trx = fl1h->priv;
if (on) {
/* signal availability */
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
@ -422,7 +433,8 @@ static void empty_req_from_rts_ind(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_E
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
struct osmo_phsap_prim *l1sap)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *l1msg = l1p_msgb_alloc();
uint32_t u32Fn;
uint8_t u8Tn, subCh, sapi = 0;
@ -489,7 +501,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&data_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID);
data_req->TrxId.byTrxId = trx->nr;
data_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
data_req->LchId.byTimeslotNb = u8Tn;
data_req->LchId.bySAPI = sapi;
data_req->LchId.bySubChannelNb = subCh;
@ -508,7 +520,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&empty_frame_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID);
empty_frame_req->TrxId.byTrxId = trx->nr;
empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
empty_frame_req->LchId.byTimeslotNb = u8Tn;
empty_frame_req->LchId.bySAPI = sapi;
empty_frame_req->LchId.bySubChannelNb = subCh;
@ -527,7 +539,8 @@ done:
static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
struct osmo_phsap_prim *l1sap)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct gsm_lchan *lchan;
uint32_t u32Fn;
uint8_t u8Tn, subCh, sapi, ss;
@ -565,7 +578,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&data_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID);
data_req->TrxId.byTrxId = trx->nr;
data_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
data_req->LchId.byTimeslotNb = u8Tn;
data_req->LchId.bySAPI = sapi;
data_req->LchId.bySubChannelNb = subCh;
@ -590,7 +603,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&empty_frame_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID);
empty_frame_req->TrxId.byTrxId = trx->nr;
empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
empty_frame_req->LchId.byTimeslotNb = u8Tn;
empty_frame_req->LchId.bySAPI = sapi;
empty_frame_req->LchId.bySubChannelNb = subCh;
@ -686,32 +699,78 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
return rc;
}
static int trx_close_all_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car =
(tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h;
/* in a completion call-back, we take msgb ownership and must
* release it before returning */
mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP_SWAP(car);
/* we now know that the PHY link is connected */
phy_link_state_set(fl1->phy_link, PHY_LINK_CONNECTED);
msgb_free(resp);
return 0;
}
static int phy_link_trx_close_all(struct phy_link *plink)
{
struct octphy_hdl *fl1h = plink->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac;
cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *)
msgb_put(msg, sizeof(*cac));
l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CID);
mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD_SWAP(cac);
return l1if_req_compl(fl1h, msg, trx_close_all_cb, NULL);
}
int bts_model_phy_link_open(struct phy_link *plink)
{
if (plink->u.octphy.hdl)
l1if_close(plink->u.octphy.hdl);
phy_link_state_set(plink, PHY_LINK_CONNECTING);
plink->u.octphy.hdl = l1if_open(plink);
if (!plink->u.octphy.hdl) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1;
}
/* do we need to iterate over the list of instances and do some
* instance-specific initialization? */
/* close all TRXs that might still exist in this link from
* previous execitions / sessions */
phy_link_trx_close_all(plink);
/* in the call-back to the above we will set the link state to
* connected */
return 0;
}
int bts_model_init(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb;
struct octphy_hdl *fl1h;
LOGP(DL1C, LOGL_NOTICE, "model_init()\n");
btsb = bts_role_bts(bts);
btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
fl1h = talloc_zero(bts, struct octphy_hdl);
if (!fl1h)
return -ENOMEM;
INIT_LLIST_HEAD(&fl1h->wlc_list);
INIT_LLIST_HEAD(&fl1h->wlc_postponed);
fl1h->priv = bts->c0;
bts->c0->role_bts.l1h = fl1h;
/* FIXME: what is the nominal transmit power of the PHY/board? */
bts->c0->nominal_power = 15;
/* configure some reasonable defaults, to be overridden by VTY */
fl1h->config.rf_port_index = 0;
fl1h->config.rx_gain_db = 70;
fl1h->config.tx_atten_db = 0;
bts_model_vty_init(bts);
return 0;
@ -750,24 +809,16 @@ static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m)
static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts *bts = trx->bts;
struct gsm_bts_trx *trx = trx_by_l1h(fl1, trx_id);
struct osmo_phsap_prim l1sap;
/* increment the primitive count for the alive timer */
fl1->alive_prim_cnt++;
/* ignore every time indication, except for c0 */
if (trx != bts->c0)
if (trx != trx->bts->c0)
return 0;
if (trx_id != trx->nr) {
LOGP(DL1C, LOGL_FATAL,
"TRX id %d from response does not match the L1 context trx %d\n",
trx_id, trx->nr);
return 0;
}
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
PRIM_OP_INDICATION, NULL);
@ -783,7 +834,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_READY_TO_SEND_INDICATION_EVT *evt,
struct msgb *l1p_msg)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts_trx *trx = trx_by_l1h(fl1, evt->TrxId.byTrxId);
struct gsm_bts *bts = trx->bts;
struct osmo_phsap_prim *l1sap;
struct gsm_time g_time;
@ -908,7 +959,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *data_ind,
struct msgb *l1p_msg)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts_trx *trx = trx_by_l1h(fl1, data_ind->TrxId.byTrxId);
uint8_t chan_nr, link_id;
struct osmo_phsap_prim *l1sap;
uint32_t fn;
@ -992,7 +1043,7 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_RACH_INDICATION_EVT *ra_ind,
struct msgb *l1p_msg)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts_trx *trx = trx_by_l1h(fl1, ra_ind->TrxId.byTrxId);
struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
struct gsm_lchan *lchan;
@ -1131,7 +1182,7 @@ static int rx_octvc1_resp(struct msgb *msg, uint32_t msg_id, uint32_t trans_id)
if (wlc->cb) {
/* call-back function must take msgb
* ownership. */
rc = wlc->cb(fl1h->priv, msg, wlc->cb_data);
rc = wlc->cb(fl1h, msg, wlc->cb_data);
} else {
rc = 0;
msgb_free(msg);
@ -1485,6 +1536,18 @@ static int rx_octphy_msg(struct msgb *msg)
return rc;
}
void bts_model_phy_link_set_defaults(struct phy_link *plink)
{
/* configure some reasonable defaults, to be overridden by VTY */
plink->u.octphy.rf_port_index = 0;
plink->u.octphy.rx_gain_db = 70;
plink->u.octphy.tx_atten_db = 0;
}
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
{
}
/***********************************************************************
* octphy socket / main loop integration
***********************************************************************/
@ -1534,15 +1597,25 @@ static int octphy_write_cb(struct osmo_fd *fd, struct msgb *msg)
return rc;
}
int l1if_open(struct octphy_hdl *fl1h)
struct octphy_hdl *l1if_open(struct phy_link *plink)
{
struct octphy_hdl *fl1h;
struct ifreq ifr;
int sfd, rc;
char *phy_dev = fl1h->netdev_name;
char *phy_dev = plink->u.octphy.netdev_name;
fl1h = talloc_zero(plink, struct octphy_hdl);
if (!fl1h)
return NULL;
INIT_LLIST_HEAD(&fl1h->wlc_list);
INIT_LLIST_HEAD(&fl1h->wlc_postponed);
fl1h->phy_link = plink;
if (!phy_dev) {
LOGP(DL1C, LOGL_ERROR, "You have to specify a phy-netdev\n");
return -EINVAL;
talloc_free(fl1h);
return NULL;
}
LOGP(DL1C, LOGL_NOTICE, "Opening L1 interface for OctPHY (%s)\n",
@ -1553,7 +1626,8 @@ int l1if_open(struct octphy_hdl *fl1h)
if (sfd < 0) {
LOGP(DL1C, LOGL_FATAL, "Error opening PHY socket: %s\n",
strerror(errno));
return -EIO;
talloc_free(fl1h);
return NULL;
}
/* resolve the string device name to an ifindex */
@ -1564,18 +1638,21 @@ int l1if_open(struct octphy_hdl *fl1h)
LOGP(DL1C, LOGL_FATAL, "Error using network device %s: %s\n",
phy_dev, strerror(errno));
close(sfd);
return -EIO;
talloc_free(fl1h);
return NULL;
}
fl1h->session_id = rand();
/* set fl1h->phy_addr, which we use as sendto() destionation */
/* set fl1h->phy_addr, which we use as sendto() destination */
fl1h->phy_addr.sll_family = AF_PACKET;
fl1h->phy_addr.sll_protocol = htons(cOCTPKT_HDR_ETHERTYPE);
fl1h->phy_addr.sll_ifindex = ifr.ifr_ifindex;
fl1h->phy_addr.sll_hatype = ARPHRD_ETHER;
fl1h->phy_addr.sll_halen = 6;
/* sll_addr is filled by bts_model_vty code */
fl1h->phy_addr.sll_halen = ETH_ALEN;
/* plink->phy_addr.sll_addr is filled by bts_model_vty code */
memcpy(fl1h->phy_addr.sll_addr, plink->u.octphy.phy_addr.sll_addr,
ETH_ALEN);
/* Write queue / osmo_fd registration */
osmo_wqueue_init(&fl1h->phy_wq, 10);
@ -1588,10 +1665,11 @@ int l1if_open(struct octphy_hdl *fl1h)
rc = osmo_fd_register(&fl1h->phy_wq.bfd);
if (rc < 0) {
close(sfd);
return -EIO;
talloc_free(fl1h);
return NULL;
}
return 0;
return fl1h;
}
int l1if_close(struct octphy_hdl *fl1h)

View File

@ -13,16 +13,16 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <octphy/octvc1/gsm/octvc1_gsm_api.h>
struct octphy_hdl {
/* MAC address of the PHY */
struct sockaddr_ll phy_addr;
/* packet socket to talk with PHY */
struct osmo_wqueue phy_wq;
/* MAC address of th PHY */
struct sockaddr_ll phy_addr;
/* Network device name */
char *netdev_name;
/* address parameters of the PHY */
uint32_t session_id;
@ -32,12 +32,6 @@ struct octphy_hdl {
/* clock manager state */
uint32_t clkmgr_state;
struct {
uint32_t rf_port_index;
uint32_t rx_gain_db;
uint32_t tx_atten_db;
} config;
struct {
struct {
char *name;
@ -72,8 +66,8 @@ struct octphy_hdl {
struct llist_head wlc_postponed;
int wlc_postponed_len;
/* private pointer, points back to TRX */
void *priv;
/* back pointer to the PHY link */
struct phy_link *phy_link;
struct osmo_timer_list alive_timer;
uint32_t alive_prim_cnt;
@ -82,15 +76,10 @@ struct octphy_hdl {
int opened;
};
static inline struct octphy_hdl *trx_octphy_hdl(struct gsm_bts_trx *trx)
{
return trx->role_bts.l1h;
}
void l1if_fill_msg_hdr(tOCTVC1_MSG_HEADER *mh, struct msgb *msg,
struct octphy_hdl *fl1h, uint32_t msg_type, uint32_t api_cmd);
typedef int l1if_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, void *data);
typedef int l1if_compl_cb(struct octphy_hdl *fl1, struct msgb *l1_msg, void *data);
/* send a request primitive to the L1 and schedule completion call-back */
int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg,
@ -100,19 +89,21 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg,
struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx,
tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id);
int l1if_open(struct octphy_hdl *fl1h);
struct octphy_hdl *l1if_open(struct phy_link *plink);
int l1if_close(struct octphy_hdl *hdl);
int l1if_trx_open(struct gsm_bts_trx *trx);
int l1if_trx_close_all(struct gsm_bts *bts);
int l1if_enable_events(struct gsm_bts_trx *trx);
int l1if_activate_rf(struct octphy_hdl *fl1h, int on);
int l1if_activate_rf(struct gsm_bts_trx *trx, int on);
int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *
data_ind);
struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id);
struct msgb *l1p_msgb_alloc(void);
/* tch.c */

View File

@ -348,10 +348,11 @@ static void sapi_clear_queue(struct llist_head *queue)
}
}
static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int lchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *ar =
(tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h;
struct gsm_bts_trx *trx;
struct gsm_lchan *lchan;
uint8_t sapi;
uint8_t direction;
@ -361,7 +362,7 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *
* release it before returning */
mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ar);
OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr);
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
lchan = get_lchan_by_lchid(trx, &ar->LchId);
sapi = ar->LchId.bySAPI;
@ -411,7 +412,8 @@ err:
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx);
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD *lac;
@ -420,7 +422,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
l1if_fill_msg_hdr(&lac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CID);
lac->TrxId.byTrxId = lchan->ts->trx->nr;
lac->TrxId.byTrxId = pinst->u.octphy.trx_id;
lac->LchId.byTimeslotNb = lchan->ts->nr;
lac->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan);
lac->LchId.bySAPI = cmd->sapi;
@ -451,10 +453,11 @@ static tOCTVC1_GSM_CIPHERING_ID_ENUM rsl2l1_ciph[] = {
[4] = cOCTVC1_GSM_CIPHERING_ID_ENUM_A5_3
};
static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *pcr =
(tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *) resp->l2h;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
struct gsm_lchan *lchan;
@ -470,6 +473,7 @@ static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d
exit(-1);
}
trx = trx_by_l1h(fl1, pcr->TrxId.byTrxId);
OSMO_ASSERT(pcr->TrxId.byTrxId == trx->nr);
ts = &trx->ts[pcr->PchId.byTimeslotNb];
/* for some strange reason the response does not tell which
@ -508,8 +512,8 @@ err:
static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
{
struct gsm_bts_trx *trx = lchan->ts->trx;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CMD *pcc;
@ -518,6 +522,7 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c
l1if_fill_msg_hdr(&pcc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CID);
pcc->TrxId.byTrxId = pinst->u.octphy.trx_id;
pcc->PchId.byTimeslotNb = lchan->ts->nr;
pcc->ulSubchannelNb = lchan_to_GsmL1_SubCh_t(lchan);
pcc->ulDirection = cmd->dir;
@ -627,7 +632,8 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir)
static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx);
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
int i, res;
@ -654,10 +660,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
return res;
}
static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int lchan_deact_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *ldr =
(tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h;
struct gsm_bts_trx *trx;
struct gsm_lchan *lchan;
struct sapi_cmd *cmd;
uint8_t status;
@ -666,7 +673,7 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void
* release it before returning */
mOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ldr);
OSMO_ASSERT(ldr->TrxId.byTrxId == trx->nr);
trx = trx_by_l1h(fl1, ldr->TrxId.byTrxId);
lchan = get_lchan_by_lchid(trx, &ldr->LchId);
@ -725,7 +732,8 @@ err:
static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx);
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CMD *ldc;
@ -734,6 +742,7 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd
l1if_fill_msg_hdr(&ldc->Header, msg, fl1h,cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CID);
ldc->TrxId.byTrxId = pinst->u.octphy.trx_id;
ldc->LchId.byTimeslotNb = lchan->ts->nr;
ldc->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan);
ldc->LchId.byDirection = cmd->dir;
@ -1031,7 +1040,8 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir)
int lchan_activate(struct gsm_lchan *lchan)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx);
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
unsigned int i;
@ -1069,7 +1079,7 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
return 0;
}
static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int enable_events_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *mser =
(tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *) resp->l2h;
@ -1088,7 +1098,8 @@ static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, vo
int l1if_enable_events(struct gsm_bts_trx *trx)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_CMD *mse;
@ -1112,9 +1123,8 @@ int l1if_enable_events(struct gsm_bts_trx *trx)
dst = talloc_strdup(ctx, (const char *) src); \
} while (0)
static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data)
{
struct octphy_hdl *fl1h = resp->dst;
tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *aisr =
(tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *) resp->l2h;
@ -1136,7 +1146,8 @@ static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, voi
int l1if_check_app_sys_version(struct gsm_bts_trx *trx)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_CMD *ais;
@ -1152,9 +1163,8 @@ int l1if_check_app_sys_version(struct gsm_bts_trx *trx)
return l1if_req_compl(fl1h, msg, app_info_sys_compl_cb, 0);
}
static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data)
{
struct octphy_hdl *fl1h = resp->dst;
tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air =
(tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h;
@ -1178,7 +1188,8 @@ static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d
int l1if_check_app_version(struct gsm_bts_trx *trx)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_MAIN_MSG_APPLICATION_INFO_CMD *ai;
@ -1193,9 +1204,50 @@ int l1if_check_app_version(struct gsm_bts_trx *trx)
return l1if_req_compl(fl1h, msg, app_info_compl_cb, 0);
}
/* call-back once the TRX_OPEN_CID response arrives */
static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int trx_close_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_CLOSE_RSP *car =
(tOCTVC1_GSM_MSG_TRX_CLOSE_RSP *) resp->l2h;
/* in a completion call-back, we take msgb ownership and must
* release it before returning */
mOCTVC1_GSM_MSG_TRX_CLOSE_RSP_SWAP(car);
LOGP(DL1C, LOGL_INFO, "Rx TRX-CLOSE.conf(%u)\n", car->TrxId.byTrxId);
msgb_free(resp);
return 0;
}
static int trx_close(struct gsm_bts_trx *trx)
{
struct phy_instance *pinst = trx_phy_instance(trx);
struct phy_link *plink = pinst->phy_link;
struct octphy_hdl *fl1h = plink->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_CLOSE_CMD *cac;
cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_CMD *)
msgb_put(msg, sizeof(*cac));
l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_CLOSE_CID);
cac->TrxId.byTrxId = pinst->u.octphy.trx_id;
LOGP(DL1C, LOGL_INFO, "Tx TRX-CLOSE.req(%u)\n", cac->TrxId.byTrxId);
mOCTVC1_GSM_MSG_TRX_CLOSE_CMD_SWAP(cac);
return l1if_req_compl(fl1h, msg, trx_close_cb, NULL);
}
/* call-back once the TRX_OPEN_CID response arrives */
static int trx_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data)
{
struct gsm_bts_trx *trx;
tOCTVC1_GSM_MSG_TRX_OPEN_RSP *or =
(tOCTVC1_GSM_MSG_TRX_OPEN_RSP *) resp->l2h;
@ -1203,8 +1255,7 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d
* release it before returning */
mOCTVC1_GSM_MSG_TRX_OPEN_RSP_SWAP(or);
OSMO_ASSERT(or->TrxId.byTrxId == trx->nr);
trx = trx_by_l1h(fl1h, or->TrxId.byTrxId);
LOGP(DL1C, LOGL_INFO, "TRX-OPEN.resp(trx=%u) = %s\n",
trx->nr, octvc1_rc2string(or->Header.ulReturnCode));
@ -1221,7 +1272,6 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d
opstart_compl(&trx->mo);
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
octphy_hw_get_pcb_info(fl1h);
octphy_hw_get_rf_port_info(fl1h, 0);
octphy_hw_get_rf_ant_rx_config(fl1h, 0, 0);
@ -1238,22 +1288,24 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d
int l1if_trx_open(struct gsm_bts_trx *trx)
{
/* putting it all together */
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct phy_link *plink = pinst->phy_link;
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_OPEN_CMD *oc;
oc = (tOCTVC1_GSM_MSG_TRX_OPEN_CMD *) msgb_put(msg, sizeof(*oc));
l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_OPEN_CID);
oc->ulRfPortIndex = fl1h->config.rf_port_index;
oc->TrxId.byTrxId = trx->nr;
oc->ulRfPortIndex = plink->u.octphy.rf_port_index;
oc->TrxId.byTrxId = pinst->u.octphy.trx_id;
oc->Config.ulBand = osmocom_to_octphy_band(trx->bts->band, trx->arfcn);
oc->Config.usArfcn = trx->arfcn;
oc->Config.usTsc = trx->bts->bsic & 0x7;
oc->Config.usBcchArfcn = trx->bts->c0->arfcn;
oc->RfConfig.ulRxGainDb = fl1h->config.rx_gain_db;
oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db;
/* FIXME: compute this based on nominal transmit power, etc. */
oc->RfConfig.ulTxAttndB = fl1h->config.tx_atten_db;
oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db;
LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, "
"tsc=%u, rx_gain=%u, tx_atten=%u)\n",
@ -1266,38 +1318,6 @@ int l1if_trx_open(struct gsm_bts_trx *trx)
return l1if_req_compl(fl1h, msg, trx_open_compl_cb, NULL);
}
static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car =
(tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h;
/* in a completion call-back, we take msgb ownership and must
* release it before returning */
mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP_SWAP(car);
msgb_free(resp);
return 0;
}
int l1if_trx_close_all(struct gsm_bts *bts)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0);
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac;
cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *)
msgb_put(msg, sizeof(*cac));
l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CID);
mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD_SWAP(cac);
return l1if_req_compl(fl1h, msg, trx_close_all_cb, NULL);
}
uint32_t trx_get_hlayer1(struct gsm_bts_trx * trx)
{
return 0;
@ -1313,8 +1333,6 @@ static int trx_init(struct gsm_bts_trx *trx)
/* return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM); */
}
l1if_trx_close_all(trx->bts);
l1if_check_app_version(trx);
l1if_check_app_sys_version(trx);
@ -1325,11 +1343,12 @@ static int trx_init(struct gsm_bts_trx *trx)
* PHYSICAL CHANNE ACTIVATION
***********************************************************************/
static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *ar =
(tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *) resp->l2h;
uint8_t ts_nr;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
struct gsm_abis_mo *mo;
@ -1337,9 +1356,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *
* release it before returning */
mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar);
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
ts_nr = ar->PchId.byTimeslotNb;
OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr);
OSMO_ASSERT(ts_nr <= ARRAY_SIZE(trx->ts));
ts = &trx->ts[ts_nr];
@ -1367,7 +1385,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *
static int ts_connect(struct gsm_bts_trx_ts *ts)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(ts->trx);
struct phy_instance *pinst = trx_phy_instance(ts->trx);
struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *oc =
(tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) oc;
@ -1376,7 +1395,7 @@ static int ts_connect(struct gsm_bts_trx_ts *ts)
l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CID);
oc->TrxId.byTrxId = ts->trx->nr;
oc->TrxId.byTrxId = pinst->u.octphy.trx_id;
oc->PchId.byTimeslotNb = ts->nr;
oc->ulChannelType = pchan_to_logChComb[ts->pchan];
@ -1430,8 +1449,7 @@ int bts_model_oml_estab(struct gsm_bts *bts)
int i;
for (i = 0; i < bts->num_trx; i++) {
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
l1if_activate_rf(fl1h, 1);
l1if_activate_rf(trx, 1);
}
return 0;
}
@ -1447,14 +1465,13 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
{
struct octphy_hdl *fl1 = trx_octphy_hdl(trx);
return l1if_activate_rf(fl1, 0);
return l1if_activate_rf(trx, 0);
}
int bts_model_trx_close(struct gsm_bts_trx *trx)
{
/* FIXME: close only one TRX */
return l1if_trx_close_all(trx->bts);
return trx_close(trx);
}

View File

@ -52,10 +52,9 @@
extern int pcu_direct;
static struct gsm_bts *bts;
int bts_model_print_help()
{
return 0;
}
int bts_model_handle_options(int argc, char **argv)

View File

@ -35,7 +35,7 @@
#include <octphy/octvc1/hw/octvc1_hw_api_swap.h>
/* Chapter 12.1 */
static int get_pcb_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
static int get_pcb_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
{
tOCTVC1_HW_MSG_PCB_INFO_RSP *pir =
(tOCTVC1_HW_MSG_PCB_INFO_RSP *) resp->l2h;
@ -69,7 +69,7 @@ int octphy_hw_get_pcb_info(struct octphy_hdl *fl1h)
}
/* Chapter 12.9 */
static int rf_port_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int rf_port_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *pir =
@ -114,7 +114,7 @@ static const struct value_string radio_std_vals[] = {
};
/* Chapter 12.10 */
static int rf_port_stats_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int rf_port_stats_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr =
@ -167,7 +167,7 @@ static const struct value_string rx_gain_mode_vals[] = {
};
/* Chapter 12.13 */
static int rf_ant_rx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int rf_ant_rx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *arc =
@ -209,7 +209,7 @@ int octphy_hw_get_rf_ant_rx_config(struct octphy_hdl *fl1h, uint32_t port_idx,
}
/* Chapter 12.14 */
static int rf_ant_tx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int rf_ant_tx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *atc =
@ -292,7 +292,7 @@ static const struct value_string clocksync_state_vals[] = {
};
/* Chapter 12.15 */
static int get_clock_sync_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int get_clock_sync_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *cir =
@ -326,7 +326,7 @@ int octphy_hw_get_clock_sync_info(struct octphy_hdl *fl1h)
}
/* Chapter 12.16 */
static int get_clock_sync_stats_cb(struct gsm_bts_trx *trx, struct msgb *resp,
static int get_clock_sync_stats_cb(struct octphy_hdl *fl1, struct msgb *resp,
void *data)
{
tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr =

View File

@ -38,6 +38,7 @@
#include <osmocom/vty/misc.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/vty.h>
@ -51,149 +52,189 @@
SHOW_STR \
TRX_STR
#define OCT_STR "OCTPHY Um interface\n"
static struct gsm_bts *vty_bts;
/* configuration */
DEFUN(cfg_bts_phy_hwaddr, cfg_bts_phy_hwaddr_cmd,
"phy-hw-addr HWADDR",
"Configure the hardware addess of the OCTPHY\n"
DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd,
"octphy hw-addr HWADDR",
OCT_STR "Configure the hardware addess of the OCTPHY\n"
"hardware address in aa:bb:cc:dd:ee:ff format\n")
{
struct gsm_bts *bts = vty->index;
struct gsm_bts_trx *trx = bts->c0;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_link *plink = vty->index;
int rc;
rc = osmo_macaddr_parse(fl1h->phy_addr.sll_addr, argv[0]);
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Can only reconfigure a PHY link that is down%s",
VTY_NEWLINE);
return CMD_WARNING;
}
rc = osmo_macaddr_parse(plink->u.octphy.phy_addr.sll_addr, argv[0]);
if (rc < 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_phy_netdev, cfg_bts_phy_netdev_cmd,
"phy-netdev NAME",
"Configure the hardware device towards the OCTPHY\n"
DEFUN(cfg_phy_netdev, cfg_phy_netdev_cmd,
"octphy net-device NAME",
OCT_STR "Configure the hardware device towards the OCTPHY\n"
"Ethernet device name\n")
{
struct gsm_bts *bts = vty->index;
struct gsm_bts_trx *trx = bts->c0;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_link *plink = vty->index;
if (fl1h->netdev_name)
talloc_free(fl1h->netdev_name);
fl1h->netdev_name = talloc_strdup(fl1h, argv[0]);
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Can only reconfigure a PHY link that is down%s",
VTY_NEWLINE);
return CMD_WARNING;
}
if (plink->u.octphy.netdev_name)
talloc_free(plink->u.octphy.netdev_name);
plink->u.octphy.netdev_name = talloc_strdup(plink, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_rf_port_idx, cfg_trx_rf_port_idx_cmd,
"rf-port-index <0-255>",
"Configure the RF Port for this TRX\n"
DEFUN(cfg_phy_rf_port_idx, cfg_phy_rf_port_idx_cmd,
"octphy rf-port-index <0-255>",
OCT_STR "Configure the RF Port for this TRX\n"
"RF Port Index\n")
{
struct gsm_bts_trx *trx = vty->index;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_link *plink = vty->index;
fl1h->config.rf_port_index = atoi(argv[0]);
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Can only reconfigure a PHY link that is down%s",
VTY_NEWLINE);
return CMD_WARNING;
}
plink->u.octphy.rf_port_index = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_rx_gain_db, cfg_trx_rx_gain_db_cmd,
"rx-gain <0-73>",
"Configure the Rx Gain in dB\n"
DEFUN(cfg_phy_rx_gain_db, cfg_phy_rx_gain_db_cmd,
"octphy rx-gain <0-73>",
OCT_STR "Configure the Rx Gain in dB\n"
"Rx gain in dB\n")
{
struct gsm_bts_trx *trx = vty->index;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_link *plink = vty->index;
fl1h->config.rx_gain_db = atoi(argv[0]);
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Can only reconfigure a PHY link that is down%s",
VTY_NEWLINE);
return CMD_WARNING;
}
plink->u.octphy.rx_gain_db = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_tx_atten_db, cfg_trx_tx_atten_db_cmd,
"tx-attenuation <0-359>",
"Configure the Tx Attenuation in quarter-dB\n"
DEFUN(cfg_phy_tx_atten_db, cfg_phy_tx_atten_db_cmd,
"octphy tx-attenuation <0-359>",
OCT_STR "Configure the Tx Attenuation in quarter-dB\n"
"Tx attenuation in quarter-dB\n")
{
struct gsm_bts_trx *trx = vty->index;
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
struct phy_link *plink = vty->index;
fl1h->config.tx_atten_db = atoi(argv[0]);
if (plink->state != PHY_LINK_SHUTDOWN) {
vty_out(vty, "Can only reconfigure a PHY link that is down%s",
VTY_NEWLINE);
return CMD_WARNING;
}
plink->u.octphy.tx_atten_db = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(get_rf_port_stats, get_rf_port_stats_cmd,
"get-rf-port-stats <0-1>",
"Obtain statistics for the RF Port\n"
DEFUN(show_rf_port_stats, show_rf_port_stats_cmd,
"show phy <0-255> rf-port-stats <0-1>",
"Show statistics for the RF Port\n"
"RF Port Number\n")
{
struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0);
int phy_nr = atoi(argv[0]);
struct phy_link *plink = phy_link_by_num(phy_nr);
octphy_hw_get_rf_port_stats(fl1h, atoi(argv[0]));
octphy_hw_get_rf_port_stats(plink->u.octphy.hdl, atoi(argv[1]));
/* FIXME: Actually print to VTY, not just log */
vty_out(vty, "Please check the log file for the response%s",
VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(get_clk_sync_stats, get_clk_sync_stats_cmd,
"get-clk-sync-stats",
DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd,
"show phy <0-255> clk-sync-stats",
"Obtain statistics for the Clock Sync Manager\n")
{
struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0);
int phy_nr = atoi(argv[0]);
struct phy_link *plink = phy_link_by_num(phy_nr);
octphy_hw_get_clock_sync_stats(fl1h);
octphy_hw_get_clock_sync_stats(plink->u.octphy.hdl);
/* FIXME: Actually print to VTY, not just log */
vty_out(vty, "Please check the log file for the response%s",
VTY_NEWLINE);
return CMD_SUCCESS;
}
void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
{
if (plink->u.octphy.netdev_name)
vty_out(vty, " netdev %s%s", plink->u.octphy.netdev_name,
VTY_NEWLINE);
vty_out(vty, " hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s",
plink->u.octphy.phy_addr.sll_addr[0],
plink->u.octphy.phy_addr.sll_addr[1],
plink->u.octphy.phy_addr.sll_addr[2],
plink->u.octphy.phy_addr.sll_addr[3],
plink->u.octphy.phy_addr.sll_addr[4],
plink->u.octphy.phy_addr.sll_addr[5],
VTY_NEWLINE);
vty_out(vty, " rx-gain %u%s", plink->u.octphy.rx_gain_db,
VTY_NEWLINE);
vty_out(vty, " tx-attenuation %u%s", plink->u.octphy.tx_atten_db,
VTY_NEWLINE);
vty_out(vty, " rf-port-index %u%s", plink->u.octphy.rf_port_index,
VTY_NEWLINE);
}
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0);
if (fl1h->netdev_name)
vty_out(vty, " phy-netdev %s%s", fl1h->netdev_name,
VTY_NEWLINE);
if (btsb->auto_band)
vty_out(vty, " auto-band%s", VTY_NEWLINE);
vty_out(vty, " phy-hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s",
fl1h->phy_addr.sll_addr[0], fl1h->phy_addr.sll_addr[1],
fl1h->phy_addr.sll_addr[2], fl1h->phy_addr.sll_addr[3],
fl1h->phy_addr.sll_addr[4], fl1h->phy_addr.sll_addr[5],
VTY_NEWLINE);
}
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
{
struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
vty_out(vty, " rx-gain %u%s", fl1h->config.rx_gain_db,
VTY_NEWLINE);
vty_out(vty, " tx-attenuation %u%s", fl1h->config.tx_atten_db,
VTY_NEWLINE);
}
DEFUN(show_sys_info, show_sys_info_cmd,
"show trx <0-255> system-information",
"show phy <0-255> system-information",
SHOW_TRX_STR "Display information about system\n")
{
int trx_nr = atoi(argv[0]);
struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
int phy_nr = atoi(argv[0]);
struct phy_link *plink = phy_link_by_num(phy_nr);
struct octphy_hdl *fl1h;
int i;
if (!trx) {
vty_out(vty, "Cannot find TRX number %u%s",
trx_nr, VTY_NEWLINE);
if (!plink) {
vty_out(vty, "Cannot find PHY number %u%s",
phy_nr, VTY_NEWLINE);
return CMD_WARNING;
}
fl1h = trx_octphy_hdl(trx);
fl1h = plink->u.octphy.hdl;
vty_out(vty, "System Platform: '%s', Version: '%s'%s",
fl1h->info.system.platform, fl1h->info.system.version,
@ -210,15 +251,14 @@ int bts_model_vty_init(struct gsm_bts *bts)
{
vty_bts = bts;
install_element(BTS_NODE, &cfg_bts_phy_hwaddr_cmd);
install_element(BTS_NODE, &cfg_bts_phy_netdev_cmd);
install_element(PHY_NODE, &cfg_phy_hwaddr_cmd);
install_element(PHY_NODE, &cfg_phy_netdev_cmd);
install_element(PHY_NODE, &cfg_phy_rf_port_idx_cmd);
install_element(PHY_NODE, &cfg_phy_rx_gain_db_cmd);
install_element(PHY_NODE, &cfg_phy_tx_atten_db_cmd);
install_element(TRX_NODE, &cfg_trx_rf_port_idx_cmd);
install_element(TRX_NODE, &cfg_trx_rx_gain_db_cmd);
install_element(TRX_NODE, &cfg_trx_tx_atten_db_cmd);
install_element_ve(&get_rf_port_stats_cmd);
install_element_ve(&get_clk_sync_stats_cmd);
install_element_ve(&show_rf_port_stats_cmd);
install_element_ve(&show_clk_sync_stats_cmd);
install_element_ve(&show_sys_info_cmd);
return 0;
@ -226,13 +266,5 @@ int bts_model_vty_init(struct gsm_bts *bts)
int bts_model_ctrl_cmds_install(struct gsm_bts *bts)
{
/* FIXME: really ugly hack: We can only initialize the L1 intrface
* after reading the config file, and this is the only call-back after
* vty_read_config_fioe() at this point. Will be cleaned up with the
* phy interface generalization patches coming up soon as part of the
* multi-trx work */
struct octphy_hdl *fl1h = bts->c0->role_bts.l1h;
l1if_open(fl1h);
return 0;
}

View File

@ -59,7 +59,7 @@ static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = {
* create/destroy trx l1 instance
*/
struct trx_l1h *l1if_open(struct gsm_bts_trx *trx)
struct trx_l1h *l1if_open(struct phy_instance *pinst)
{
struct trx_l1h *l1h;
int rc;
@ -67,11 +67,9 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx)
l1h = talloc_zero(tall_bts_ctx, struct trx_l1h);
if (!l1h)
return NULL;
l1h->trx = trx;
l1h->l1s.trx = trx;
trx->role_bts.l1h = l1h;
l1h->phy_inst = pinst;
trx_sched_init(&l1h->l1s);
trx_sched_init(&l1h->l1s, pinst->trx);
rc = trx_if_open(l1h);
if (rc < 0) {
@ -83,7 +81,6 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx)
err:
l1if_close(l1h);
trx->role_bts.l1h = NULL;
return NULL;
}
@ -100,7 +97,8 @@ void l1if_reset(struct trx_l1h *l1h)
static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail)
{
struct gsm_bts_trx *trx = l1h->trx;
struct phy_instance *pinst = l1h->phy_inst;
struct gsm_bts_trx *trx = pinst->trx;
uint8_t tn;
/* HACK, we should change state when we receive first clock from
@ -132,10 +130,10 @@ static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail)
int check_transceiver_availability(struct gsm_bts *bts, int avail)
{
struct gsm_bts_trx *trx;
struct trx_l1h *l1h;
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
check_transceiver_availability_trx(l1h, avail);
}
return 0;
@ -147,6 +145,7 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail)
*/
int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
{
struct phy_link *plink = l1h->phy_inst->phy_link;
uint8_t tn;
if (!transceiver_available)
@ -177,18 +176,23 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
}
/* after power on */
if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) {
trx_if_cmd_setrxgain(l1h, l1h->config.rxgain);
l1h->config.rxgain_sent = 1;
}
if (l1h->config.power_valid && !l1h->config.power_sent) {
trx_if_cmd_setpower(l1h, l1h->config.power);
l1h->config.power_sent = 1;
if (l1h->phy_inst->num == 0) {
if (plink->u.osmotrx.rxgain_valid &&
!plink->u.osmotrx.rxgain_sent) {
trx_if_cmd_setrxgain(l1h, plink->u.osmotrx.rxgain);
plink->u.osmotrx.rxgain_sent = 1;
}
if (plink->u.osmotrx.power_valid &&
!plink->u.osmotrx.power_sent) {
trx_if_cmd_setpower(l1h, plink->u.osmotrx.power);
plink->u.osmotrx.power_sent = 1;
}
}
if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) {
trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly);
l1h->config.maxdly_sent = 1;
}
for (tn = 0; tn < TRX_NR_TS; tn++) {
if (l1h->config.slottype_valid[tn]
&& !l1h->config.slottype_sent[tn]) {
@ -203,8 +207,10 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
if (!l1h->config.poweron && !l1h->config.poweron_sent) {
trx_if_cmd_poweroff(l1h);
l1h->config.poweron_sent = 1;
l1h->config.rxgain_sent = 0;
l1h->config.power_sent = 0;
if (l1h->phy_inst->num == 0) {
plink->u.osmotrx.rxgain_sent = 0;
plink->u.osmotrx.power_sent = 0;
}
l1h->config.maxdly_sent = 0;
for (tn = 0; tn < TRX_NR_TS; tn++)
l1h->config.slottype_sent[tn] = 0;
@ -216,17 +222,20 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
int l1if_provision_transceiver(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct trx_l1h *l1h;
uint8_t tn;
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct phy_link *plink = pinst->phy_link;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
l1h->config.arfcn_sent = 0;
l1h->config.tsc_sent = 0;
l1h->config.bsic_sent = 0;
l1h->config.poweron_sent = 0;
l1h->config.rxgain_sent = 0;
l1h->config.power_sent = 0;
if (l1h->phy_inst->num == 0) {
plink->u.osmotrx.rxgain_sent = 0;
plink->u.osmotrx.power_sent = 0;
}
l1h->config.maxdly_sent = 0;
for (tn = 0; tn < TRX_NR_TS; tn++)
l1h->config.slottype_sent[tn] = 0;
@ -242,7 +251,8 @@ int l1if_provision_transceiver(struct gsm_bts *bts)
/* initialize the layer1 */
static int trx_init(struct gsm_bts_trx *trx)
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
/* power on transceiver, if not already */
if (!l1h->config.poweron) {
@ -264,7 +274,8 @@ static int trx_init(struct gsm_bts_trx *trx)
/* deactivate transceiver */
int bts_model_trx_close(struct gsm_bts_trx *trx)
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
enum gsm_phys_chan_config pchan = trx->ts[0].pchan;
/* close all logical channels and reset timeslots */
@ -308,7 +319,6 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr)
{
struct gsm_bts_trx *trx;
struct trx_l1h *l1h;
uint8_t bsic = bts->bsic;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
@ -318,7 +328,8 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr)
}
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) {
l1h->config.bsic = bsic;
l1h->config.bsic_valid = 1;
@ -335,7 +346,9 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr)
/* set trx attributes */
static uint8_t trx_set_trx(struct gsm_bts_trx *trx)
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct phy_link *plink = pinst->phy_link;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
uint16_t arfcn = trx->arfcn;
if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) {
@ -345,10 +358,10 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx)
l1if_provision_transceiver_trx(l1h);
}
if (l1h->config.power_oml) {
l1h->config.power = trx->max_power_red;
l1h->config.power_valid = 1;
l1h->config.power_sent = 0;
if (plink->u.osmotrx.power_oml && pinst->num == 0) {
plink->u.osmotrx.power = trx->max_power_red;
plink->u.osmotrx.power_valid = 1;
plink->u.osmotrx.power_sent = 0;
l1if_provision_transceiver_trx(l1h);
}
@ -358,7 +371,8 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx)
/* set ts attributes */
static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts)
{
struct trx_l1h *l1h = trx_l1h_hdl(ts->trx);
struct phy_instance *pinst = trx_phy_instance(ts->trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
uint8_t tn = ts->nr;
uint16_t tsc = ts->tsc;
enum gsm_phys_chan_config pchan = ts->pchan;
@ -439,6 +453,7 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan,
static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr,
enum osmo_mph_info_type type, uint8_t cause)
{
struct phy_instance *pinst = l1h->phy_inst;
struct osmo_phsap_prim l1sap;
memset(&l1sap, 0, sizeof(l1sap));
@ -448,7 +463,7 @@ static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr,
l1sap.u.info.u.act_cnf.chan_nr = chan_nr;
l1sap.u.info.u.act_cnf.cause = cause;
return l1sap_up(l1h->trx, &l1sap);
return l1sap_up(pinst->trx, &l1sap);
}
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
@ -503,7 +518,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint
/* primitive from common part */
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
struct msgb *msg = l1sap->oph.msg;
uint8_t chan_nr;
uint8_t tn, ss;

View File

@ -2,6 +2,7 @@
#define L1_IF_H_TRX
#include <osmo-bts/scheduler.h>
#include <osmo-bts/phy_link.h>
struct trx_config {
uint8_t poweron; /* poweron(1) or poweroff(0) */
@ -19,15 +20,6 @@ struct trx_config {
uint8_t bsic;
int bsic_sent;
int rxgain_valid;
int rxgain;
int rxgain_sent;
int power_valid;
int power;
int power_oml;
int power_sent;
int maxdly_valid;
int maxdly;
int maxdly_sent;
@ -42,7 +34,8 @@ struct trx_config {
struct trx_l1h {
struct llist_head trx_ctrl_list;
struct gsm_bts_trx *trx;
//struct gsm_bts_trx *trx;
struct phy_instance *phy_inst;
struct osmo_fd trx_ofd_ctrl;
struct osmo_timer_list trx_ctrl_timer;
@ -55,7 +48,7 @@ struct trx_l1h {
struct l1sched_trx l1s;
};
struct trx_l1h *l1if_open(struct gsm_bts_trx *trx);
struct trx_l1h *l1if_open(struct phy_instance *pinst);
void l1if_close(struct trx_l1h *l1h);
void l1if_reset(struct trx_l1h *l1h);
int check_transceiver_availability(struct gsm_bts *bts, int avail);
@ -69,7 +62,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint
static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx->role_bts.l1h;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
return &l1h->l1s;
}

View File

@ -45,6 +45,7 @@
#include <osmocom/core/bits.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
@ -58,43 +59,6 @@
#include "l1_if.h"
#include "trx_if.h"
int bts_model_init(struct gsm_bts *bts)
{
void *l1h;
struct gsm_bts_trx *trx;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2);
if (!settsc_enabled && !setbsic_enabled)
settsc_enabled = setbsic_enabled = 1;
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = l1if_open(trx);
if (!l1h) {
LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n");
goto error;
}
trx->role_bts.l1h = l1h;
trx->nominal_power = 23;
l1if_reset(l1h);
}
bts_model_vty_init(bts);
return 0;
error:
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = trx->role_bts.l1h;
if (l1h)
l1if_close(l1h);
}
return -EIO;
}
/* dummy, since no direct dsp support */
uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
{
@ -103,10 +67,6 @@ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
void bts_model_print_help()
{
printf(
" -I --local-trx-ip Local IP for transceiver to connect (default=%s)\n"
, transceiver_ip
);
}
int bts_model_handle_options(int argc, char **argv)
@ -116,21 +76,16 @@ int bts_model_handle_options(int argc, char **argv)
while (1) {
int option_idx = 0, c;
static const struct option long_options[] = {
/* specific to this hardware */
{ "local-trx-ip", 1, 0, 'I' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "I:",
c = getopt_long(argc, argv, "",
long_options, &option_idx);
if (c == -1)
break;
switch (c) {
case 'I':
transceiver_ip = strdup(optarg);
break;
default:
num_errors++;
break;
@ -140,6 +95,35 @@ int bts_model_handle_options(int argc, char **argv)
return num_errors;
}
int bts_model_init(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2);
/* FIXME: this needs to be overridden with the real hardrware
* value */
bts->c0->nominal_power = 23;
bts_model_vty_init(bts);
return 0;
}
void bts_model_phy_link_set_defaults(struct phy_link *plink)
{
plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, "127.0.0.1");
plink->u.osmotrx.base_port_local = 5800;
plink->u.osmotrx.base_port_remote = 5700;
plink->u.osmotrx.clock_advance = 20;
plink->u.osmotrx.rts_advance = 5;
plink->u.osmotrx.power_oml = 1;
}
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
{
}
int main(int argc, char **argv)
{
return bts_main(argc, argv);

View File

@ -55,12 +55,6 @@ uint32_t transceiver_last_fn;
static struct timeval transceiver_clock_tv;
static struct osmo_timer_list transceiver_clock_timer;
/* clock advance for the transceiver */
uint32_t trx_clock_advance = 20;
/* advance RTS to give some time for data processing. (especially PCU) */
uint32_t trx_rts_advance = 5; /* about 20ms */
/* Enable this to multiply TOA of RACH by 10.
* This is usefull to check tenth of timing advances with RSSI test tool.
* Note that regular phones will not work when using this test! */
@ -1262,14 +1256,16 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
/* send time indication */
l1if_mph_time_ind(bts, fn);
/* advance frame number, so the transceiver has more time until
* it must be transmitted. */
fn = (fn + trx_clock_advance) % GSM_HYPERFRAME;
/* process every TRX */
llist_for_each_entry(trx, &bts->trx_list, list) {
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct l1sched_trx *l1t = trx_l1sched_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
struct phy_link *plink = pinst->phy_link;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
struct l1sched_trx *l1t = &l1h->l1s;
/* advance frame number, so the transceiver has more
* time until it must be transmitted. */
fn = (fn + plink->u.osmotrx.clock_advance) % GSM_HYPERFRAME;
/* we don't schedule, if power is off */
if (!trx_if_powered(l1h))
@ -1279,7 +1275,7 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
/* ready-to-send */
_sched_rts(l1t, tn,
(fn + trx_rts_advance) % GSM_HYPERFRAME);
(fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME);
/* get burst for FN */
bits = _sched_dl_burst(l1t, tn, fn);
if (!bits) {
@ -1323,10 +1319,12 @@ no_clock:
/* flush pending messages of transceiver */
/* close all logical channels and reset timeslots */
llist_for_each_entry(trx, &bts->trx_list, list) {
trx_if_flush(trx_l1h_hdl(trx));
trx_sched_reset(trx_l1sched_hdl(trx));
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
trx_if_flush(l1h);
trx_sched_reset(&l1h->l1s);
if (trx->nr == 0)
trx_if_cmd_poweroff(trx_l1h_hdl(trx));
trx_if_cmd_poweroff(l1h);
}
/* tell BSC */
@ -1461,7 +1459,8 @@ new_clock:
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
{
struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx);
struct phy_instance *pinst = trx_phy_instance(l1t->trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (activate)
trx_if_cmd_handover(l1h, tn, ss);

View File

@ -2,6 +2,7 @@
* OpenBTS TRX interface handling
*
* Copyright (C) 2013 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2016 Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@ -34,6 +35,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/scheduler.h>
@ -45,7 +47,6 @@
//#define TOA_RSSI_DEBUG
int transceiver_available = 0;
const char *transceiver_ip = "127.0.0.1";
int settsc_enabled = 0;
int setbsic_enabled = 0;
@ -53,11 +54,10 @@ int setbsic_enabled = 0;
* socket
*/
static uint16_t base_port_local = 5800;
/* open socket */
static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port,
int (*cb)(struct osmo_fd *fd, unsigned int what))
static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host,
uint16_t port_local, uint16_t port_remote,
int (*cb)(struct osmo_fd *fd, unsigned int what))
{
struct sockaddr_storage sas;
struct sockaddr *sa = (struct sockaddr *)&sas;
@ -71,8 +71,8 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port,
ofd->data = priv;
/* Listen / Binds */
rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, transceiver_ip,
port, OSMO_SOCK_F_BIND);
rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, host,
port_local, OSMO_SOCK_F_BIND);
if (rc < 0)
return rc;
@ -84,10 +84,10 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port,
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_port = htons(ntohs(sin->sin_port) - 100);
sin->sin_port = htons(port_remote);
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
sin6->sin6_port = htons(ntohs(sin6->sin6_port) - 100);
sin6->sin6_port = htons(port_remote);
} else {
return -EINVAL;
}
@ -96,7 +96,6 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port,
if (rc)
return rc;
return 0;
}
@ -115,13 +114,11 @@ static void trx_udp_close(struct osmo_fd *ofd)
* clock
*/
static struct osmo_fd trx_ofd_clk;
/* get clock from clock socket */
static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct trx_l1h *l1h = ofd->data;
struct phy_link *plink = ofd->data;
struct phy_instance *pinst = phy_instance_by_num(plink, 0);
char buf[1500];
int len;
uint32_t fn;
@ -146,7 +143,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
"correctly, correcting to fn=%u\n", fn);
}
trx_sched_clock(l1h->trx->bts, fn);
trx_sched_clock(pinst->trx->bts, fn);
return 0;
}
@ -168,8 +165,8 @@ static void trx_ctrl_send(struct trx_l1h *l1h)
return;
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list);
LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd,
l1h->trx->nr);
LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to %s\n", tcm->cmd,
phy_instance_name(l1h->phy_inst));
/* send command */
send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0);
@ -184,8 +181,8 @@ static void trx_ctrl_timer_cb(void *data)
{
struct trx_l1h *l1h = data;
LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n",
l1h->trx->nr);
LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for %s\n",
phy_instance_name(l1h->phy_inst));
trx_ctrl_send(l1h);
}
@ -232,7 +229,8 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd,
int trx_if_cmd_poweroff(struct trx_l1h *l1h)
{
if (l1h->trx->nr == 0)
struct phy_instance *pinst = l1h->phy_inst;
if (pinst->num == 0)
return trx_ctrl_cmd(l1h, 1, "POWEROFF", "");
else
return 0;
@ -240,7 +238,8 @@ int trx_if_cmd_poweroff(struct trx_l1h *l1h)
int trx_if_cmd_poweron(struct trx_l1h *l1h)
{
if (l1h->trx->nr == 0)
struct phy_instance *pinst = l1h->phy_inst;
if (pinst->num == 0)
return trx_ctrl_cmd(l1h, 1, "POWERON", "");
else
return 0;
@ -324,6 +323,7 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss)
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct trx_l1h *l1h = ofd->data;
struct phy_instance *pinst = l1h->phy_inst;
char buf[1500];
int len, resp;
@ -374,11 +374,12 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
sscanf(p + 1, "%d", &resp);
if (resp) {
LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
"transceiver (trx=%d) rejected TRX command "
"with response: '%s'\n", l1h->trx->nr, buf);
"transceiver (%s) rejected TRX command "
"with response: '%s'\n",
phy_instance_name(pinst), buf);
rsp_error:
if (tcm->critical) {
bts_shutdown(l1h->trx->bts, "SIGINT");
bts_shutdown(pinst->trx->bts, "SIGINT");
/* keep tcm list, so process is stopped */
return -EIO;
}
@ -493,37 +494,91 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
* open/close
*/
int trx_if_open(struct trx_l1h *l1h)
int bts_model_phy_link_open(struct phy_link *plink)
{
struct phy_instance *pinst;
int rc;
LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr);
phy_link_state_set(plink, PHY_LINK_CONNECTING);
/* open the shared/common clock socket */
rc = trx_udp_open(plink, &plink->u.osmotrx.trx_ofd_clk,
plink->u.osmotrx.transceiver_ip,
plink->u.osmotrx.base_port_local,
plink->u.osmotrx.base_port_remote,
trx_clk_read_cb);
if (rc < 0) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1;
}
/* open the individual instances with their ctrl+data sockets */
llist_for_each_entry(pinst, &plink->instances, list) {
pinst->u.osmotrx.hdl = l1if_open(pinst);
if (!pinst->u.osmotrx.hdl)
goto cleanup;
}
return 0;
cleanup:
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
llist_for_each_entry(pinst, &plink->instances, list) {
if (pinst->u.osmotrx.hdl) {
trx_if_close(pinst->u.osmotrx.hdl);
pinst->u.osmotrx.hdl = NULL;
}
}
trx_udp_close(&plink->u.osmotrx.trx_ofd_clk);
return -1;
}
static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data)
{
struct phy_link *plink = pinst->phy_link;
uint16_t inc = 1;
if (is_data)
inc = 2;
if (remote)
return plink->u.osmotrx.base_port_remote + (pinst->num << 1) + inc;
else
return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc;
}
int trx_if_open(struct trx_l1h *l1h)
{
struct phy_instance *pinst = l1h->phy_inst;
struct phy_link *plink = pinst->phy_link;
int rc;
LOGP(DTRX, LOGL_NOTICE, "Open transceiver for %s\n",
phy_instance_name(pinst));
/* initialize ctrl queue */
INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
/* open sockets */
if (l1h->trx->nr == 0) {
rc = trx_udp_open(l1h, &trx_ofd_clk, base_port_local,
trx_clk_read_cb);
if (rc < 0)
return rc;
LOGP(DTRX, LOGL_NOTICE, "Waiting for transceiver send clock\n");
}
rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl,
base_port_local + (l1h->trx->nr << 1) + 1, trx_ctrl_read_cb);
plink->u.osmotrx.transceiver_ip,
compute_port(pinst, 0, 0),
compute_port(pinst, 1, 0), trx_ctrl_read_cb);
if (rc < 0)
goto err;
rc = trx_udp_open(l1h, &l1h->trx_ofd_data,
base_port_local + (l1h->trx->nr << 1) + 2, trx_data_read_cb);
plink->u.osmotrx.transceiver_ip,
compute_port(pinst, 0, 1),
compute_port(pinst, 1, 1), trx_data_read_cb);
if (rc < 0)
goto err;
/* enable all slots */
l1h->config.slotmask = 0xff;
if (l1h->trx->nr == 0)
trx_if_cmd_poweroff(l1h);
/* FIXME: why was this only for TRX0 ? */
//if (l1h->trx->nr == 0)
trx_if_cmd_poweroff(l1h);
return 0;
@ -548,13 +603,13 @@ void trx_if_flush(struct trx_l1h *l1h)
void trx_if_close(struct trx_l1h *l1h)
{
LOGP(DTRX, LOGL_NOTICE, "Close transceiver for trx=%u\n", l1h->trx->nr);
struct phy_instance *pinst = l1h->phy_inst;
LOGP(DTRX, LOGL_NOTICE, "Close transceiver for %s\n",
phy_instance_name(pinst));
trx_if_flush(l1h);
/* close sockets */
if (l1h->trx->nr == 0)
trx_udp_close(&trx_ofd_clk);
trx_udp_close(&l1h->trx_ofd_ctrl);
trx_udp_close(&l1h->trx_ofd_data);
}

View File

@ -6,6 +6,7 @@ extern const char *transceiver_ip;
extern int settsc_enabled;
extern int setbsic_enabled;
struct trx_l1h;
struct trx_ctrl_msg {
struct llist_head list;

View File

@ -45,6 +45,8 @@
#include "trx_if.h"
#include "loops.h"
#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n"
static struct gsm_bts *vty_bts;
DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
@ -53,7 +55,6 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
struct gsm_bts *bts = vty_bts;
struct gsm_bts_trx *trx;
struct trx_l1h *l1h;
uint8_t tn;
if (!transceiver_available) {
vty_out(vty, "transceiver is not connected%s", VTY_NEWLINE);
@ -63,7 +64,8 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
}
llist_for_each_entry(trx, &bts->trx_list, list) {
l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = trx_phy_instance(trx);
l1h = pinst->u.osmotrx.hdl;
vty_out(vty, "TRX %d%s", trx->nr, VTY_NEWLINE);
vty_out(vty, " %s%s",
(l1h->config.poweron) ? "poweron":"poweroff",
@ -85,56 +87,70 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
VTY_NEWLINE);
else
vty_out(vty, " bisc : undefined%s", VTY_NEWLINE);
if (l1h->config.rxgain_valid)
vty_out(vty, " rxgain : %d%s", l1h->config.rxgain,
VTY_NEWLINE);
else
vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE);
if (l1h->config.power_valid)
vty_out(vty, " power : %d%s", l1h->config.power,
VTY_NEWLINE);
else
vty_out(vty, " power : undefined%s", VTY_NEWLINE);
if (l1h->config.maxdly_valid)
vty_out(vty, " maxdly : %d%s", l1h->config.maxdly,
VTY_NEWLINE);
else
vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE);
for (tn = 0; tn < TRX_NR_TS; tn++) {
if (!((1 << tn) & l1h->config.slotmask))
vty_out(vty, " slot #%d: unsupported%s", tn,
VTY_NEWLINE);
else if (l1h->config.slottype_valid[tn])
vty_out(vty, " slot #%d: type %d%s", tn,
l1h->config.slottype[tn],
VTY_NEWLINE);
else
vty_out(vty, " slot #%d: undefined%s", tn,
VTY_NEWLINE);
}
}
return CMD_SUCCESS;
}
DEFUN(cfg_bts_fn_advance, cfg_bts_fn_advance_cmd,
"fn-advance <0-30>",
"Set the number of frames to be transmitted to transceiver in advance "
"of current FN\n"
"Advance in frames\n")
{
trx_clock_advance = atoi(argv[0]);
return CMD_SUCCESS;
static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst)
{
uint8_t tn;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
vty_out(vty, "PHY Instance %s%s",
phy_instance_name(pinst), VTY_NEWLINE);
if (l1h->config.maxdly_valid)
vty_out(vty, " maxdly : %d%s", l1h->config.maxdly,
VTY_NEWLINE);
else
vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE);
for (tn = 0; tn < TRX_NR_TS; tn++) {
if (!((1 << tn) & l1h->config.slotmask))
vty_out(vty, " slot #%d: unsupported%s", tn,
VTY_NEWLINE);
else if (l1h->config.slottype_valid[tn])
vty_out(vty, " slot #%d: type %d%s", tn,
l1h->config.slottype[tn],
VTY_NEWLINE);
else
vty_out(vty, " slot #%d: undefined%s", tn,
VTY_NEWLINE);
}
}
DEFUN(cfg_bts_rts_advance, cfg_bts_rts_advance_cmd,
"rts-advance <0-30>",
"Set the number of frames to be requested (PCU) in advance of current "
"FN. Do not change this, unless you have a good reason!\n"
"Advance in frames\n")
static void show_phy_single(struct vty *vty, struct phy_link *plink)
{
trx_rts_advance = atoi(argv[0]);
struct phy_instance *pinst;
vty_out(vty, "PHY %u%s", plink->num, VTY_NEWLINE);
if (plink->u.osmotrx.rxgain_valid)
vty_out(vty, " rx-gain : %d dB%s",
plink->u.osmotrx.rxgain, VTY_NEWLINE);
else
vty_out(vty, " rx-gain : undefined%s", VTY_NEWLINE);
if (plink->u.osmotrx.power_valid)
vty_out(vty, " tx-attenuation : %d dB%s",
plink->u.osmotrx.power, VTY_NEWLINE);
else
vty_out(vty, " tx-attenuation : undefined%s", VTY_NEWLINE);
llist_for_each_entry(pinst, &plink->instances, list)
show_phy_inst_single(vty, pinst);
}
DEFUN(show_phy, show_phy_cmd, "show phy",
SHOW_STR "Display information about the available PHYs")
{
int i;
for (i = 0; i < 255; i++) {
struct phy_link *plink = phy_link_by_num(i);
if (!plink)
break;
show_phy_single(vty, plink);
}
return CMD_SUCCESS;
}
@ -220,63 +236,14 @@ DEFUN(cfg_bts_no_setbsic, cfg_bts_no_setbsic_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_rxgain, cfg_trx_rxgain_cmd,
"rxgain <0-50>",
"Set the receiver gain in dB\n"
"Gain in dB\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
l1h->config.rxgain = atoi(argv[0]);
l1h->config.rxgain_valid = 1;
l1h->config.rxgain_sent = 0;
l1if_provision_transceiver_trx(l1h);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_power, cfg_trx_power_cmd,
"power <0-50>",
"Set the transmitter power dampening\n"
"Power dampening in dB\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
l1h->config.power = atoi(argv[0]);
l1h->config.power_oml = 0;
l1h->config.power_valid = 1;
l1h->config.power_sent = 0;
l1if_provision_transceiver_trx(l1h);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_poweroml_, cfg_trx_power_oml_cmd,
"power oml",
"Set the transmitter power dampening\n"
"Given by NM_ATT_RF_MAXPOWR_R (max power reduction) via OML\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
l1h->config.power = trx->max_power_red;
l1h->config.power_oml = 1;
l1h->config.power_valid = 1;
l1h->config.power_sent = 0;
l1if_provision_transceiver_trx(l1h);
return CMD_SUCCESS;
}
DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd,
"maxdly <0-31>",
DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd,
"osmotrx maxdly <0-31>",
"Set the maximum delay of GSM symbols\n"
"GSM symbols (approx. 1.1km per symbol)\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
l1h->config.maxdly = atoi(argv[0]);
l1h->config.maxdly_valid = 1;
@ -286,7 +253,7 @@ DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd,
DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd,
"slotmask (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0)",
"Set the supported slots\n"
"TS0 supported\nTS0 unsupported\nTS1 supported\nTS1 unsupported\n"
@ -294,8 +261,8 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd,
"TS4 supported\nTS4 unsupported\nTS5 supported\nTS5 unsupported\n"
"TS6 supported\nTS6 unsupported\nTS7 supported\nTS7 unsupported\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
uint8_t tn;
l1h->config.slotmask = 0;
@ -306,76 +273,171 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_no_rxgain, cfg_trx_no_rxgain_cmd,
"no rxgain <0-50>",
NO_STR "Unset the receiver gain in dB\n"
DEFUN(cfg_phy_fn_advance, cfg_phy_fn_advance_cmd,
"osmotrx fn-advance <0-30>",
OSMOTRX_STR
"Set the number of frames to be transmitted to transceiver in advance "
"of current FN\n"
"Advance in frames\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.clock_advance = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_phy_rts_advance, cfg_phy_rts_advance_cmd,
"osmotrx rts-advance <0-30>",
OSMOTRX_STR
"Set the number of frames to be requested (PCU) in advance of current "
"FN. Do not change this, unless you have a good reason!\n"
"Advance in frames\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.rts_advance = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_phy_rxgain, cfg_phy_rxgain_cmd,
"osmotrx rx-gain <0-50>",
OSMOTRX_STR
"Set the receiver gain in dB\n"
"Gain in dB\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_link *plink = vty->index;
l1h->config.rxgain_valid = 0;
plink->u.osmotrx.rxgain = atoi(argv[0]);
plink->u.osmotrx.rxgain_valid = 1;
plink->u.osmotrx.rxgain_sent = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_trx_no_power, cfg_trx_no_power_cmd,
"no power <0-50>",
NO_STR "Unset the transmitter power dampening\n"
"Power dampening in dB\n")
DEFUN(cfg_phy_tx_atten, cfg_phy_tx_atten_cmd,
"osmotrx tx-attenuation <0-50>",
OSMOTRX_STR
"Set the transmitter attenuation\n"
"Fixed attenuation in dB, overriding OML\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_link *plink = vty->index;
l1h->config.power_valid = 0;
plink->u.osmotrx.power = atoi(argv[0]);
plink->u.osmotrx.power_oml = 0;
plink->u.osmotrx.power_valid = 1;
plink->u.osmotrx.power_sent = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_trx_no_maxdly, cfg_trx_no_maxdly_cmd,
"no maxdly <0-31>",
NO_STR "Unset the maximum delay of GSM symbols\n"
"GSM symbols (approx. 1.1km per symbol)\n")
DEFUN(cfg_phy_tx_atten_oml, cfg_phy_tx_atten_oml_cmd,
"osmotrx tx-attenuation oml",
OSMOTRX_STR
"Set the transmitter attenuation\n"
"Use NM_ATT_RF_MAXPOWR_R (max power reduction) from BSC via OML\n")
{
struct gsm_bts_trx *trx = vty->index;
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_link *plink = vty->index;
plink->u.osmotrx.power_oml = 1;
plink->u.osmotrx.power_valid = 1;
plink->u.osmotrx.power_sent = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_phy_no_rxgain, cfg_phy_no_rxgain_cmd,
"no osmotrx rx-gain",
NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.rxgain_valid = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_phy_no_tx_atten, cfg_phy_no_tx_atten_cmd,
"no osmotrx tx-attenuation",
NO_STR OSMOTRX_STR "Unset the transmitter attenuation\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.power_valid = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd,
"no osmotrx maxdly",
NO_STR "Unset the maximum delay of GSM symbols\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
l1h->config.maxdly_valid = 0;
return CMD_SUCCESS;
}
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
DEFUN(cfg_phy_transc_ip, cfg_phy_transc_ip_cmd,
"osmotrx ip HOST",
OSMOTRX_STR
"Set remote IP address\n"
"IP address of OsmoTRX\n")
{
vty_out(vty, " fn-advance %d%s", trx_clock_advance, VTY_NEWLINE);
vty_out(vty, " rts-advance %d%s", trx_rts_advance, VTY_NEWLINE);
struct phy_link *plink = vty->index;
if (trx_ms_power_loop)
vty_out(vty, " ms-power-loop %d%s", trx_target_rssi,
VTY_NEWLINE);
else
vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE);
vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ",
VTY_NEWLINE);
if (settsc_enabled)
vty_out(vty, " settsc%s", VTY_NEWLINE);
if (setbsic_enabled)
vty_out(vty, " setbsic%s", VTY_NEWLINE);
if (plink->u.osmotrx.transceiver_ip)
talloc_free(plink->u.osmotrx.transceiver_ip);
plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, argv[0]);
return CMD_SUCCESS;
}
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd,
"osmotrx base-port (local|remote) <0-65535>",
OSMOTRX_STR "Set base UDP port number\n" "Local UDP port\n"
"Remote UDP port\n" "UDP base port number\n")
{
struct trx_l1h *l1h = trx_l1h_hdl(trx);
struct phy_link *plink = vty->index;
if (l1h->config.rxgain_valid)
vty_out(vty, " rxgain %d%s", l1h->config.rxgain, VTY_NEWLINE);
if (l1h->config.power_valid) {
if (l1h->config.power_oml)
vty_out(vty, " power oml%s", VTY_NEWLINE);
if (!strcmp(argv[0], "local"))
plink->u.osmotrx.base_port_local = atoi(argv[1]);
else
plink->u.osmotrx.base_port_remote = atoi(argv[1]);
return CMD_SUCCESS;
}
void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
{
if (plink->u.osmotrx.transceiver_ip)
vty_out(vty, " osmotrx ip %s%s",
plink->u.osmotrx.transceiver_ip, VTY_NEWLINE);
vty_out(vty, " osmotrx fn-advance %d%s",
plink->u.osmotrx.clock_advance, VTY_NEWLINE);
vty_out(vty, " osmotrx rts-advance %d%s",
plink->u.osmotrx.rts_advance, VTY_NEWLINE);
if (plink->u.osmotrx.rxgain_valid)
vty_out(vty, " osmotrx rx-gain %d%s",
plink->u.osmotrx.rxgain, VTY_NEWLINE);
if (plink->u.osmotrx.power_valid) {
if (plink->u.osmotrx.power_oml)
vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE);
else
vty_out(vty, " power %d%s", l1h->config.power,
VTY_NEWLINE);
vty_out(vty, " osmotrx tx-attenuation %d%s",
plink->u.osmotrx.power, VTY_NEWLINE);
}
}
void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
{
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (l1h->config.maxdly_valid)
vty_out(vty, " maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE);
if (l1h->config.slotmask != 0xff)
@ -391,14 +453,32 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
VTY_NEWLINE);
}
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
if (trx_ms_power_loop)
vty_out(vty, " ms-power-loop %d%s", trx_target_rssi,
VTY_NEWLINE);
else
vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE);
vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ",
VTY_NEWLINE);
if (settsc_enabled)
vty_out(vty, " settsc%s", VTY_NEWLINE);
if (setbsic_enabled)
vty_out(vty, " setbsic%s", VTY_NEWLINE);
}
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
{
}
int bts_model_vty_init(struct gsm_bts *bts)
{
vty_bts = bts;
install_element_ve(&show_transceiver_cmd);
install_element_ve(&show_phy_cmd);
install_element(BTS_NODE, &cfg_bts_fn_advance_cmd);
install_element(BTS_NODE, &cfg_bts_rts_advance_cmd);
install_element(BTS_NODE, &cfg_bts_ms_power_loop_cmd);
install_element(BTS_NODE, &cfg_bts_no_ms_power_loop_cmd);
install_element(BTS_NODE, &cfg_bts_timing_advance_loop_cmd);
@ -408,14 +488,19 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(BTS_NODE, &cfg_bts_no_settsc_cmd);
install_element(BTS_NODE, &cfg_bts_no_setbsic_cmd);
install_element(TRX_NODE, &cfg_trx_rxgain_cmd);
install_element(TRX_NODE, &cfg_trx_power_cmd);
install_element(TRX_NODE, &cfg_trx_power_oml_cmd);
install_element(TRX_NODE, &cfg_trx_maxdly_cmd);
install_element(TRX_NODE, &cfg_trx_slotmask_cmd);
install_element(TRX_NODE, &cfg_trx_no_rxgain_cmd);
install_element(TRX_NODE, &cfg_trx_no_power_cmd);
install_element(TRX_NODE, &cfg_trx_no_maxdly_cmd);
install_element(PHY_NODE, &cfg_phy_base_port_cmd);
install_element(PHY_NODE, &cfg_phy_fn_advance_cmd);
install_element(PHY_NODE, &cfg_phy_rts_advance_cmd);
install_element(PHY_NODE, &cfg_phy_transc_ip_cmd);
install_element(PHY_NODE, &cfg_phy_rxgain_cmd);
install_element(PHY_NODE, &cfg_phy_tx_atten_cmd);
install_element(PHY_NODE, &cfg_phy_tx_atten_oml_cmd);
install_element(PHY_NODE, &cfg_phy_no_rxgain_cmd);
install_element(PHY_NODE, &cfg_phy_no_tx_atten_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_slotmask_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdly_cmd);
return 0;
}