OpenBSC
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- 1 participants
- 4322 discussions
Hi folks,
to share a finding: the question was whether 2G and 3G cells may share location
area codes.
A glance at some (mostly anonymized) live data from GSM cell monitoring
hardware, in use by one of our customers, answers that quite clearly:
Network MCC MNC LAC CID Type Band
FirstOperator 123 4 678 C669 GSM GSM900
FirstOperator 123 4 678 CF5A GSM GSM900
FirstOperator 123 4 678 CF2A GSM GSM900
FirstOperator 123 4 678 C695 GSM GSM900
FirstOperator 123 4 678 CF30 GSM GSM900
FirstOperator 123 4 678 CF58 GSM GSM900
FirstOperator 123 4 678 6869 UMTS UMTS2100
FirstOperator 123 4 678 C69B GSM GSM900
SecondOperator 123 5 9AB DEEF GSM DCS1800
SecondOperator 123 5 9AB E15D UMTS UMTS2100
SecondOperator 123 5 9AB E163 UMTS UMTS2100
SecondOperator 123 5 9AB E080 GSM DCS1800
LACs are shared across 2G ("GSM" here) and 3G ("UMTS") technologies, only the
cell IDs are guaranteed to differ.
Happy hacking,
~Neels
--
- Neels Hofmeyr <nhofmeyr(a)sysmocom.de> http://www.sysmocom.de/
=======================================================================
* sysmocom - systems for mobile communications GmbH
* Alt-Moabit 93
* 10559 Berlin, Germany
* Sitz / Registered office: Berlin, HRB 134158 B
* Geschäftsführer / Managing Directors: Holger Freyther, Harald Welte
1
0
Hi all,
this is diverting a mail dialog that started off privately to this list,
for the benefit of everyone.
You may have noticed that Daniel is working on IuPS (3G/UMTS data conns)
and I'm working on the OsmoCSCN, which is going to handle IuCS (3G/UMTS
voice calls).
There was still some puzzlement around connection IDs and how to reach a
mobile device (aka UE). In particular, which ID or information do I store
to identify the link to a UE, and how do I find a UE in case of paging?
First off, we're so far implementing a special case where we're using a
HNB-GW to demultiplex voice and data (IuCS and IuPS) from an hNodeB
(femto-cell). ASCII art to illustrate, view in a monospaced font:
UE 1 <--> |hNodeB 1| <-->|HNB-GW| <---> |CSCN or SGSN
| 1 | |
UE 2 <--> |hNodeB 2| <-->| | |
UE 3 <--> | | | |
|
|
UE 4 <--> |hNodeB 3| <-->|HNB-GW| <---> |
| 2 | |
UE 5 <--> |hNodeB 4| <-->| | |
UE 6 <--> | | | |
So, how does a CSCN know where to send a message for a given UE, and how
does it reach that UE?
Turns out the picture is more like this:
. . . (hNodeB) . . . (HNB-GW)
UE1 <--> | Cell <--1--> [RNC] <------------> [CSCN]
UE2 <--> |
Meaning that the hNodeB actually encloses an RNC (Radio Network
Controller) and a single radio cell. The HNB-GW does pretty much
"invisible" forwarding of the SCCP|SUA connection to the RNC. Each RNC has
a global RNC ID, and can manage N radio cells. In the hNodeB case, there
is exactly one cell behind the RNC, but the general case looks like this:
UE1 <--> | Cell <-----> |RNC1 <------------> |CSCN
UE2 <--> | | |
| |
UE3 <--> | Cell <-----> | |
|
|
UE4 <--> | Cell <-----> |RNC2 <------------> |
UE5 <--> | | |
| |
UE6 <--> | Cell <-----> | |
When a UE calls, the CSCN receives a User SAP link with a conn_id, and
simply routes the reply back to this link and conn_id. The reply goes
right back to the RNC, and the RNC knows which cell the UE is at.
The case where the CN contacts a UE is known as paging, i.e. the request
by the CN that the UE shall please establish a connection to the CN. The
CSCN may encounter different cases here: a User SAP link may have been
established and is still present, or no link is available (e.g. a link has
existed before but has been torn down due to a Reset by the RNC, etc.).
If the link is still valid, this manifests as: the struct
gsm_subscriber_connection still has a valid pointer to an osmo_sua_link,
and iu_tx() feeds the conn_id to this link to reach the UE.
(Note that the gsm_subscriber_connection struct does not yet have an
osmo_sua_link pointer. I will move the ue_conn_ctx into the
gsm_subscriber_connection struct in an upcoming commit.)
If, e.g. due to a Reset, the osmo_sua_link pointer has been cleared, the
CSCN or SGSN will ask the HLR: where has the last location update for this
IMSI been registered? Each RNC can manage several location areas, further
divided into several service areas, and once the HLR has identified the
service area where the UE is expected, the CSCN or SGSN can identify the
RNC by the global RNC ID and send the paging request in that direction.
A bit of pseudo struct code:
struct gsm_network {
llist of struct gsm_subscriber_connection:
{
{
struct gsm_subscriber subscr {
char imsi[GSM_IMSI_LENGTH];
};
struct {
struct osmo_sua_link *link; /* point into an rnc struct */
uint32_t conn_id;
} iu;
},
...
};
llist of struct rnc (does not exist yet) :
{
struct osmo_sua_link *link; /* upon link-down, clear the above */
...
};
};
So, IIUC, the global RNC ID resolved from the HLR info should identify the
path to a particular UE. The CSCN knows which RNC is behind which of its
local link endpoints. In our special case with an HNB-GW and when there
are several hNodeB instances behind the HNB-GW, the HNB-GW knows which way
to send a connection reply by the established SCCP|SUA link, or which way
to send a paging request by the RNC ID. The finer code details here are
not entirely known to me yet, but I hope that the answers will come
naturally or have already been implemented by Daniel ;)
If any questions, answers or comments emerge in your mind while reading
this, please don't hesitate and share!
Thanks,
~Neels
--
- Neels Hofmeyr <nhofmeyr(a)sysmocom.de> http://www.sysmocom.de/
=======================================================================
* sysmocom - systems for mobile communications GmbH
* Alt-Moabit 93
* 10559 Berlin, Germany
* Sitz / Registered office: Berlin, HRB 134158 B
* Geschäftsführer / Managing Directors: Holger Freyther, Harald Welte
1
0
Hi.
There are bunch of functions like osmo_counter_* and osmo_stats_reporter_* in
libosmocore and other projects.
I'm pretty much understand what they do, but what happens on the receiving end?
There's nothing in our wiki regarding statsd.
How do you guys use it? Any statsd config examples? Workflow hints?
With such an elaborate functionality there got to be somebody who actually uses it.
Please share your experience, configs, pretty screenshots and complaints :)
cheers,
Max.
1
0
Would anyone like to prevent this commit from reaching master? ;)
Thanks!
~Neels
commit 76af8ad075e7857983ef102f80440ee716958482
Author: Neels Hofmeyr <nhofmeyr(a)sysmocom.de>
Date: Thu Jan 28 14:26:05 2016 +0100
add fixme comment for todo comment :/
diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c
index b4facff..4bea699 100644
--- a/openbsc/src/libmsc/osmo_msc.c
+++ b/openbsc/src/libmsc/osmo_msc.c
@@ -48,7 +48,7 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
gsm0408_new_conn(conn);
gsm0408_dispatch(conn, msg);
- /* TODO: do better */
+ /* TODO: do better */ /* FIXME: do the TODO comment better in the first place! */
if (conn->silent_call)
return BSC_API_CONN_POL_ACCEPT;
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
--
- Neels Hofmeyr <nhofmeyr(a)sysmocom.de> http://www.sysmocom.de/
=======================================================================
* sysmocom - systems for mobile communications GmbH
* Alt-Moabit 93
* 10559 Berlin, Germany
* Sitz / Registered office: Berlin, HRB 134158 B
* Geschäftsführer / Managing Directors: Holger Freyther, Harald Welte
2
2
05 Feb '16
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.
---
doc/examples/octphy/osmo-bts.cfg | 8 +-
doc/phy_link.txt | 57 ++++++
doc/startup.txt | 42 ++++
include/osmo-bts/Makefile.am | 2 +-
include/osmo-bts/bts.h | 2 +-
include/osmo-bts/bts_model.h | 8 +
include/osmo-bts/gsm_data.h | 15 --
include/osmo-bts/phy_link.h | 115 +++++++++++
include/osmo-bts/scheduler.h | 4 +-
include/osmo-bts/vty.h | 7 +-
src/common/Makefile.am | 2 +-
src/common/bts.c | 30 ++-
src/common/main.c | 20 ++
src/common/phy_link.c | 159 +++++++++++++++
src/common/scheduler.c | 6 +-
src/common/vty.c | 194 +++++++++++++++++-
src/osmo-bts-octphy/l1_if.c | 170 +++++++++++-----
src/osmo-bts-octphy/l1_if.h | 31 ++-
src/osmo-bts-octphy/l1_oml.c | 163 ++++++++-------
src/osmo-bts-octphy/main.c | 3 +-
src/osmo-bts-octphy/octphy_hw_api.c | 14 +-
src/osmo-bts-octphy/octphy_vty.c | 198 +++++++++++--------
src/osmo-bts-trx/l1_if.c | 84 ++++----
src/osmo-bts-trx/l1_if.h | 18 +-
src/osmo-bts-trx/main.c | 78 +++-----
src/osmo-bts-trx/scheduler_trx.c | 33 ++--
src/osmo-bts-trx/trx_if.c | 133 +++++++++----
src/osmo-bts-trx/trx_if.h | 1 +
src/osmo-bts-trx/trx_vty.c | 381 ++++++++++++++++++++++--------------
29 files changed, 1424 insertions(+), 554 deletions(-)
create mode 100644 doc/phy_link.txt
create mode 100644 doc/startup.txt
create mode 100644 include/osmo-bts/phy_link.h
create mode 100644 src/common/phy_link.c
diff --git a/doc/examples/octphy/osmo-bts.cfg b/doc/examples/octphy/osmo-bts.cfg
index 07bcae0..4f27c8d 100644
--- a/doc/examples/octphy/osmo-bts.cfg
+++ b/doc/examples/octphy/osmo-bts.cfg
@@ -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
diff --git a/doc/phy_link.txt b/doc/phy_link.txt
new file mode 100644
index 0000000..c49e328
--- /dev/null
+++ b/doc/phy_link.txt
@@ -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.
diff --git a/doc/startup.txt b/doc/startup.txt
new file mode 100644
index 0000000..cc64375
--- /dev/null
+++ b/doc/startup.txt
@@ -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
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index af88a1a..d0b55ff 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -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
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 9e21186..ec58edd 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -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);
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index 41b5e93..6252557 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -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
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index 6a7bca8..f9e6ed1 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -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 */
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
new file mode 100644
index 0000000..b9fc412
--- /dev/null
+++ b/include/osmo-bts/phy_link.h
@@ -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);
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index 13ef051..b11e6f1 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -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);
diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h
index 546729c..5d8d4a7 100644
--- a/include/osmo-bts/vty.h
+++ b/include/osmo-bts/vty.h
@@ -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,
};
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index fea205c..8df6513 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -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
diff --git a/src/common/bts.c b/src/common/bts.c
index 43f4c25..2d0ad8e 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -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;
diff --git a/src/common/main.c b/src/common/main.c
index fabe482..e454a28 100644
--- a/src/common/main.c
+++ b/src/common/main.c
@@ -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) {
diff --git a/src/common/phy_link.c b/src/common/phy_link.c
new file mode 100644
index 0000000..4103ede
--- /dev/null
+++ b/src/common/phy_link.c
@@ -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 = talloc_zero(ctx, struct phy_link);
+
+ 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 = talloc_zero(plink, struct phy_instance);
+
+ 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;
+}
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index 64d89ac..de09fbf 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -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,
diff --git a/src/common/vty.c b/src/common/vty.c
index 4fd65d0..94ccdbe 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -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;
}
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index db6e032..3215aa1 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -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,23 +809,15 @@ 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)
- 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);
+ if (trx != trx->bts->c0)
return 0;
- }
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
@@ -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)
diff --git a/src/osmo-bts-octphy/l1_if.h b/src/osmo-bts-octphy/l1_if.h
index 4277865..2dee178 100644
--- a/src/osmo-bts-octphy/l1_if.h
+++ b/src/osmo-bts-octphy/l1_if.h
@@ -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;
@@ -33,12 +33,6 @@ struct octphy_hdl {
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;
char *description;
@@ -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 */
diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c
index 318c384..c50f1d6 100644
--- a/src/osmo-bts-octphy/l1_oml.c
+++ b/src/osmo-bts-octphy/l1_oml.c
@@ -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);
}
+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 gsm_bts_trx *trx, struct msgb *resp, void *data)
+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);
}
diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c
index 1f516e4..0f4d0dd 100644
--- a/src/osmo-bts-octphy/main.c
+++ b/src/osmo-bts-octphy/main.c
@@ -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)
diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c
index 5291742..ec7c4be 100644
--- a/src/osmo-bts-octphy/octphy_hw_api.c
+++ b/src/osmo-bts-octphy/octphy_hw_api.c
@@ -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 =
diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c
index dbc903a..6e58ad4 100644
--- a/src/osmo-bts-octphy/octphy_vty.c
+++ b/src/osmo-bts-octphy/octphy_vty.c
@@ -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;
+
+ if (plink->state != PHY_LINK_SHUTDOWN) {
+ vty_out(vty, "Can only reconfigure a PHY link that is down%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- fl1h->config.rx_gain_db = atoi(argv[0]);
+ 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;
+
+ if (plink->state != PHY_LINK_SHUTDOWN) {
+ vty_out(vty, "Can only reconfigure a PHY link that is down%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- fl1h->config.tx_atten_db = atoi(argv[0]);
+ 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(plink->u.octphy.hdl);
- octphy_hw_get_clock_sync_stats(fl1h);
+ /* 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;
}
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index edd4b7b..befaffd 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -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;
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index f492687..187303c 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -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;
}
diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c
index aa6987c..62e8fe9 100644
--- a/src/osmo-bts-trx/main.c
+++ b/src/osmo-bts-trx/main.c
@@ -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);
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index ac9212b..15c05e8 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -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);
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index dbe6f68..a4c16dc 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -2,6 +2,7 @@
* OpenBTS TRX interface handling
*
* Copyright (C) 2013 Andreas Eversberg <jolly(a)eversberg.eu>
+ * Copyright (C) 2016 Harald Welte <laforge(a)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 bts_model_phy_link_open(struct phy_link *plink)
+{
+ struct phy_instance *pinst;
+ int rc;
+
+ 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 trx=%u\n", l1h->trx->nr);
+ 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);
}
diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h
index 3862e2b..1ea0da9 100644
--- a/src/osmo-bts-trx/trx_if.h
+++ b/src/osmo-bts-trx/trx_if.h
@@ -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;
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index a4a7909..d2feea4 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -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,
+ }
+
+ 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
- vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE);
- if (l1h->config.power_valid)
- vty_out(vty, " power : %d%s", l1h->config.power,
+ 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, " power : undefined%s", VTY_NEWLINE);
- if (l1h->config.maxdly_valid)
- vty_out(vty, " maxdly : %d%s", l1h->config.maxdly,
+ vty_out(vty, " slot #%d: undefined%s", tn,
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")
+static void show_phy_single(struct vty *vty, struct phy_link *plink)
{
- trx_clock_advance = atoi(argv[0]);
+ struct phy_instance *pinst;
- return CMD_SUCCESS;
+ 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(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")
+DEFUN(show_phy, show_phy_cmd, "show phy",
+ SHOW_STR "Display information about the available PHYs")
{
- trx_rts_advance = atoi(argv[0]);
+ 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 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 gsm_bts_trx *trx = vty->index;
- struct trx_l1h *l1h = trx_l1h_hdl(trx);
+ 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 (!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;
+}
- 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);
+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;
}
--
2.7.0
2
5
From: Max <msuraev(a)sysmocom.de>
Add bit filling, shifting and other functions necessary for bit
compression implementation. Add corresponding tests.
---
include/osmocom/core/bitvec.h | 9 +++
src/bitvec.c | 134 +++++++++++++++++++++++++++++++++++++--
tests/bitvec/bitvec_test.c | 141 +++++++++++++++++++++++++++++++++++++++++-
tests/bitvec/bitvec_test.ok | 119 +++++++++++++++++++++++++++++++++++
4 files changed, 396 insertions(+), 7 deletions(-)
diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h
index a7e6fc4..5314cf2 100644
--- a/include/osmocom/core/bitvec.h
+++ b/include/osmocom/core/bitvec.h
@@ -4,6 +4,7 @@
/* (C) 2009 by Harald Welte <laforge(a)gnumonks.org>
* (C) 2012 Ivan Klyuchnikov
+ * (C) 2015 Sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
@@ -41,6 +42,7 @@
#include <stdint.h>
#include <talloc.h>
+#include <stdbool.h>
/*! \brief A single GSM bit
*
@@ -82,5 +84,12 @@ unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer);
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer);
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len);
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len);
+int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill);
+char bit_value_to_char(enum bit_value v);
+void bitvec_to_string_r(const struct bitvec *bv, char *str);
+void bitvec_zero(struct bitvec *bv);
+unsigned bitvec_rl(const struct bitvec *bv, bool b);
+void bitvec_shiftl(struct bitvec *bv, unsigned int n);
+int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits);
/*! @} */
diff --git a/src/bitvec.c b/src/bitvec.c
index b5d2c24..592bfc2 100644
--- a/src/bitvec.c
+++ b/src/bitvec.c
@@ -34,7 +34,9 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
+#include <stdbool.h>
+#include <osmocom/core/bits.h>
#include <osmocom/core/bitvec.h>
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
@@ -224,6 +226,18 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
return 0;
}
+/*! \brief get multiple bits (num_bits) from beginning of vector (MSB side) */
+int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits)
+{
+ if (num_bits > 15 || bv->cur_bit < num_bits)
+ return -EINVAL;
+
+ if (num_bits < 9)
+ return bv->data[0] >> (8 - num_bits);
+
+ return osmo_load16be(bv->data) >> (16 - num_bits);
+}
+
/*! \brief get multiple bits (based on numeric value) from current pos */
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
{
@@ -242,15 +256,27 @@ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
return ui;
}
+/*! \brief fill num_bits with \fill starting from the current position
+ * returns 0 on success, negative otherwise (out of vector boundary)
+ */
+int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
+{
+ unsigned i, stop = bv->cur_bit + num_bits;
+ for (i = bv->cur_bit; i < stop; i++)
+ if (bitvec_set_bit(bv, fill) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
/*! \brief pad all remaining bits up to num_bits */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
{
- unsigned int i;
-
- for (i = bv->cur_bit; i <= up_to_bit; i++)
- bitvec_set_bit(bv, L);
+ int n = up_to_bit - bv->cur_bit + 1;
+ if (n < 1)
+ return 0;
- return 0;
+ return bitvec_fill(bv, n, L);
}
/*! \brief find first bit set in bit vector */
@@ -446,4 +472,102 @@ int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t va
return 0;
}
+/*! \brief convert enum to corresponding character */
+char bit_value_to_char(enum bit_value v)
+{
+ switch (v) {
+ case ZERO: return '0';
+ case ONE: return '1';
+ case L: return 'L';
+ case H: return 'H';
+ default: abort();
+ }
+}
+
+/*! \brief prints bit vector to provided string
+ * It's caller's responsibility to ensure that we won't shoot him in the foot:
+ * the provided buffer should be at lest cur_bit + 1 bytes long
+ */
+void bitvec_to_string_r(const struct bitvec *bv, char *str)
+{
+ unsigned i, pos = 0;
+ char *cur = str;
+ for (i = 0; i < bv->cur_bit; i++) {
+ if (0 == i % 8)
+ *cur++ = ' ';
+ *cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i));
+ pos++;
+ }
+ *cur = 0;
+}
+
+/* we assume that x have at least 1 non-b bit */
+static inline unsigned leading_bits(uint8_t x, bool b)
+{
+ if (b) {
+ if (x < 0x80) return 0;
+ if (x < 0xC0) return 1;
+ if (x < 0xE0) return 2;
+ if (x < 0xF0) return 3;
+ if (x < 0xF8) return 4;
+ if (x < 0xFC) return 5;
+ if (x < 0xFE) return 6;
+ } else {
+ if (x > 0x7F) return 0;
+ if (x > 0x3F) return 1;
+ if (x > 0x1F) return 2;
+ if (x > 0xF) return 3;
+ if (x > 7) return 4;
+ if (x > 3) return 5;
+ if (x > 1) return 6;
+ }
+ return 7;
+}
+/*! \brief force bit vector to all 0 and current bit to the beginnig of the vector */
+void bitvec_zero(struct bitvec *bv)
+{
+ bv->cur_bit = 0;
+ memset(bv->data, 0, bv->data_len);
+}
+
+/*! \brief Return number (bits) of uninterrupted bit run in vector starting from the MSB
+ * \param[in] bv The boolean vector to work on
+ * \param[in] b The boolean, sequence of which is looked at from the vector start
+ * \returns Number of consecutive bits of \p b in \p bv
+ */
+unsigned bitvec_rl(const struct bitvec *bv, bool b)
+{
+ unsigned i;
+ for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) {
+ if ( (b ? 0xFF : 0) != bv->data[i])
+ return i * 8 + leading_bits(bv->data[i], b);
+ }
+
+ return bv->cur_bit;
+}
+
+/*! \brief Shifts bitvec to the left, n MSB bits lost */
+void bitvec_shiftl(struct bitvec *bv, unsigned n)
+{
+ if (0 == n)
+ return;
+ if (n >= bv->cur_bit) {
+ bitvec_zero(bv);
+ return;
+ }
+
+ memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8);
+
+ uint8_t tmp[2];
+ unsigned i;
+ for (i = 0; i < bv->data_len - 2; i++) {
+ uint16_t t = osmo_load16be(bv->data + i);
+ osmo_store16be(t << (n % 8), &tmp);
+ bv->data[i] = tmp[0];
+ }
+
+ bv->data[bv->data_len - 1] <<= (n % 8);
+ bv->cur_bit -= n;
+}
+
/*! @} */
diff --git a/tests/bitvec/bitvec_test.c b/tests/bitvec/bitvec_test.c
index 7d131e0..800a040 100644
--- a/tests/bitvec/bitvec_test.c
+++ b/tests/bitvec/bitvec_test.c
@@ -3,9 +3,82 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
+#include <time.h>
+#include <stdbool.h>
+#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bitvec.h>
+#include <osmocom/core/bits.h>
+
+#define BIN_PATTERN "%d%d%d%d%d%d%d%d"
+#define BIN(byte) \
+ (byte & 0x80 ? 1 : 0), \
+ (byte & 0x40 ? 1 : 0), \
+ (byte & 0x20 ? 1 : 0), \
+ (byte & 0x10 ? 1 : 0), \
+ (byte & 0x08 ? 1 : 0), \
+ (byte & 0x04 ? 1 : 0), \
+ (byte & 0x02 ? 1 : 0), \
+ (byte & 0x01 ? 1 : 0)
+
+static char lol[1024]; // we pollute this with printed vectors
+static inline void test_rl(const struct bitvec *bv)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d] RL0=%d, RL1=%d\n", lol, bv->cur_bit, bitvec_rl(bv, false), bitvec_rl(bv, true));
+}
+
+static inline void test_shift(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s << %d:\n", lol, n);
+ bitvec_shiftl(bv, n);
+ bitvec_to_string_r(bv, lol);
+ printf("%s\n", lol);
+}
+
+static inline void test_get(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d]", lol, bv->cur_bit);
+ int16_t x = bitvec_get_int16_msb(bv, n);
+ uint8_t tmp[2];
+ osmo_store16be(x, &tmp);
+ printf(" -> %d (%u bit) ["BIN_PATTERN" "BIN_PATTERN"]:\n", x, n, BIN(tmp[0]), BIN(tmp[1]));
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d]\n", lol, bv->cur_bit);
+}
+
+static inline void test_fill(struct bitvec *bv, unsigned n, enum bit_value val)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int fi = bitvec_fill(bv, n, val);
+ printf("%c> FILL %s [%d] -%d-> [%d]:\n", bit_value_to_char(val), lol, bvlen, n, fi);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
+
+static inline void test_spare(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int sp = bitvec_spare_padding(bv, n);
+ printf("%c> SPARE %s [%d] -%d-> [%d]:\n", bit_value_to_char(L), lol, bvlen, n, sp);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
+
+static inline void test_set(struct bitvec *bv, enum bit_value bit)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int set = bitvec_set_bit(bv, bit);
+ printf("%c> SET %s [%d] ++> [%d]:\n", bit_value_to_char(bit), lol, bvlen, set);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
static void test_byte_ops()
{
@@ -33,7 +106,7 @@ static void test_byte_ops()
rc = bitvec_set_uint(&bv, 0x7e, 8);
OSMO_ASSERT(rc >= 0);
- fprintf(stderr, "bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len));
+ printf("bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len));
/* Read from bitvec */
memset(out, 0xff, sizeof(out));
@@ -45,7 +118,7 @@ static void test_byte_ops()
rc = bitvec_get_uint(&bv, 8);
OSMO_ASSERT(rc == 0x7e);
- fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out)));
+ printf("out: %s\n", osmo_hexdump(out, sizeof(out)));
OSMO_ASSERT(out[0] == 0xff);
OSMO_ASSERT(out[in_size+1] == 0xff);
@@ -72,11 +145,75 @@ static void test_unhex(const char *hex)
int main(int argc, char **argv)
{
+ struct bitvec bv;
+ uint8_t i = 8, test[i];
+
+ memset(test, 0, i);
+ bv.data_len = i;
+ bv.data = test;
+ bv.cur_bit = 0;
+
+ printf("test shifting...\n");
+
+ bitvec_set_uint(&bv, 0x0E, 7);
+ test_shift(&bv, 3);
+ test_shift(&bv, 17);
+ bitvec_set_uint(&bv, 0, 32);
+ bitvec_set_uint(&bv, 0x0A, 7);
+ test_shift(&bv, 24);
+
+ printf("checking RL functions...\n");
+
+ bitvec_zero(&bv);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0x000F, 32);
+ test_rl(&bv);
+ bitvec_shiftl(&bv, 18);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0x0F, 8);
+ test_rl(&bv);
+ bitvec_zero(&bv);
+ bitvec_set_uint(&bv, 0xFF, 8);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0xFE, 7);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0, 17);
+ test_rl(&bv);
+ bitvec_shiftl(&bv, 18);
+ test_rl(&bv);
+
+ printf("probing bit access...\n");
+
+ bitvec_zero(&bv);
+ bitvec_set_uint(&bv, 0x3747817, 32);
+ bitvec_shiftl(&bv, 10);
+
+ test_get(&bv, 2);
+ test_get(&bv, 7);
+ test_get(&bv, 9);
+ test_get(&bv, 13);
+ test_get(&bv, 16);
+ test_get(&bv, 42);
+
+ printf("feeling bit fills...\n");
+
+ test_set(&bv, ONE);
+ test_fill(&bv, 3, ZERO);
+ test_spare(&bv, 38);
+ test_spare(&bv, 43);
+ test_spare(&bv, 1);
+ test_spare(&bv, 7);
+ test_fill(&bv, 5, ONE);
+ test_fill(&bv, 3, L);
+
+ printf("byte me...\n");
+
test_byte_ops();
test_unhex("48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b");
test_unhex("47240c00400000000000000079eb2ac9402b2b2b2b2b2b");
test_unhex("47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b");
test_unhex("DEADFACE000000000000000000000000000000BEEFFEED");
test_unhex("FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
+
return 0;
}
diff --git a/tests/bitvec/bitvec_test.ok b/tests/bitvec/bitvec_test.ok
index 83328b2..1c993d3 100644
--- a/tests/bitvec/bitvec_test.ok
+++ b/tests/bitvec/bitvec_test.ok
@@ -1,4 +1,123 @@
+test shifting...
+ 0001110 << 3:
+ 1110
+ 1110 << 17:
+
+ 00000000 00000000 00000000 00000000 0001010 << 24:
+ 00000000 0001010
+checking RL functions...
+ [0] RL0=0, RL1=0
+ 00000000 00000000 00000000 00001111 [32] RL0=28, RL1=0
+ 00000000 001111 [14] RL0=10, RL1=0
+ 00000000 00111100 001111 [22] RL0=10, RL1=0
+ 11111111 [8] RL0=0, RL1=8
+ 11111111 1111110 [15] RL0=0, RL1=14
+ 11111111 11111100 00000000 00000000 [32] RL0=0, RL1=14
+ 00000000 000000 [14] RL0=14, RL1=0
+probing bit access...
+ 11010001 11100000 010111 [22] -> 3 (2 bit) [00000000 00000011]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 104 (7 bit) [00000000 01101000]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 419 (9 bit) [00000001 10100011]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 6716 (13 bit) [00011010 00111100]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> -22 (16 bit) [11111111 11101010]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> -22 (42 bit) [11111111 11101010]:
+ 11010001 11100000 010111 [22]
+feeling bit fills...
+1> SET 11010001 11100000 010111 [22] ++> [0]:
+ 11010001 11100000 0101111 [23]
+
+0> FILL 11010001 11100000 0101111 [23] -3-> [0]:
+ 11010001 11100000 01011110 00 [26]
+
+L> SPARE 11010001 11100000 01011110 00 [26] -38-> [0]:
+ 11010001 11100000 01011110 00101011 0010101 [39]
+
+L> SPARE 11010001 11100000 01011110 00101011 0010101 [39] -43-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -1-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -7-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+1> FILL 11010001 11100000 01011110 00101011 00101011 0010 [44] -5-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 00101111 1 [49]
+
+L> FILL 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] -3-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 00101111 1010 [52]
+
+byte me...
=== start test_byte_ops ===
+bitvec: 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
=== end test_byte_ops ===
1 -=> cur_bit=184
48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000
--
2.5.0
1
1
Hi,
before the l1sap changes were merged I fixed a case where after a ip.access CRCX with recvonly mode the BTS would already start to send RTP frames to UDP port 0 which will trigger an ICMP unreachable. This is not harmful but still a bug. After the l1sap merge the sysmobts is still doing it when it receives a TCH frame and all other bts models behave like before the bugfix. The below diff copies this into the common code.
Besides administratives work I try to work on the SMSC, so if anyone could testdrive this patch and check for ICMP errors it would be greatly appreciated.
holger
1
0
From: Daniel Willmann <daniel(a)totalueberwachung.de>
Hello,
it seems PDP context updates was never really used/tested to an Update PDP
context would not go through. The following patches fix that (at least for
gtpv1).
Regards
Daniel
Daniel Willmann (3):
gtp: Pass pdp along when calling gtp_req() in gtp_update_context()
gtp: Make gtp_update_pdp_conf() work for gtp0 and gtp1 connections
gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly
gtp/gtp.c | 162 +++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 118 insertions(+), 44 deletions(-)
--
2.1.4
--
- Daniel Willmann <dwillmann(a)sysmocom.de> http://www.sysmocom.de/
=======================================================================
* sysmocom - systems for mobile communications GmbH
* Alt-Moabit 93
* 10559 Berlin, Germany
* Sitz / Registered office: Berlin, HRB 134158 B
* Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte
3
6
From: Max <msuraev(a)sysmocom.de>
Add bit filling, shifting and other functions necessary for bit
compression implementation. Add corresponding tests.
---
include/osmocom/core/bitvec.h | 9 +++
src/bitvec.c | 132 ++++++++++++++++++++++++++++++++++++--
tests/bitvec/bitvec_test.c | 143 +++++++++++++++++++++++++++++++++++++++++-
tests/bitvec/bitvec_test.ok | 119 +++++++++++++++++++++++++++++++++++
4 files changed, 396 insertions(+), 7 deletions(-)
diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h
index a7e6fc4..5314cf2 100644
--- a/include/osmocom/core/bitvec.h
+++ b/include/osmocom/core/bitvec.h
@@ -4,6 +4,7 @@
/* (C) 2009 by Harald Welte <laforge(a)gnumonks.org>
* (C) 2012 Ivan Klyuchnikov
+ * (C) 2015 Sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
@@ -41,6 +42,7 @@
#include <stdint.h>
#include <talloc.h>
+#include <stdbool.h>
/*! \brief A single GSM bit
*
@@ -82,5 +84,12 @@ unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer);
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer);
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len);
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len);
+int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill);
+char bit_value_to_char(enum bit_value v);
+void bitvec_to_string_r(const struct bitvec *bv, char *str);
+void bitvec_zero(struct bitvec *bv);
+unsigned bitvec_rl(const struct bitvec *bv, bool b);
+void bitvec_shiftl(struct bitvec *bv, unsigned int n);
+int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits);
/*! @} */
diff --git a/src/bitvec.c b/src/bitvec.c
index b5d2c24..fc016a6 100644
--- a/src/bitvec.c
+++ b/src/bitvec.c
@@ -34,7 +34,9 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
+#include <stdbool.h>
+#include <osmocom/core/bits.h>
#include <osmocom/core/bitvec.h>
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
@@ -224,6 +226,20 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
return 0;
}
+/*! \brief get multiple bits (num_bits) from beginning of vector (MSB side) */
+int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits)
+{
+ uint8_t tmp[2];
+ if (num_bits > 15 || bv->cur_bit < num_bits)
+ return -EINVAL;
+
+ if (num_bits < 9)
+ return bv->data[0] >> (8 - num_bits);
+
+ memcpy(tmp, bv->data, 2);
+ return osmo_load16be(tmp) >> (16 - num_bits);
+}
+
/*! \brief get multiple bits (based on numeric value) from current pos */
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
{
@@ -242,15 +258,27 @@ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
return ui;
}
+/*! \brief fill num_bits with \fill starting from the current position
+ * returns 0 on success, negative otherwise (out of vector boundary)
+ */
+int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
+{
+ unsigned i, stop = bv->cur_bit + num_bits;
+ for (i = bv->cur_bit; i < stop; i++)
+ if (bitvec_set_bit(bv, fill) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
/*! \brief pad all remaining bits up to num_bits */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
{
- unsigned int i;
-
- for (i = bv->cur_bit; i <= up_to_bit; i++)
- bitvec_set_bit(bv, L);
+ int n = up_to_bit - bv->cur_bit + 1;
+ if (n < 1)
+ return 0;
- return 0;
+ return bitvec_fill(bv, n, L);
}
/*! \brief find first bit set in bit vector */
@@ -446,4 +474,98 @@ int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t va
return 0;
}
+/*! \brief convert enum to corresponding character */
+char bit_value_to_char(enum bit_value v)
+{
+ switch (v) {
+ case ZERO: return '0';
+ case ONE: return '1';
+ case L: return 'L';
+ case H: return 'H';
+ }
+ /* make compiler happy - "avoid control reaches end of non-void function" warning: */
+ return '?';
+}
+
+/*! \brief prints bit vector to provided string
+ * It's caller's responcibility to ensure that we won't shoot him in the foot.
+ */
+void bitvec_to_string_r(const struct bitvec *bv, char *str)
+{
+ unsigned i, pos = 0;
+ char *cur = str;
+ for (i = 0; i < bv->cur_bit; i++) {
+ if (0 == i % 8)
+ *cur++ = ' ';
+ *cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i));
+ pos++;
+ }
+ *cur = 0;
+}
+
+/* we assume that x have at least 1 non-b bit */
+static inline unsigned _leading_bits(uint8_t x, bool b)
+{
+ if (b) {
+ if (x < 0x80) return 0;
+ if (x < 0xC0) return 1;
+ if (x < 0xE0) return 2;
+ if (x < 0xF0) return 3;
+ if (x < 0xF8) return 4;
+ if (x < 0xFC) return 5;
+ if (x < 0xFE) return 6;
+ } else {
+ if (x > 0x7F) return 0;
+ if (x > 0x3F) return 1;
+ if (x > 0x1F) return 2;
+ if (x > 0xF) return 3;
+ if (x > 7) return 4;
+ if (x > 3) return 5;
+ if (x > 1) return 6;
+ }
+ return 7;
+}
+/*! \brief force bit vector to all 0 and current bit to the beginnig of the vector */
+void bitvec_zero(struct bitvec *bv)
+{
+ bv->cur_bit = 0;
+ memset(bv->data, 0, bv->data_len);
+}
+
+/*! \brief Return number (bits) of uninterrupted run of \b in \bv starting from the MSB */
+unsigned bitvec_rl(const struct bitvec *bv, bool b)
+{
+ unsigned i;
+ for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) {
+ if ( (b ? 0xFF : 0) != bv->data[i])
+ return i * 8 + _leading_bits(bv->data[i], b);
+ }
+
+ return bv->cur_bit;
+}
+
+/*! \brief Shifts bitvec to the left, n MSB bits lost */
+void bitvec_shiftl(struct bitvec *bv, unsigned n)
+{
+ if (0 == n)
+ return;
+ if (n >= bv->cur_bit) {
+ bitvec_zero(bv);
+ return;
+ }
+
+ memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8);
+
+ uint8_t tmp[2];
+ unsigned i;
+ for (i = 0; i < bv->data_len - 2; i++) {
+ uint16_t t = osmo_load16be(bv->data + i);
+ osmo_store16be(t << (n % 8), &tmp);
+ bv->data[i] = tmp[0];
+ }
+
+ bv->data[bv->data_len - 1] <<= (n % 8);
+ bv->cur_bit -= n;
+}
+
/*! @} */
diff --git a/tests/bitvec/bitvec_test.c b/tests/bitvec/bitvec_test.c
index 7d131e0..4fc9db3 100644
--- a/tests/bitvec/bitvec_test.c
+++ b/tests/bitvec/bitvec_test.c
@@ -3,9 +3,82 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
+#include <time.h>
+#include <stdbool.h>
+#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bitvec.h>
+#include <osmocom/core/bits.h>
+
+#define BIN_PATTERN "%d%d%d%d%d%d%d%d"
+#define BIN(byte) \
+ (byte & 0x80 ? 1 : 0), \
+ (byte & 0x40 ? 1 : 0), \
+ (byte & 0x20 ? 1 : 0), \
+ (byte & 0x10 ? 1 : 0), \
+ (byte & 0x08 ? 1 : 0), \
+ (byte & 0x04 ? 1 : 0), \
+ (byte & 0x02 ? 1 : 0), \
+ (byte & 0x01 ? 1 : 0)
+
+static char lol[1024]; // we pollute this with printed vectors
+static inline void test_rl(const struct bitvec *bv)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d] RL0=%d, RL1=%d\n", lol, bv->cur_bit, bitvec_rl(bv, false), bitvec_rl(bv, true));
+}
+
+static inline void test_shift(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s << %d:\n", lol, n);
+ bitvec_shiftl(bv, n);
+ bitvec_to_string_r(bv, lol);
+ printf("%s\n", lol);
+}
+
+static inline void test_get(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d]", lol, bv->cur_bit);
+ int16_t x = bitvec_get_int16_msb(bv, n);
+ uint8_t tmp[2];
+ osmo_store16be(x, &tmp);
+ printf(" -> %d (%u bit) ["BIN_PATTERN" "BIN_PATTERN"]:\n", x, n, BIN(tmp[0]), BIN(tmp[1]));
+ bitvec_to_string_r(bv, lol);
+ printf("%s [%d]\n", lol, bv->cur_bit);
+}
+
+static inline void test_fill(struct bitvec *bv, unsigned n, enum bit_value val)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int fi = bitvec_fill(bv, n, val);
+ printf("%c> FILL %s [%d] -%d-> [%d]:\n", bit_value_to_char(val), lol, bvlen, n, fi);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
+
+static inline void test_spare(struct bitvec *bv, unsigned n)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int sp = bitvec_spare_padding(bv, n);
+ printf("%c> SPARE %s [%d] -%d-> [%d]:\n", bit_value_to_char(L), lol, bvlen, n, sp);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
+
+static inline void test_set(struct bitvec *bv, enum bit_value bit)
+{
+ bitvec_to_string_r(bv, lol);
+ unsigned bvlen = bv->cur_bit;
+ int set = bitvec_set_bit(bv, bit);
+ printf("%c> SET %s [%d] ++> [%d]:\n", bit_value_to_char(bit), lol, bvlen, set);
+ bitvec_to_string_r(bv, lol);
+ printf(" %s [%d]\n\n", lol, bv->cur_bit);
+}
static void test_byte_ops()
{
@@ -33,7 +106,7 @@ static void test_byte_ops()
rc = bitvec_set_uint(&bv, 0x7e, 8);
OSMO_ASSERT(rc >= 0);
- fprintf(stderr, "bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len));
+ printf("bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len));
/* Read from bitvec */
memset(out, 0xff, sizeof(out));
@@ -45,7 +118,7 @@ static void test_byte_ops()
rc = bitvec_get_uint(&bv, 8);
OSMO_ASSERT(rc == 0x7e);
- fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out)));
+ printf("out: %s\n", osmo_hexdump(out, sizeof(out)));
OSMO_ASSERT(out[0] == 0xff);
OSMO_ASSERT(out[in_size+1] == 0xff);
@@ -72,11 +145,77 @@ static void test_unhex(const char *hex)
int main(int argc, char **argv)
{
+ srand(time(NULL));
+
+ struct bitvec bv;
+ uint8_t i = 8, test[i];
+
+ memset(test, 0, i);
+ bv.data_len = i;
+ bv.data = test;
+ bv.cur_bit = 0;
+
+ printf("test shifting...\n");
+
+ bitvec_set_uint(&bv, 0x0E, 7);
+ test_shift(&bv, 3);
+ test_shift(&bv, 17);
+ bitvec_set_uint(&bv, 0, 32);
+ bitvec_set_uint(&bv, 0x0A, 7);
+ test_shift(&bv, 24);
+
+ printf("checking RL functions...\n");
+
+ bitvec_zero(&bv);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0x000F, 32);
+ test_rl(&bv);
+ bitvec_shiftl(&bv, 18);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0x0F, 8);
+ test_rl(&bv);
+ bitvec_zero(&bv);
+ bitvec_set_uint(&bv, 0xFF, 8);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0xFE, 7);
+ test_rl(&bv);
+ bitvec_set_uint(&bv, 0, 17);
+ test_rl(&bv);
+ bitvec_shiftl(&bv, 18);
+ test_rl(&bv);
+
+ printf("probing bit access...\n");
+
+ bitvec_zero(&bv);
+ bitvec_set_uint(&bv, 0x3747817, 32);
+ bitvec_shiftl(&bv, 10);
+
+ test_get(&bv, 2);
+ test_get(&bv, 7);
+ test_get(&bv, 9);
+ test_get(&bv, 13);
+ test_get(&bv, 16);
+ test_get(&bv, 42);
+
+ printf("feeling bit fills...\n");
+
+ test_set(&bv, ONE);
+ test_fill(&bv, 3, ZERO);
+ test_spare(&bv, 38);
+ test_spare(&bv, 43);
+ test_spare(&bv, 1);
+ test_spare(&bv, 7);
+ test_fill(&bv, 5, ONE);
+ test_fill(&bv, 3, L);
+
+ printf("byte me...\n");
+
test_byte_ops();
test_unhex("48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b");
test_unhex("47240c00400000000000000079eb2ac9402b2b2b2b2b2b");
test_unhex("47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b");
test_unhex("DEADFACE000000000000000000000000000000BEEFFEED");
test_unhex("FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
+
return 0;
}
diff --git a/tests/bitvec/bitvec_test.ok b/tests/bitvec/bitvec_test.ok
index 83328b2..1c993d3 100644
--- a/tests/bitvec/bitvec_test.ok
+++ b/tests/bitvec/bitvec_test.ok
@@ -1,4 +1,123 @@
+test shifting...
+ 0001110 << 3:
+ 1110
+ 1110 << 17:
+
+ 00000000 00000000 00000000 00000000 0001010 << 24:
+ 00000000 0001010
+checking RL functions...
+ [0] RL0=0, RL1=0
+ 00000000 00000000 00000000 00001111 [32] RL0=28, RL1=0
+ 00000000 001111 [14] RL0=10, RL1=0
+ 00000000 00111100 001111 [22] RL0=10, RL1=0
+ 11111111 [8] RL0=0, RL1=8
+ 11111111 1111110 [15] RL0=0, RL1=14
+ 11111111 11111100 00000000 00000000 [32] RL0=0, RL1=14
+ 00000000 000000 [14] RL0=14, RL1=0
+probing bit access...
+ 11010001 11100000 010111 [22] -> 3 (2 bit) [00000000 00000011]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 104 (7 bit) [00000000 01101000]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 419 (9 bit) [00000001 10100011]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> 6716 (13 bit) [00011010 00111100]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> -22 (16 bit) [11111111 11101010]:
+ 11010001 11100000 010111 [22]
+ 11010001 11100000 010111 [22] -> -22 (42 bit) [11111111 11101010]:
+ 11010001 11100000 010111 [22]
+feeling bit fills...
+1> SET 11010001 11100000 010111 [22] ++> [0]:
+ 11010001 11100000 0101111 [23]
+
+0> FILL 11010001 11100000 0101111 [23] -3-> [0]:
+ 11010001 11100000 01011110 00 [26]
+
+L> SPARE 11010001 11100000 01011110 00 [26] -38-> [0]:
+ 11010001 11100000 01011110 00101011 0010101 [39]
+
+L> SPARE 11010001 11100000 01011110 00101011 0010101 [39] -43-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -1-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -7-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 0010 [44]
+
+1> FILL 11010001 11100000 01011110 00101011 00101011 0010 [44] -5-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 00101111 1 [49]
+
+L> FILL 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] -3-> [0]:
+ 11010001 11100000 01011110 00101011 00101011 00101111 1010 [52]
+
+byte me...
=== start test_byte_ops ===
+bitvec: 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
+bitvec: 00 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff
=== end test_byte_ops ===
1 -=> cur_bit=184
48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000
--
2.5.0
3
4
03 Feb '16
From: Harald Welte <laforge(a)gnumonks.org>
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.
---
doc/examples/octphy/osmo-bts.cfg | 8 +-
include/osmo-bts/Makefile.am | 2 +-
include/osmo-bts/bts.h | 3 +-
include/osmo-bts/bts_model.h | 5 +
include/osmo-bts/gsm_data.h | 15 --
include/osmo-bts/phy_link.h | 115 +++++++++++
include/osmo-bts/scheduler.h | 4 +-
include/osmo-bts/vty.h | 7 +-
src/common/Makefile.am | 2 +-
src/common/bts.c | 33 +++-
src/common/main.c | 20 ++
src/common/phy_link.c | 155 +++++++++++++++
src/common/scheduler.c | 6 +-
src/common/vty.c | 194 ++++++++++++++++++-
src/osmo-bts-octphy/l1_if.c | 133 ++++++++-----
src/osmo-bts-octphy/l1_if.h | 31 ++-
src/osmo-bts-octphy/l1_oml.c | 96 +++++----
src/osmo-bts-octphy/main.c | 1 +
src/osmo-bts-octphy/octphy_hw_api.c | 14 +-
src/osmo-bts-octphy/octphy_vty.c | 198 +++++++++++--------
src/osmo-bts-trx/l1_if.c | 84 ++++----
src/osmo-bts-trx/l1_if.h | 18 +-
src/osmo-bts-trx/main.c | 56 ++----
src/osmo-bts-trx/scheduler_trx.c | 16 +-
src/osmo-bts-trx/trx_if.c | 124 +++++++++---
src/osmo-bts-trx/trx_if.h | 1 +
src/osmo-bts-trx/trx_vty.c | 377 ++++++++++++++++++++++--------------
27 files changed, 1220 insertions(+), 498 deletions(-)
create mode 100644 include/osmo-bts/phy_link.h
create mode 100644 src/common/phy_link.c
diff --git a/doc/examples/octphy/osmo-bts.cfg b/doc/examples/octphy/osmo-bts.cfg
index 07bcae0..4f27c8d 100644
--- a/doc/examples/octphy/osmo-bts.cfg
+++ b/doc/examples/octphy/osmo-bts.cfg
@@ -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
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index af88a1a..d0b55ff 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -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
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 9e21186..af0b305 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -21,13 +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);
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index 41b5e93..dfea988 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -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);
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index 6a7bca8..f9e6ed1 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -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 */
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
new file mode 100644
index 0000000..b9fc412
--- /dev/null
+++ b/include/osmo-bts/phy_link.h
@@ -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);
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index 13ef051..b11e6f1 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -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);
diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h
index 546729c..5d8d4a7 100644
--- a/include/osmo-bts/vty.h
+++ b/include/osmo-bts/vty.h
@@ -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,
};
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index fea205c..8df6513 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -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
diff --git a/src/common/bts.c b/src/common/bts.c
index 43f4c25..a775329 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -44,6 +44,8 @@
#include <osmo-bts/oml.h>
#include <osmo-bts/signal.h>
+static void bts_update_agch_max_queue_length(struct gsm_bts *bts);
+static int bts_agch_max_queue_length(int T, int bcch_conf);
struct gsm_network bts_gsmnet = {
.bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list },
@@ -72,6 +74,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 +259,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;
@@ -271,7 +300,7 @@ int lchan_init_lapdm(struct gsm_lchan *lchan)
#define CCCH_RACH_RATIO_COMBINED256 (256*1/9)
#define CCCH_RACH_RATIO_SEPARATE256 (256*10/55)
-int bts_agch_max_queue_length(int T, int bcch_conf)
+static int bts_agch_max_queue_length(int T, int bcch_conf)
{
int S, ccch_rach_ratio256, i;
int T_group = 0;
@@ -310,7 +339,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;
diff --git a/src/common/main.c b/src/common/main.c
index fabe482..e454a28 100644
--- a/src/common/main.c
+++ b/src/common/main.c
@@ -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) {
diff --git a/src/common/phy_link.c b/src/common/phy_link.c
new file mode 100644
index 0000000..9442349
--- /dev/null
+++ b/src/common/phy_link.c
@@ -0,0 +1,155 @@
+#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 = talloc_zero(ctx, struct phy_link);
+
+ 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);
+
+ 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 = talloc_zero(plink, struct phy_instance);
+
+ 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);
+
+ 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;
+}
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index 64d89ac..de09fbf 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -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,
diff --git a/src/common/vty.c b/src/common/vty.c
index 4fd65d0..94ccdbe 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -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;
}
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index db6e032..f73e4f9 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -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,37 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
return rc;
}
+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? */
+
+ /* FIXME: delay this until we know the PHY responds */
+ phy_link_state_set(plink, PHY_LINK_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,23 +768,15 @@ 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)
- 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);
+ if (trx != trx->bts->c0)
return 0;
- }
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
@@ -783,7 +793,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 +918,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 +1002,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 +1141,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);
@@ -1534,15 +1544,35 @@ 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 0
+ 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;
+#endif
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 +1583,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 +1595,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 +1622,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)
diff --git a/src/osmo-bts-octphy/l1_if.h b/src/osmo-bts-octphy/l1_if.h
index 4277865..2dee178 100644
--- a/src/osmo-bts-octphy/l1_if.h
+++ b/src/osmo-bts-octphy/l1_if.h
@@ -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;
@@ -33,12 +33,6 @@ struct octphy_hdl {
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;
char *description;
@@ -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 */
diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c
index 318c384..627b238 100644
--- a/src/osmo-bts-octphy/l1_oml.c
+++ b/src/osmo-bts-octphy/l1_oml.c
@@ -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;
@@ -1194,8 +1205,11 @@ int l1if_check_app_version(struct gsm_bts_trx *trx)
}
/* 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_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data)
{
+ struct gsm_bts_trx *trx;
+ struct phy_instance *pinst;
+
tOCTVC1_GSM_MSG_TRX_OPEN_RSP *or =
(tOCTVC1_GSM_MSG_TRX_OPEN_RSP *) resp->l2h;
@@ -1203,8 +1217,8 @@ 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);
+ pinst = trx_phy_instance(trx);
LOGP(DL1C, LOGL_INFO, "TRX-OPEN.resp(trx=%u) = %s\n",
trx->nr, octvc1_rc2string(or->Header.ulReturnCode));
@@ -1221,7 +1235,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 +1251,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,7 +1281,7 @@ 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)
+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;
@@ -1283,7 +1298,9 @@ static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *da
int l1if_trx_close_all(struct gsm_bts *bts)
{
- struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0);
+#warning "Truly iterate over all TRX in this BTS"
+ struct phy_instance *pinst = trx_phy_instance(bts->c0);
+ struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *msg = l1p_msgb_alloc();
tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac;
@@ -1325,11 +1342,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 +1355,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 +1384,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 +1394,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 +1448,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,8 +1464,7 @@ 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)
diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c
index 1f516e4..d237e42 100644
--- a/src/osmo-bts-octphy/main.c
+++ b/src/osmo-bts-octphy/main.c
@@ -56,6 +56,7 @@ static struct gsm_bts *bts;
int bts_model_print_help()
{
+ return 0;
}
int bts_model_handle_options(int argc, char **argv)
diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c
index 5291742..ec7c4be 100644
--- a/src/osmo-bts-octphy/octphy_hw_api.c
+++ b/src/osmo-bts-octphy/octphy_hw_api.c
@@ -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 =
diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c
index dbc903a..e2000e9 100644
--- a/src/osmo-bts-octphy/octphy_vty.c
+++ b/src/osmo-bts-octphy/octphy_vty.c
@@ -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;
+
+ if (plink->state != PHY_LINK_SHUTDOWN) {
+ vty_out(vty, "Can only reconfigure a PHY link that is down%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- fl1h->config.rx_gain_db = atoi(argv[0]);
+ 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;
+
+ if (plink->state != PHY_LINK_SHUTDOWN) {
+ vty_out(vty, "Can only reconfigure a PHY link that is down%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- fl1h->config.tx_atten_db = atoi(argv[0]);
+ 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 */
+ 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(plink->u.octphy.hdl);
- octphy_hw_get_clock_sync_stats(fl1h);
+ /* FIXME */
+ 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;
}
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index edd4b7b..befaffd 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -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;
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index f492687..187303c 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -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;
}
diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c
index aa6987c..40cbcac 100644
--- a/src/osmo-bts-trx/main.c
+++ b/src/osmo-bts-trx/main.c
@@ -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,42 +59,13 @@
#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;
- }
-
+#if 0
trx->role_bts.l1h = l1h;
trx->nominal_power = 23;
l1if_reset(l1h);
- }
-
- bts_model_vty_init(bts);
+#endif
- 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 +75,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 +84,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 +103,17 @@ 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);
+
+ bts_model_vty_init(bts);
+
+ return 0;
+}
+
int main(int argc, char **argv)
{
return bts_main(argc, argv);
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index ac9212b..87d21ff 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -1268,8 +1268,9 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
/* 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 trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ struct l1sched_trx *l1t = &l1h->l1s;
/* we don't schedule, if power is off */
if (!trx_if_powered(l1h))
@@ -1323,10 +1324,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 +1464,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);
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index dbe6f68..6743d0b 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -2,6 +2,7 @@
* OpenBTS TRX interface handling
*
* Copyright (C) 2013 Andreas Eversberg <jolly(a)eversberg.eu>
+ * Copyright (C) 2016 Harald Welte <laforge(a)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;
@@ -56,8 +57,9 @@ int setbsic_enabled = 0;
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 +73,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 +86,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 +98,6 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port,
if (rc)
return rc;
-
return 0;
}
@@ -115,13 +116,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 +145,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 +167,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 +183,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 +231,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 +240,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 +325,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 +376,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,11 +496,67 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
* open/close
*/
+int bts_model_phy_link_open(struct phy_link *plink)
+{
+ struct phy_instance *pinst;
+ int rc;
+
+ 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 trx=%u\n", l1h->trx->nr);
+ LOGP(DTRX, LOGL_NOTICE, "Open transceiver for %s\n",
+ phy_instance_name(pinst));
/* initialize ctrl queue */
INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
@@ -511,19 +570,24 @@ int trx_if_open(struct trx_l1h *l1h)
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 +612,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);
}
diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h
index 3862e2b..1ea0da9 100644
--- a/src/osmo-bts-trx/trx_if.h
+++ b/src/osmo-bts-trx/trx_if.h
@@ -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;
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index a4a7909..b273e94 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -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,
+ }
+
+ 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
- vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE);
- if (l1h->config.power_valid)
- vty_out(vty, " power : %d%s", l1h->config.power,
+ 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, " power : undefined%s", VTY_NEWLINE);
- if (l1h->config.maxdly_valid)
- vty_out(vty, " maxdly : %d%s", l1h->config.maxdly,
+ vty_out(vty, " slot #%d: undefined%s", tn,
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")
+static void show_phy_single(struct vty *vty, struct phy_link *plink)
{
- trx_clock_advance = atoi(argv[0]);
+ struct phy_instance *pinst;
- return CMD_SUCCESS;
+ 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(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")
+DEFUN(show_phy, show_phy_cmd, "show phy",
+ SHOW_STR "Display information about the available PHYs")
{
- trx_rts_advance = atoi(argv[0]);
+ 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,167 @@ 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")
+{
+ trx_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")
+{
+ trx_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 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 gsm_bts_trx *trx = vty->index;
- struct trx_l1h *l1h = trx_l1h_hdl(trx);
+ 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 (!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;
+}
- 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);
+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 +449,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 +484,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;
}
--
2.7.0
2
3