From: Max msuraev@sysmocom.de
--- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore index d2713bf..959b09b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ compile depcomp install-sh missing -libtool +*libtool ltmain.sh
core
From: Max msuraev@sysmocom.de
This helps to increase compatibility with newer automake. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac index 5274022..7a97954 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_INIT([osmo-pcu], m4_esyscmd([./git-version-gen .tarball-version]), [osmocom-net-gprs@lists.osmocom.org])
-AM_INIT_AUTOMAKE([dist-bzip2]) +AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects]) AC_CONFIG_TESTDIR(tests)
dnl kernel style compile messages
Hi Max,
On Thu, Apr 21, 2016 at 02:35:54PM +0200, msuraev@sysmocom.de wrote:
This helps to increase compatibility with newer automake.
I tried several times to add subdir-objects, but we always had to revert these kind of changes, as they broke something. Don't recall what exactly, but I think it was related to either out-of-source builds and/or autotest? Holger?
It's currently enabled for libosmocore master.
On 04/22/2016 02:38 PM, Harald Welte wrote:
Hi Max,
On Thu, Apr 21, 2016 at 02:35:54PM +0200, msuraev@sysmocom.de wrote:
This helps to increase compatibility with newer automake.
I tried several times to add subdir-objects, but we always had to revert these kind of changes, as they broke something. Don't recall what exactly, but I think it was related to either out-of-source builds and/or autotest? Holger?
See my mail from 17th Feb Cc'd to openbsc@, where I ask autoconf about the weird dirs showing up when subdir-objects is used, answered by Eric Blake of RedHat:
[[[
On Thu, Jan 14, 2016 at 02:40:38PM +0100, Neels Hofmeyr wrote:
Dear autoconf,
I am observing a bug with `autoreconf -i`. To my/our knowledge, this is not due to an error in our configuration but a genuine bug from 'subdir-objects'.
The symptom: after running ./configure, I find a directory src/tests/$(top_srcdir)
This is a known automake bug, not caused by autoconf; that may explain why you haven't seen much response on the autoconf list, but I don't know if there are any active maintainers on the automake list that have suggestions on how to work around it, or on when a fixed automake will be available (or if it is already available). A quick search found this, though: https://lists.gnu.org/archive/html/automake/2015-12/msg00001.html ]]]
Here is the openbsc@ thread: http://lists.osmocom.org/pipermail/openbsc/2016-February/007971.html
So besides creating those weird directories, subdir-objects works AFAIK. We are currently using subdir-objects in osmo-iuh, libosmo-abis, libosmo-netif and last but not least libosmocore. (at least on 3G branches)
~Neels
On Fri, Apr 22, 2016 at 02:38:21PM +0200, Harald Welte wrote:
Hi Max,
On Thu, Apr 21, 2016 at 02:35:54PM +0200, msuraev@sysmocom.de wrote:
This helps to increase compatibility with newer automake.
I tried several times to add subdir-objects, but we always had to revert these kind of changes, as they broke something. Don't recall what exactly, but I think it was related to either out-of-source builds and/or autotest? Holger?
--
- Harald Welte laforge@gnumonks.org http://laforge.gnumonks.org/
============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6)
From: Max msuraev@sysmocom.de
--- src/Makefile.am | 2 +- src/osmobts_sock.cpp | 2 +- src/pcu_l1_if.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am index 6428bef..832c3b0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS)
if ENABLE_SYSMODSP -AM_CPPFLAGS += -DENABLE_SYSMODSP +AM_CPPFLAGS += -DENABLE_DIRECT_PHY endif
AM_CXXFLAGS = -Wall -ldl -pthread diff --git a/src/osmobts_sock.cpp b/src/osmobts_sock.cpp index b42f042..21a404f 100644 --- a/src/osmobts_sock.cpp +++ b/src/osmobts_sock.cpp @@ -100,7 +100,7 @@ static void pcu_sock_close(struct pcu_sock_state *state, int lost)
/* disable all slots, kick all TBFs */ for (trx = 0; trx < 8; trx++) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { l1if_close_pdch(bts->trx[trx].fl1h); bts->trx[trx].fl1h = NULL; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 19dda5c..67272ab 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -128,7 +128,7 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, { struct gprs_rlcmac_bts *bts = bts_main_data();
-#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr, msg->data, msg->len); @@ -147,7 +147,7 @@ void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, { struct gprs_rlcmac_bts *bts = bts_main_data();
-#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, msg->data, msg->len); @@ -445,7 +445,7 @@ bssgp_failed: bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; if ((info_ind->flags & PCU_IF_FLAG_SYSMO) && info_ind->trx[trx].hlayer1) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY LOGP(DL1IF, LOGL_DEBUG, " TRX %d hlayer1=%x\n", trx, info_ind->trx[trx].hlayer1); if (!bts->trx[trx].fl1h) @@ -471,7 +471,7 @@ bssgp_failed: if ((info_ind->trx[trx].pdch_mask & (1 << ts))) { /* FIXME: activate dynamically at RLCMAC */ if (!pdch->is_enabled()) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if ((info_ind->flags & PCU_IF_FLAG_SYSMO)) l1if_connect_pdch(
From: Max msuraev@sysmocom.de
Move hardware-spicefic files into subdirectory similar to the way it's done in OsmoBTS to make adding new hardware support easier. --- src/Makefile.am | 49 +++-- src/femtobts.c | 275 -------------------------- src/femtobts.h | 57 ------ src/osmo-bts-sysmo/femtobts.c | 275 ++++++++++++++++++++++++++ src/osmo-bts-sysmo/femtobts.h | 57 ++++++ src/osmo-bts-sysmo/sysmo_l1_fwd.c | 145 ++++++++++++++ src/osmo-bts-sysmo/sysmo_l1_hw.c | 216 +++++++++++++++++++++ src/osmo-bts-sysmo/sysmo_l1_if.c | 394 ++++++++++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/sysmo_l1_if.h | 91 +++++++++ src/sysmo_l1_fwd.c | 145 -------------- src/sysmo_l1_hw.c | 216 --------------------- src/sysmo_l1_if.c | 394 -------------------------------------- src/sysmo_l1_if.h | 91 --------- 13 files changed, 1207 insertions(+), 1198 deletions(-) delete mode 100644 src/femtobts.c delete mode 100644 src/femtobts.h create mode 100644 src/osmo-bts-sysmo/femtobts.c create mode 100644 src/osmo-bts-sysmo/femtobts.h create mode 100644 src/osmo-bts-sysmo/sysmo_l1_fwd.c create mode 100644 src/osmo-bts-sysmo/sysmo_l1_hw.c create mode 100644 src/osmo-bts-sysmo/sysmo_l1_if.c create mode 100644 src/osmo-bts-sysmo/sysmo_l1_if.h delete mode 100644 src/sysmo_l1_fwd.c delete mode 100644 src/sysmo_l1_hw.c delete mode 100644 src/sysmo_l1_if.c delete mode 100644 src/sysmo_l1_if.h
diff --git a/src/Makefile.am b/src/Makefile.am index 832c3b0..3049744 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,11 +64,6 @@ bin_PROGRAMS = \
noinst_PROGRAMS =
-if ENABLE_SYSMODSP -noinst_PROGRAMS += \ - osmo-pcu-remote -endif - noinst_HEADERS = \ gprs_debug.h \ csn1.h \ @@ -83,8 +78,6 @@ noinst_HEADERS = \ bitvector.h \ pcu_vty.h \ pcu_vty_functions.h \ - sysmo_l1_if.h \ - femtobts.h \ tbf.h \ bts.h \ poll_controller.h \ @@ -101,30 +94,46 @@ noinst_HEADERS = \ osmo_pcu_SOURCES = pcu_main.cpp
if ENABLE_SYSMODSP -osmo_pcu_SOURCES += sysmo_l1_if.c \ - sysmo_l1_hw.c \ - femtobts.c - -osmo_pcu_remote_SOURCES = pcu_main.cpp \ - sysmo_l1_if.c \ - sysmo_l1_fwd.c \ - femtobts.c -endif +AM_CPPFLAGS += -I$(srcdir)/osmo-bts-sysmo
-osmo_pcu_LDADD = \ +EXTRA_DIST = \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_if.h \ + osmo-bts-sysmo/sysmo_l1_hw.c \ + osmo-bts-sysmo/femtobts.c \ + osmo-bts-sysmo/femtobts.h + +noinst_HEADERS += \ + osmo-bts-sysmo/sysmo_l1_if.h \ + osmo-bts-sysmo/femtobts.h + +noinst_PROGRAMS += \ + osmo-pcu-remote + +osmo_pcu_SOURCES += \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_hw.c \ + osmo-bts-sysmo/femtobts.c + +osmo_pcu_remote_SOURCES = \ + pcu_main.cpp \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_fwd.c \ + osmo-bts-sysmo/femtobts.c + +osmo_pcu_remote_LDADD = \ libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(COMMON_LA) +endif
-if ENABLE_SYSMODSP -osmo_pcu_remote_LDADD = \ +osmo_pcu_LDADD = \ libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(COMMON_LA) -endif
#MOSTLYCLEANFILES += testSource testDestination diff --git a/src/femtobts.c b/src/femtobts.c deleted file mode 100644 index f6957d2..0000000 --- a/src/femtobts.c +++ /dev/null @@ -1,275 +0,0 @@ -/* sysmocom femtobts L1 API related definitions */ - -/* (C) 2011 by Harald Welte laforge@gnumonks.org - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -#include <sysmocom/femtobts/superfemto.h> -#include <sysmocom/femtobts/gsml1const.h> -#include <sysmocom/femtobts/gsml1dbg.h> - -#include "femtobts.h" - -const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM] = { - [GsmL1_PrimId_MphInitReq] = L1P_T_REQ, - [GsmL1_PrimId_MphCloseReq] = L1P_T_REQ, - [GsmL1_PrimId_MphConnectReq] = L1P_T_REQ, - [GsmL1_PrimId_MphDisconnectReq] = L1P_T_REQ, - [GsmL1_PrimId_MphActivateReq] = L1P_T_REQ, - [GsmL1_PrimId_MphDeactivateReq] = L1P_T_REQ, - [GsmL1_PrimId_MphConfigReq] = L1P_T_REQ, - [GsmL1_PrimId_MphMeasureReq] = L1P_T_REQ, - [GsmL1_PrimId_MphInitCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphCloseCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphConnectCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphDisconnectCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphActivateCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphDeactivateCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphConfigCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphMeasureCnf] = L1P_T_CONF, - [GsmL1_PrimId_MphTimeInd] = L1P_T_IND, - [GsmL1_PrimId_MphSyncInd] = L1P_T_IND, - [GsmL1_PrimId_PhEmptyFrameReq] = L1P_T_REQ, - [GsmL1_PrimId_PhDataReq] = L1P_T_REQ, - [GsmL1_PrimId_PhConnectInd] = L1P_T_IND, - [GsmL1_PrimId_PhReadyToSendInd] = L1P_T_IND, - [GsmL1_PrimId_PhDataInd] = L1P_T_IND, - [GsmL1_PrimId_PhRaInd] = L1P_T_IND, -}; - -const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1] = { - { GsmL1_PrimId_MphInitReq, "MPH-INIT.req" }, - { GsmL1_PrimId_MphCloseReq, "MPH-CLOSE.req" }, - { GsmL1_PrimId_MphConnectReq, "MPH-CONNECT.req" }, - { GsmL1_PrimId_MphDisconnectReq,"MPH-DISCONNECT.req" }, - { GsmL1_PrimId_MphActivateReq, "MPH-ACTIVATE.req" }, - { GsmL1_PrimId_MphDeactivateReq,"MPH-DEACTIVATE.req" }, - { GsmL1_PrimId_MphConfigReq, "MPH-CONFIG.req" }, - { GsmL1_PrimId_MphMeasureReq, "MPH-MEASURE.req" }, - { GsmL1_PrimId_MphInitCnf, "MPH-INIT.conf" }, - { GsmL1_PrimId_MphCloseCnf, "MPH-CLOSE.conf" }, - { GsmL1_PrimId_MphConnectCnf, "MPH-CONNECT.conf" }, - { GsmL1_PrimId_MphDisconnectCnf,"MPH-DISCONNECT.conf" }, - { GsmL1_PrimId_MphActivateCnf, "MPH-ACTIVATE.conf" }, - { GsmL1_PrimId_MphDeactivateCnf,"MPH-DEACTIVATE.conf" }, - { GsmL1_PrimId_MphConfigCnf, "MPH-CONFIG.conf" }, - { GsmL1_PrimId_MphMeasureCnf, "MPH-MEASURE.conf" }, - { GsmL1_PrimId_MphTimeInd, "MPH-TIME.ind" }, - { GsmL1_PrimId_MphSyncInd, "MPH-SYNC.ind" }, - { GsmL1_PrimId_PhEmptyFrameReq, "PH-EMPTY_FRAME.req" }, - { GsmL1_PrimId_PhDataReq, "PH-DATA.req" }, - { GsmL1_PrimId_PhConnectInd, "PH-CONNECT.ind" }, - { GsmL1_PrimId_PhReadyToSendInd,"PH-READY_TO_SEND.ind" }, - { GsmL1_PrimId_PhDataInd, "PH-DATA.ind" }, - { GsmL1_PrimId_PhRaInd, "PH-RA.ind" }, - { 0, NULL } -}; - -const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM] = { - [GsmL1_PrimId_MphInitReq] = GsmL1_PrimId_MphInitCnf, - [GsmL1_PrimId_MphCloseReq] = GsmL1_PrimId_MphCloseCnf, - [GsmL1_PrimId_MphConnectReq] = GsmL1_PrimId_MphConnectCnf, - [GsmL1_PrimId_MphDisconnectReq] = GsmL1_PrimId_MphDisconnectCnf, - [GsmL1_PrimId_MphActivateReq] = GsmL1_PrimId_MphActivateCnf, - [GsmL1_PrimId_MphDeactivateReq] = GsmL1_PrimId_MphDeactivateCnf, - [GsmL1_PrimId_MphConfigReq] = GsmL1_PrimId_MphConfigCnf, - [GsmL1_PrimId_MphMeasureReq] = GsmL1_PrimId_MphMeasureCnf, -}; - -const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = { - [SuperFemto_PrimId_SystemInfoReq] = L1P_T_REQ, - [SuperFemto_PrimId_SystemInfoCnf] = L1P_T_CONF, - [SuperFemto_PrimId_SystemFailureInd] = L1P_T_IND, - [SuperFemto_PrimId_ActivateRfReq] = L1P_T_REQ, - [SuperFemto_PrimId_ActivateRfCnf] = L1P_T_CONF, - [SuperFemto_PrimId_DeactivateRfReq] = L1P_T_REQ, - [SuperFemto_PrimId_DeactivateRfCnf] = L1P_T_CONF, - [SuperFemto_PrimId_SetTraceFlagsReq] = L1P_T_REQ, - [SuperFemto_PrimId_RfClockInfoReq] = L1P_T_REQ, - [SuperFemto_PrimId_RfClockInfoCnf] = L1P_T_CONF, - [SuperFemto_PrimId_RfClockSetupReq] = L1P_T_REQ, - [SuperFemto_PrimId_RfClockSetupCnf] = L1P_T_CONF, - [SuperFemto_PrimId_Layer1ResetReq] = L1P_T_REQ, - [SuperFemto_PrimId_Layer1ResetCnf] = L1P_T_CONF, -}; - -const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = { - { SuperFemto_PrimId_SystemInfoReq, "SYSTEM-INFO.req" }, - { SuperFemto_PrimId_SystemInfoCnf, "SYSTEM-INFO.conf" }, - { SuperFemto_PrimId_SystemFailureInd, "SYSTEM-FAILURE.ind" }, - { SuperFemto_PrimId_ActivateRfReq, "ACTIVATE-RF.req" }, - { SuperFemto_PrimId_ActivateRfCnf, "ACTIVATE-RF.conf" }, - { SuperFemto_PrimId_DeactivateRfReq, "DEACTIVATE-RF.req" }, - { SuperFemto_PrimId_DeactivateRfCnf, "DEACTIVATE-RF.conf" }, - { SuperFemto_PrimId_SetTraceFlagsReq, "SET-TRACE-FLAGS.req" }, - { SuperFemto_PrimId_RfClockInfoReq, "RF-CLOCK-INFO.req" }, - { SuperFemto_PrimId_RfClockInfoCnf, "RF-CLOCK-INFO.conf" }, - { SuperFemto_PrimId_RfClockSetupReq, "RF-CLOCK-SETUP.req" }, - { SuperFemto_PrimId_RfClockSetupCnf, "RF-CLOCK-SETUP.conf" }, - { SuperFemto_PrimId_Layer1ResetReq, "LAYER1-RESET.req" }, - { SuperFemto_PrimId_Layer1ResetCnf, "LAYER1-RESET.conf" }, - { 0, NULL } -}; - -const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = { - [SuperFemto_PrimId_SystemInfoReq] = SuperFemto_PrimId_SystemInfoCnf, - [SuperFemto_PrimId_ActivateRfReq] = SuperFemto_PrimId_ActivateRfCnf, - [SuperFemto_PrimId_DeactivateRfReq] = SuperFemto_PrimId_DeactivateRfCnf, - [SuperFemto_PrimId_RfClockInfoReq] = SuperFemto_PrimId_RfClockInfoCnf, - [SuperFemto_PrimId_RfClockSetupReq] = SuperFemto_PrimId_RfClockSetupCnf, - [SuperFemto_PrimId_Layer1ResetReq] = SuperFemto_PrimId_Layer1ResetCnf, -}; - -const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = { - { GsmL1_Sapi_Fcch, "FCCH" }, - { GsmL1_Sapi_Sch, "SCH" }, - { GsmL1_Sapi_Sacch, "SACCH" }, - { GsmL1_Sapi_Sdcch, "SDCCH" }, - { GsmL1_Sapi_Bcch, "BCCH" }, - { GsmL1_Sapi_Pch, "PCH" }, - { GsmL1_Sapi_Agch, "AGCH" }, - { GsmL1_Sapi_Cbch, "CBCH" }, - { GsmL1_Sapi_Rach, "RACH" }, - { GsmL1_Sapi_TchF, "TCH/F" }, - { GsmL1_Sapi_FacchF, "FACCH/F" }, - { GsmL1_Sapi_TchH, "TCH/H" }, - { GsmL1_Sapi_FacchH, "FACCH/H" }, - { GsmL1_Sapi_Nch, "NCH" }, - { GsmL1_Sapi_Pdtch, "PDTCH" }, - { GsmL1_Sapi_Pacch, "PACCH" }, - { GsmL1_Sapi_Pbcch, "PBCCH" }, - { GsmL1_Sapi_Pagch, "PAGCH" }, - { GsmL1_Sapi_Ppch, "PPCH" }, - { GsmL1_Sapi_Pnch, "PNCH" }, - { GsmL1_Sapi_Ptcch, "PTCCH" }, - { GsmL1_Sapi_Prach, "PRACH" }, - { 0, NULL } -}; - -const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1] = { - { GsmL1_Status_Success, "Success" }, - { GsmL1_Status_Generic, "Generic error" }, - { GsmL1_Status_NoMemory, "Not enough memory" }, - { GsmL1_Status_Timeout, "Timeout" }, - { GsmL1_Status_InvalidParam, "Invalid parameter" }, - { GsmL1_Status_Busy, "Resource busy" }, - { GsmL1_Status_NoRessource, "No more resources" }, - { GsmL1_Status_Uninitialized, "Trying to use uninitialized resource" }, - { GsmL1_Status_NullInterface, "Trying to call a NULL interface" }, - { GsmL1_Status_NullFctnPtr, "Trying to call a NULL function ptr" }, - { GsmL1_Status_BadCrc, "Bad CRC" }, - { GsmL1_Status_BadUsf, "Bad USF" }, - { GsmL1_Status_InvalidCPS, "Invalid CPS field" }, - { GsmL1_Status_UnexpectedBurst, "Unexpected burst" }, - { GsmL1_Status_UnavailCodec, "AMR codec is unavailable" }, - { GsmL1_Status_CriticalError, "Critical error" }, - { GsmL1_Status_OverheatError, "Overheat error" }, - { GsmL1_Status_DeviceError, "Device error" }, - { GsmL1_Status_FacchError, "FACCH / TCH order error" }, - { GsmL1_Status_AlreadyDeactivated, "Lchan already deactivated" }, - { GsmL1_Status_TxBurstFifoOvrn, "FIFO overrun" }, - { GsmL1_Status_TxBurstFifoUndr, "FIFO underrun" }, - { GsmL1_Status_NotSynchronized, "Not synchronized" }, - { GsmL1_Status_Unsupported, "Unsupported feature" }, - { 0, NULL } -}; - -const struct value_string femtobts_tracef_names[29] = { - { DBG_DEBUG, "DEBUG" }, - { DBG_L1WARNING, "L1_WARNING" }, - { DBG_ERROR, "ERROR" }, - { DBG_L1RXMSG, "L1_RX_MSG" }, - { DBG_L1RXMSGBYTE, "L1_RX_MSG_BYTE" }, - { DBG_L1TXMSG, "L1_TX_MSG" }, - { DBG_L1TXMSGBYTE, "L1_TX_MSG_BYTE" }, - { DBG_MPHCNF, "MPH_CNF" }, - { DBG_MPHIND, "MPH_IND" }, - { DBG_MPHREQ, "MPH_REQ" }, - { DBG_PHIND, "PH_IND" }, - { DBG_PHREQ, "PH_REQ" }, - { DBG_PHYRF, "PHY_RF" }, - { DBG_PHYRFMSGBYTE, "PHY_MSG_BYTE" }, - { DBG_MODE, "MODE" }, - { DBG_TDMAINFO, "TDMA_INFO" }, - { DBG_BADCRC, "BAD_CRC" }, - { DBG_PHINDBYTE, "PH_IND_BYTE" }, - { DBG_PHREQBYTE, "PH_REQ_BYTE" }, - { DBG_DEVICEMSG, "DEVICE_MSG" }, - { DBG_RACHINFO, "RACH_INFO" }, - { DBG_LOGCHINFO, "LOG_CH_INFO" }, - { DBG_MEMORY, "MEMORY" }, - { DBG_PROFILING, "PROFILING" }, - { DBG_TESTCOMMENT, "TEST_COMMENT" }, - { DBG_TEST, "TEST" }, - { DBG_STATUS, "STATUS" }, - { 0, NULL } -}; - -const struct value_string femtobts_tch_pl_names[] = { - { GsmL1_TchPlType_NA, "N/A" }, - { GsmL1_TchPlType_Fr, "FR" }, - { GsmL1_TchPlType_Hr, "HR" }, - { GsmL1_TchPlType_Efr, "EFR" }, - { GsmL1_TchPlType_Amr, "AMR(IF2)" }, - { GsmL1_TchPlType_Amr_SidBad, "AMR(SID BAD)" }, - { GsmL1_TchPlType_Amr_Onset, "AMR(ONSET)" }, - { GsmL1_TchPlType_Amr_Ratscch, "AMR(RATSCCH)" }, - { GsmL1_TchPlType_Amr_SidUpdateInH, "AMR(SID_UPDATE INH)" }, - { GsmL1_TchPlType_Amr_SidFirstP1, "AMR(SID_FIRST P1)" }, - { GsmL1_TchPlType_Amr_SidFirstP2, "AMR(SID_FIRST P2)" }, - { GsmL1_TchPlType_Amr_SidFirstInH, "AMR(SID_FIRST INH)" }, - { GsmL1_TchPlType_Amr_RatscchMarker, "AMR(RATSCCH MARK)" }, - { GsmL1_TchPlType_Amr_RatscchData, "AMR(RATSCCH DATA)" }, - { 0, NULL } -}; - -const struct value_string femtobts_dir_names[] = { - { GsmL1_Dir_TxDownlink, "TxDL" }, - { GsmL1_Dir_TxUplink, "TxUL" }, - { GsmL1_Dir_RxUplink, "RxUL" }, - { GsmL1_Dir_RxDownlink, "RxDL" }, - { GsmL1_Dir_TxDownlink|GsmL1_Dir_RxUplink, "BOTH" }, - { 0, NULL } -}; - -const struct value_string femtobts_chcomb_names[] = { - { GsmL1_LogChComb_0, "dummy" }, - { GsmL1_LogChComb_I, "tch_f" }, - { GsmL1_LogChComb_II, "tch_h" }, - { GsmL1_LogChComb_IV, "ccch" }, - { GsmL1_LogChComb_V, "ccch_sdcch4" }, - { GsmL1_LogChComb_VII, "sdcch8" }, - { GsmL1_LogChComb_XIII, "pdtch" }, - { 0, NULL } -}; - -const uint8_t pdch_msu_size[_NUM_PDCH_CS] = { - [PDCH_CS_1] = 23, - [PDCH_CS_2] = 34, - [PDCH_CS_3] = 40, - [PDCH_CS_4] = 54, - [PDCH_MCS_1] = 27, - [PDCH_MCS_2] = 33, - [PDCH_MCS_3] = 42, - [PDCH_MCS_4] = 49, - [PDCH_MCS_5] = 60, - [PDCH_MCS_6] = 78, - [PDCH_MCS_7] = 118, - [PDCH_MCS_8] = 142, - [PDCH_MCS_9] = 154 -}; diff --git a/src/femtobts.h b/src/femtobts.h deleted file mode 100644 index 7e45578..0000000 --- a/src/femtobts.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef FEMTOBTS_H -#define FEMTOBTS_H - -#include <stdlib.h> -#include <osmocom/core/utils.h> - -#include <sysmocom/femtobts/superfemto.h> -#include <sysmocom/femtobts/gsml1const.h> - -#ifdef L1_HAS_RTP_MODE -/* This is temporarily disabled, as AMR has some bugs in RTP mode */ -//#define USE_L1_RTP_MODE /* Tell L1 to use RTP mode */ -#endif - -enum l1prim_type { - L1P_T_REQ, - L1P_T_CONF, - L1P_T_IND, -}; - -const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM]; -const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1]; -const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM]; - -const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM]; -const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1]; -const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM]; - -const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1]; -const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1]; - -const struct value_string femtobts_tracef_names[29]; - -const struct value_string femtobts_tch_pl_names[15]; - -const struct value_string femtobts_dir_names[6]; - -enum pdch_cs { - PDCH_CS_1, - PDCH_CS_2, - PDCH_CS_3, - PDCH_CS_4, - PDCH_MCS_1, - PDCH_MCS_2, - PDCH_MCS_3, - PDCH_MCS_4, - PDCH_MCS_5, - PDCH_MCS_6, - PDCH_MCS_7, - PDCH_MCS_8, - PDCH_MCS_9, - _NUM_PDCH_CS -}; - -const uint8_t pdch_msu_size[_NUM_PDCH_CS]; - -#endif /* FEMTOBTS_H */ diff --git a/src/osmo-bts-sysmo/femtobts.c b/src/osmo-bts-sysmo/femtobts.c new file mode 100644 index 0000000..f6957d2 --- /dev/null +++ b/src/osmo-bts-sysmo/femtobts.c @@ -0,0 +1,275 @@ +/* sysmocom femtobts L1 API related definitions */ + +/* (C) 2011 by Harald Welte laforge@gnumonks.org + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include <sysmocom/femtobts/superfemto.h> +#include <sysmocom/femtobts/gsml1const.h> +#include <sysmocom/femtobts/gsml1dbg.h> + +#include "femtobts.h" + +const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM] = { + [GsmL1_PrimId_MphInitReq] = L1P_T_REQ, + [GsmL1_PrimId_MphCloseReq] = L1P_T_REQ, + [GsmL1_PrimId_MphConnectReq] = L1P_T_REQ, + [GsmL1_PrimId_MphDisconnectReq] = L1P_T_REQ, + [GsmL1_PrimId_MphActivateReq] = L1P_T_REQ, + [GsmL1_PrimId_MphDeactivateReq] = L1P_T_REQ, + [GsmL1_PrimId_MphConfigReq] = L1P_T_REQ, + [GsmL1_PrimId_MphMeasureReq] = L1P_T_REQ, + [GsmL1_PrimId_MphInitCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphCloseCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphConnectCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphDisconnectCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphActivateCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphDeactivateCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphConfigCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphMeasureCnf] = L1P_T_CONF, + [GsmL1_PrimId_MphTimeInd] = L1P_T_IND, + [GsmL1_PrimId_MphSyncInd] = L1P_T_IND, + [GsmL1_PrimId_PhEmptyFrameReq] = L1P_T_REQ, + [GsmL1_PrimId_PhDataReq] = L1P_T_REQ, + [GsmL1_PrimId_PhConnectInd] = L1P_T_IND, + [GsmL1_PrimId_PhReadyToSendInd] = L1P_T_IND, + [GsmL1_PrimId_PhDataInd] = L1P_T_IND, + [GsmL1_PrimId_PhRaInd] = L1P_T_IND, +}; + +const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1] = { + { GsmL1_PrimId_MphInitReq, "MPH-INIT.req" }, + { GsmL1_PrimId_MphCloseReq, "MPH-CLOSE.req" }, + { GsmL1_PrimId_MphConnectReq, "MPH-CONNECT.req" }, + { GsmL1_PrimId_MphDisconnectReq,"MPH-DISCONNECT.req" }, + { GsmL1_PrimId_MphActivateReq, "MPH-ACTIVATE.req" }, + { GsmL1_PrimId_MphDeactivateReq,"MPH-DEACTIVATE.req" }, + { GsmL1_PrimId_MphConfigReq, "MPH-CONFIG.req" }, + { GsmL1_PrimId_MphMeasureReq, "MPH-MEASURE.req" }, + { GsmL1_PrimId_MphInitCnf, "MPH-INIT.conf" }, + { GsmL1_PrimId_MphCloseCnf, "MPH-CLOSE.conf" }, + { GsmL1_PrimId_MphConnectCnf, "MPH-CONNECT.conf" }, + { GsmL1_PrimId_MphDisconnectCnf,"MPH-DISCONNECT.conf" }, + { GsmL1_PrimId_MphActivateCnf, "MPH-ACTIVATE.conf" }, + { GsmL1_PrimId_MphDeactivateCnf,"MPH-DEACTIVATE.conf" }, + { GsmL1_PrimId_MphConfigCnf, "MPH-CONFIG.conf" }, + { GsmL1_PrimId_MphMeasureCnf, "MPH-MEASURE.conf" }, + { GsmL1_PrimId_MphTimeInd, "MPH-TIME.ind" }, + { GsmL1_PrimId_MphSyncInd, "MPH-SYNC.ind" }, + { GsmL1_PrimId_PhEmptyFrameReq, "PH-EMPTY_FRAME.req" }, + { GsmL1_PrimId_PhDataReq, "PH-DATA.req" }, + { GsmL1_PrimId_PhConnectInd, "PH-CONNECT.ind" }, + { GsmL1_PrimId_PhReadyToSendInd,"PH-READY_TO_SEND.ind" }, + { GsmL1_PrimId_PhDataInd, "PH-DATA.ind" }, + { GsmL1_PrimId_PhRaInd, "PH-RA.ind" }, + { 0, NULL } +}; + +const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM] = { + [GsmL1_PrimId_MphInitReq] = GsmL1_PrimId_MphInitCnf, + [GsmL1_PrimId_MphCloseReq] = GsmL1_PrimId_MphCloseCnf, + [GsmL1_PrimId_MphConnectReq] = GsmL1_PrimId_MphConnectCnf, + [GsmL1_PrimId_MphDisconnectReq] = GsmL1_PrimId_MphDisconnectCnf, + [GsmL1_PrimId_MphActivateReq] = GsmL1_PrimId_MphActivateCnf, + [GsmL1_PrimId_MphDeactivateReq] = GsmL1_PrimId_MphDeactivateCnf, + [GsmL1_PrimId_MphConfigReq] = GsmL1_PrimId_MphConfigCnf, + [GsmL1_PrimId_MphMeasureReq] = GsmL1_PrimId_MphMeasureCnf, +}; + +const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = { + [SuperFemto_PrimId_SystemInfoReq] = L1P_T_REQ, + [SuperFemto_PrimId_SystemInfoCnf] = L1P_T_CONF, + [SuperFemto_PrimId_SystemFailureInd] = L1P_T_IND, + [SuperFemto_PrimId_ActivateRfReq] = L1P_T_REQ, + [SuperFemto_PrimId_ActivateRfCnf] = L1P_T_CONF, + [SuperFemto_PrimId_DeactivateRfReq] = L1P_T_REQ, + [SuperFemto_PrimId_DeactivateRfCnf] = L1P_T_CONF, + [SuperFemto_PrimId_SetTraceFlagsReq] = L1P_T_REQ, + [SuperFemto_PrimId_RfClockInfoReq] = L1P_T_REQ, + [SuperFemto_PrimId_RfClockInfoCnf] = L1P_T_CONF, + [SuperFemto_PrimId_RfClockSetupReq] = L1P_T_REQ, + [SuperFemto_PrimId_RfClockSetupCnf] = L1P_T_CONF, + [SuperFemto_PrimId_Layer1ResetReq] = L1P_T_REQ, + [SuperFemto_PrimId_Layer1ResetCnf] = L1P_T_CONF, +}; + +const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = { + { SuperFemto_PrimId_SystemInfoReq, "SYSTEM-INFO.req" }, + { SuperFemto_PrimId_SystemInfoCnf, "SYSTEM-INFO.conf" }, + { SuperFemto_PrimId_SystemFailureInd, "SYSTEM-FAILURE.ind" }, + { SuperFemto_PrimId_ActivateRfReq, "ACTIVATE-RF.req" }, + { SuperFemto_PrimId_ActivateRfCnf, "ACTIVATE-RF.conf" }, + { SuperFemto_PrimId_DeactivateRfReq, "DEACTIVATE-RF.req" }, + { SuperFemto_PrimId_DeactivateRfCnf, "DEACTIVATE-RF.conf" }, + { SuperFemto_PrimId_SetTraceFlagsReq, "SET-TRACE-FLAGS.req" }, + { SuperFemto_PrimId_RfClockInfoReq, "RF-CLOCK-INFO.req" }, + { SuperFemto_PrimId_RfClockInfoCnf, "RF-CLOCK-INFO.conf" }, + { SuperFemto_PrimId_RfClockSetupReq, "RF-CLOCK-SETUP.req" }, + { SuperFemto_PrimId_RfClockSetupCnf, "RF-CLOCK-SETUP.conf" }, + { SuperFemto_PrimId_Layer1ResetReq, "LAYER1-RESET.req" }, + { SuperFemto_PrimId_Layer1ResetCnf, "LAYER1-RESET.conf" }, + { 0, NULL } +}; + +const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = { + [SuperFemto_PrimId_SystemInfoReq] = SuperFemto_PrimId_SystemInfoCnf, + [SuperFemto_PrimId_ActivateRfReq] = SuperFemto_PrimId_ActivateRfCnf, + [SuperFemto_PrimId_DeactivateRfReq] = SuperFemto_PrimId_DeactivateRfCnf, + [SuperFemto_PrimId_RfClockInfoReq] = SuperFemto_PrimId_RfClockInfoCnf, + [SuperFemto_PrimId_RfClockSetupReq] = SuperFemto_PrimId_RfClockSetupCnf, + [SuperFemto_PrimId_Layer1ResetReq] = SuperFemto_PrimId_Layer1ResetCnf, +}; + +const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = { + { GsmL1_Sapi_Fcch, "FCCH" }, + { GsmL1_Sapi_Sch, "SCH" }, + { GsmL1_Sapi_Sacch, "SACCH" }, + { GsmL1_Sapi_Sdcch, "SDCCH" }, + { GsmL1_Sapi_Bcch, "BCCH" }, + { GsmL1_Sapi_Pch, "PCH" }, + { GsmL1_Sapi_Agch, "AGCH" }, + { GsmL1_Sapi_Cbch, "CBCH" }, + { GsmL1_Sapi_Rach, "RACH" }, + { GsmL1_Sapi_TchF, "TCH/F" }, + { GsmL1_Sapi_FacchF, "FACCH/F" }, + { GsmL1_Sapi_TchH, "TCH/H" }, + { GsmL1_Sapi_FacchH, "FACCH/H" }, + { GsmL1_Sapi_Nch, "NCH" }, + { GsmL1_Sapi_Pdtch, "PDTCH" }, + { GsmL1_Sapi_Pacch, "PACCH" }, + { GsmL1_Sapi_Pbcch, "PBCCH" }, + { GsmL1_Sapi_Pagch, "PAGCH" }, + { GsmL1_Sapi_Ppch, "PPCH" }, + { GsmL1_Sapi_Pnch, "PNCH" }, + { GsmL1_Sapi_Ptcch, "PTCCH" }, + { GsmL1_Sapi_Prach, "PRACH" }, + { 0, NULL } +}; + +const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1] = { + { GsmL1_Status_Success, "Success" }, + { GsmL1_Status_Generic, "Generic error" }, + { GsmL1_Status_NoMemory, "Not enough memory" }, + { GsmL1_Status_Timeout, "Timeout" }, + { GsmL1_Status_InvalidParam, "Invalid parameter" }, + { GsmL1_Status_Busy, "Resource busy" }, + { GsmL1_Status_NoRessource, "No more resources" }, + { GsmL1_Status_Uninitialized, "Trying to use uninitialized resource" }, + { GsmL1_Status_NullInterface, "Trying to call a NULL interface" }, + { GsmL1_Status_NullFctnPtr, "Trying to call a NULL function ptr" }, + { GsmL1_Status_BadCrc, "Bad CRC" }, + { GsmL1_Status_BadUsf, "Bad USF" }, + { GsmL1_Status_InvalidCPS, "Invalid CPS field" }, + { GsmL1_Status_UnexpectedBurst, "Unexpected burst" }, + { GsmL1_Status_UnavailCodec, "AMR codec is unavailable" }, + { GsmL1_Status_CriticalError, "Critical error" }, + { GsmL1_Status_OverheatError, "Overheat error" }, + { GsmL1_Status_DeviceError, "Device error" }, + { GsmL1_Status_FacchError, "FACCH / TCH order error" }, + { GsmL1_Status_AlreadyDeactivated, "Lchan already deactivated" }, + { GsmL1_Status_TxBurstFifoOvrn, "FIFO overrun" }, + { GsmL1_Status_TxBurstFifoUndr, "FIFO underrun" }, + { GsmL1_Status_NotSynchronized, "Not synchronized" }, + { GsmL1_Status_Unsupported, "Unsupported feature" }, + { 0, NULL } +}; + +const struct value_string femtobts_tracef_names[29] = { + { DBG_DEBUG, "DEBUG" }, + { DBG_L1WARNING, "L1_WARNING" }, + { DBG_ERROR, "ERROR" }, + { DBG_L1RXMSG, "L1_RX_MSG" }, + { DBG_L1RXMSGBYTE, "L1_RX_MSG_BYTE" }, + { DBG_L1TXMSG, "L1_TX_MSG" }, + { DBG_L1TXMSGBYTE, "L1_TX_MSG_BYTE" }, + { DBG_MPHCNF, "MPH_CNF" }, + { DBG_MPHIND, "MPH_IND" }, + { DBG_MPHREQ, "MPH_REQ" }, + { DBG_PHIND, "PH_IND" }, + { DBG_PHREQ, "PH_REQ" }, + { DBG_PHYRF, "PHY_RF" }, + { DBG_PHYRFMSGBYTE, "PHY_MSG_BYTE" }, + { DBG_MODE, "MODE" }, + { DBG_TDMAINFO, "TDMA_INFO" }, + { DBG_BADCRC, "BAD_CRC" }, + { DBG_PHINDBYTE, "PH_IND_BYTE" }, + { DBG_PHREQBYTE, "PH_REQ_BYTE" }, + { DBG_DEVICEMSG, "DEVICE_MSG" }, + { DBG_RACHINFO, "RACH_INFO" }, + { DBG_LOGCHINFO, "LOG_CH_INFO" }, + { DBG_MEMORY, "MEMORY" }, + { DBG_PROFILING, "PROFILING" }, + { DBG_TESTCOMMENT, "TEST_COMMENT" }, + { DBG_TEST, "TEST" }, + { DBG_STATUS, "STATUS" }, + { 0, NULL } +}; + +const struct value_string femtobts_tch_pl_names[] = { + { GsmL1_TchPlType_NA, "N/A" }, + { GsmL1_TchPlType_Fr, "FR" }, + { GsmL1_TchPlType_Hr, "HR" }, + { GsmL1_TchPlType_Efr, "EFR" }, + { GsmL1_TchPlType_Amr, "AMR(IF2)" }, + { GsmL1_TchPlType_Amr_SidBad, "AMR(SID BAD)" }, + { GsmL1_TchPlType_Amr_Onset, "AMR(ONSET)" }, + { GsmL1_TchPlType_Amr_Ratscch, "AMR(RATSCCH)" }, + { GsmL1_TchPlType_Amr_SidUpdateInH, "AMR(SID_UPDATE INH)" }, + { GsmL1_TchPlType_Amr_SidFirstP1, "AMR(SID_FIRST P1)" }, + { GsmL1_TchPlType_Amr_SidFirstP2, "AMR(SID_FIRST P2)" }, + { GsmL1_TchPlType_Amr_SidFirstInH, "AMR(SID_FIRST INH)" }, + { GsmL1_TchPlType_Amr_RatscchMarker, "AMR(RATSCCH MARK)" }, + { GsmL1_TchPlType_Amr_RatscchData, "AMR(RATSCCH DATA)" }, + { 0, NULL } +}; + +const struct value_string femtobts_dir_names[] = { + { GsmL1_Dir_TxDownlink, "TxDL" }, + { GsmL1_Dir_TxUplink, "TxUL" }, + { GsmL1_Dir_RxUplink, "RxUL" }, + { GsmL1_Dir_RxDownlink, "RxDL" }, + { GsmL1_Dir_TxDownlink|GsmL1_Dir_RxUplink, "BOTH" }, + { 0, NULL } +}; + +const struct value_string femtobts_chcomb_names[] = { + { GsmL1_LogChComb_0, "dummy" }, + { GsmL1_LogChComb_I, "tch_f" }, + { GsmL1_LogChComb_II, "tch_h" }, + { GsmL1_LogChComb_IV, "ccch" }, + { GsmL1_LogChComb_V, "ccch_sdcch4" }, + { GsmL1_LogChComb_VII, "sdcch8" }, + { GsmL1_LogChComb_XIII, "pdtch" }, + { 0, NULL } +}; + +const uint8_t pdch_msu_size[_NUM_PDCH_CS] = { + [PDCH_CS_1] = 23, + [PDCH_CS_2] = 34, + [PDCH_CS_3] = 40, + [PDCH_CS_4] = 54, + [PDCH_MCS_1] = 27, + [PDCH_MCS_2] = 33, + [PDCH_MCS_3] = 42, + [PDCH_MCS_4] = 49, + [PDCH_MCS_5] = 60, + [PDCH_MCS_6] = 78, + [PDCH_MCS_7] = 118, + [PDCH_MCS_8] = 142, + [PDCH_MCS_9] = 154 +}; diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h new file mode 100644 index 0000000..7e45578 --- /dev/null +++ b/src/osmo-bts-sysmo/femtobts.h @@ -0,0 +1,57 @@ +#ifndef FEMTOBTS_H +#define FEMTOBTS_H + +#include <stdlib.h> +#include <osmocom/core/utils.h> + +#include <sysmocom/femtobts/superfemto.h> +#include <sysmocom/femtobts/gsml1const.h> + +#ifdef L1_HAS_RTP_MODE +/* This is temporarily disabled, as AMR has some bugs in RTP mode */ +//#define USE_L1_RTP_MODE /* Tell L1 to use RTP mode */ +#endif + +enum l1prim_type { + L1P_T_REQ, + L1P_T_CONF, + L1P_T_IND, +}; + +const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM]; +const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1]; +const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM]; + +const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM]; +const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1]; +const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM]; + +const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1]; +const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1]; + +const struct value_string femtobts_tracef_names[29]; + +const struct value_string femtobts_tch_pl_names[15]; + +const struct value_string femtobts_dir_names[6]; + +enum pdch_cs { + PDCH_CS_1, + PDCH_CS_2, + PDCH_CS_3, + PDCH_CS_4, + PDCH_MCS_1, + PDCH_MCS_2, + PDCH_MCS_3, + PDCH_MCS_4, + PDCH_MCS_5, + PDCH_MCS_6, + PDCH_MCS_7, + PDCH_MCS_8, + PDCH_MCS_9, + _NUM_PDCH_CS +}; + +const uint8_t pdch_msu_size[_NUM_PDCH_CS]; + +#endif /* FEMTOBTS_H */ diff --git a/src/osmo-bts-sysmo/sysmo_l1_fwd.c b/src/osmo-bts-sysmo/sysmo_l1_fwd.c new file mode 100644 index 0000000..535a7f0 --- /dev/null +++ b/src/osmo-bts-sysmo/sysmo_l1_fwd.c @@ -0,0 +1,145 @@ +/* Interface handler for Sysmocom L1 (forwarding) */ + +/* (C) 2011 by Harald Welte laforge@gnumonks.org + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/select.h> +#include <osmocom/core/write_queue.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/timer.h> +#include <osmocom/gsm/gsm_utils.h> + +#include <sysmocom/femtobts/superfemto.h> +#include <sysmocom/femtobts/gsml1prim.h> +#include <sysmocom/femtobts/gsml1const.h> +#include <sysmocom/femtobts/gsml1types.h> + +#include "gprs_debug.h" +#include "sysmo_l1_if.h" + + +#define L1FWD_L1_PORT 9999 +#define L1FWD_SYS_PORT 9998 +#define L1FWD_TCH_PORT 9997 +#define L1FWD_PDTCH_PORT 9996 + +static const uint16_t fwd_udp_ports[] = { + [MQ_SYS_WRITE] = L1FWD_SYS_PORT, + [MQ_L1_WRITE] = L1FWD_L1_PORT, + [MQ_TCH_WRITE] = L1FWD_TCH_PORT, + [MQ_PDTCH_WRITE]= L1FWD_PDTCH_PORT, +}; + +static int fwd_read_cb(struct osmo_fd *ofd) +{ + struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128, + 128, "udp_rx"); + struct femtol1_hdl *fl1h = ofd->data; + int rc; + + if (!msg) + return -ENOMEM; + + msg->l1h = msg->data; + rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg)); + if (rc < 0) { + LOGP(DL1IF, LOGL_ERROR, "Short read from UDP\n"); + msgb_free(msg); + return rc; + } else if (rc == 0) { + LOGP(DL1IF, LOGL_ERROR, "Len=0 from UDP\n"); + msgb_free(msg); + return rc; + } + msgb_put(msg, rc); + + if (ofd->priv_nr == MQ_SYS_WRITE) + rc = l1if_handle_sysprim(fl1h, msg); + else + rc = l1if_handle_l1prim(ofd->priv_nr, fl1h, msg); + + return rc; +} + +static int prim_write_cb(struct osmo_fd *ofd, struct msgb *msg) +{ + /* write to the fd */ + return write(ofd->fd, msg->head, msg->len); +} + +int l1if_transport_open(int q, struct femtol1_hdl *fl1h) +{ + int rc; + char *bts_host = getenv("L1FWD_BTS_HOST"); + + printf("sizeof(GsmL1_Prim_t) = %zu\n", sizeof(GsmL1_Prim_t)); + printf("sizeof(SuperFemto_Prim_t) = %zu\n", sizeof(SuperFemto_Prim_t)); + + if (!bts_host) { + fprintf(stderr, "You have to set the L1FWD_BTS_HOST environment variable\n"); + exit(2); + } + + struct osmo_wqueue *wq = &fl1h->write_q[q]; + struct osmo_fd *ofd = &wq->bfd; + + osmo_wqueue_init(wq, 10); + wq->write_cb = prim_write_cb; + wq->read_cb = fwd_read_cb; + + ofd->data = fl1h; + ofd->priv_nr = q; + ofd->when |= BSC_FD_READ; + + rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + bts_host, fwd_udp_ports[q], + OSMO_SOCK_F_CONNECT); + if (rc < 0) + return rc; + + return 0; +} + +int l1if_transport_close(int q, struct femtol1_hdl *fl1h) +{ + struct osmo_wqueue *wq = &fl1h->write_q[q]; + struct osmo_fd *ofd = &wq->bfd; + + osmo_wqueue_clear(wq); + osmo_fd_unregister(ofd); + close(ofd->fd); + + return 0; +} diff --git a/src/osmo-bts-sysmo/sysmo_l1_hw.c b/src/osmo-bts-sysmo/sysmo_l1_hw.c new file mode 100644 index 0000000..8351d68 --- /dev/null +++ b/src/osmo-bts-sysmo/sysmo_l1_hw.c @@ -0,0 +1,216 @@ +/* Interface handler for Sysmocom L1 (real hardware) */ + +/* (C) 2011 by Harald Welte laforge@gnumonks.org + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include <assert.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/select.h> +#include <osmocom/core/write_queue.h> +#include <osmocom/core/timer.h> +#include <osmocom/gsm/gsm_utils.h> + +#include <sysmocom/femtobts/superfemto.h> +#include <sysmocom/femtobts/gsml1prim.h> +#include <sysmocom/femtobts/gsml1const.h> +#include <sysmocom/femtobts/gsml1types.h> + +#include "gprs_debug.h" +#include "femtobts.h" +#include "sysmo_l1_if.h" + + +#ifdef HW_SYSMOBTS_V1 +#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/femtobts_dsp2arm" +#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/femtobts_arm2dsp" +#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_dsp2arm" +#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_arm2dsp" +#else +#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/superfemto_dsp2arm" +#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/superfemto_arm2dsp" +#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_sig_dsp2arm" +#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_sig_arm2dsp" + +#define DEV_TCH_DSP2ARM_NAME "/dev/msgq/gsml1_tch_dsp2arm" +#define DEV_TCH_ARM2DSP_NAME "/dev/msgq/gsml1_tch_arm2dsp" +#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm" +#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp" +#endif + +static const char *rd_devnames[] = { + [MQ_SYS_READ] = DEV_SYS_DSP2ARM_NAME, + [MQ_L1_READ] = DEV_L1_DSP2ARM_NAME, +#ifndef HW_SYSMOBTS_V1 + [MQ_TCH_READ] = DEV_TCH_DSP2ARM_NAME, + [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME, +#endif +}; + +static const char *wr_devnames[] = { + [MQ_SYS_WRITE] = DEV_SYS_ARM2DSP_NAME, + [MQ_L1_WRITE] = DEV_L1_ARM2DSP_NAME, +#ifndef HW_SYSMOBTS_V1 + [MQ_TCH_WRITE] = DEV_TCH_ARM2DSP_NAME, + [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME, +#endif +}; + +/* callback when there's something to read from the l1 msg_queue */ +static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + //struct msgb *msg = l1p_msgb_alloc(); + struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128, + 128, "1l_fd"); + struct femtol1_hdl *fl1h = ofd->data; + int rc; + + msg->l1h = msg->data; + rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg)); + if (rc < 0) { + if (rc != -1) + LOGP(DL1IF, LOGL_ERROR, "error reading from L1 msg_queue: %s\n", + strerror(errno)); + msgb_free(msg); + return rc; + } + msgb_put(msg, rc); + + switch (ofd->priv_nr) { + case MQ_SYS_WRITE: + if (rc != sizeof(SuperFemto_Prim_t)) + LOGP(DL1IF, LOGL_NOTICE, "%u != " + "sizeof(SuperFemto_Prim_t)\n", rc); + return l1if_handle_sysprim(fl1h, msg); + case MQ_L1_WRITE: +#ifndef HW_SYSMOBTS_V1 + case MQ_TCH_WRITE: + case MQ_PDTCH_WRITE: +#endif + if (rc != sizeof(GsmL1_Prim_t)) + LOGP(DL1IF, LOGL_NOTICE, "%u != " + "sizeof(GsmL1_Prim_t)\n", rc); + return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg); + default: + /* The compiler can't know that priv_nr is an enum. Assist. */ + LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n", + ofd->priv_nr); + exit(0); + break; + } +}; + +/* callback when we can write to one of the l1 msg_queue devices */ +static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg) +{ + int rc; + + rc = write(ofd->fd, msg->l1h, msgb_l1len(msg)); + if (rc < 0) { + LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n", + strerror(errno)); + return rc; + } else if (rc < msg->len) { + LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: " + "%u < %u\n", rc, msg->len); + return -EIO; + } + + return 0; +} + +int l1if_transport_open(int q, struct femtol1_hdl *hdl) +{ + int rc; + + /* Step 1: Open all msg_queue file descriptors */ + struct osmo_fd *read_ofd = &hdl->read_ofd[q]; + struct osmo_wqueue *wq = &hdl->write_q[q]; + struct osmo_fd *write_ofd = &hdl->write_q[q].bfd; + + rc = open(rd_devnames[q], O_RDONLY); + if (rc < 0) { + LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n", + strerror(errno)); + return rc; + } + read_ofd->fd = rc; + read_ofd->priv_nr = q; + read_ofd->data = hdl; + read_ofd->cb = l1if_fd_cb; + read_ofd->when = BSC_FD_READ; + rc = osmo_fd_register(read_ofd); + if (rc < 0) { + close(read_ofd->fd); + read_ofd->fd = -1; + return rc; + } + + rc = open(wr_devnames[q], O_WRONLY); + if (rc < 0) { + LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n", + strerror(errno)); + goto out_read; + } + osmo_wqueue_init(wq, 10); + wq->write_cb = l1fd_write_cb; + write_ofd->fd = rc; + write_ofd->priv_nr = q; + write_ofd->data = hdl; + write_ofd->when = BSC_FD_WRITE; + rc = osmo_fd_register(write_ofd); + if (rc < 0) { + close(write_ofd->fd); + write_ofd->fd = -1; + goto out_read; + } + + return 0; + +out_read: + close(hdl->read_ofd[q].fd); + osmo_fd_unregister(&hdl->read_ofd[q]); + + return rc; +} + +int l1if_transport_close(int q, struct femtol1_hdl *hdl) +{ + struct osmo_fd *read_ofd = &hdl->read_ofd[q]; + struct osmo_fd *write_ofd = &hdl->write_q[q].bfd; + + osmo_fd_unregister(read_ofd); + close(read_ofd->fd); + read_ofd->fd = -1; + + osmo_fd_unregister(write_ofd); + close(write_ofd->fd); + write_ofd->fd = -1; + + return 0; +} diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c new file mode 100644 index 0000000..c7c54dd --- /dev/null +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -0,0 +1,394 @@ + +#include <string.h> +#include <errno.h> + +#include <sysmocom/femtobts/superfemto.h> +#include <sysmocom/femtobts/gsml1prim.h> +#include <sysmocom/femtobts/gsml1const.h> +#include <sysmocom/femtobts/gsml1types.h> + +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/timer.h> +#include <sysmo_l1_if.h> +#include <gprs_debug.h> +#include <pcu_l1_if.h> + +extern void *tall_pcu_ctx; + +uint32_t l1if_ts_to_hLayer2(uint8_t trx, uint8_t ts) +{ + return (ts << 16) | (trx << 24); +} + +/* allocate a msgb containing a GsmL1_Prim_t */ +struct msgb *l1p_msgb_alloc(void) +{ + struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim"); + + if (msg) + msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t)); + + return msg; +} + +static int l1if_req_pdch(struct femtol1_hdl *fl1h, struct msgb *msg) +{ + struct osmo_wqueue *wqueue = &fl1h->write_q[MQ_PDTCH_WRITE]; + + if (osmo_wqueue_enqueue(wqueue, msg) != 0) { + LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n"); + msgb_free(msg); + } + + return 0; +} + +static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct femtol1_hdl *gl1) +{ + prim->id = id; + + /* for some reason the hLayer1 field is not always at the same position + * in the GsmL1_Prim_t, so we have to have this ugly case statement here... */ + switch (id) { + case GsmL1_PrimId_MphInitReq: + //prim->u.mphInitReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphCloseReq: + prim->u.mphCloseReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphConnectReq: + prim->u.mphConnectReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphDisconnectReq: + prim->u.mphDisconnectReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphActivateReq: + prim->u.mphActivateReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphDeactivateReq: + prim->u.mphDeactivateReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphConfigReq: + prim->u.mphConfigReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphMeasureReq: + prim->u.mphMeasureReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_MphInitCnf: + case GsmL1_PrimId_MphCloseCnf: + case GsmL1_PrimId_MphConnectCnf: + case GsmL1_PrimId_MphDisconnectCnf: + case GsmL1_PrimId_MphActivateCnf: + case GsmL1_PrimId_MphDeactivateCnf: + case GsmL1_PrimId_MphConfigCnf: + case GsmL1_PrimId_MphMeasureCnf: + break; + case GsmL1_PrimId_MphTimeInd: + break; + case GsmL1_PrimId_MphSyncInd: + break; + case GsmL1_PrimId_PhEmptyFrameReq: + prim->u.phEmptyFrameReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_PhDataReq: + prim->u.phDataReq.hLayer1 = gl1->hLayer1; + break; + case GsmL1_PrimId_PhConnectInd: + break; + case GsmL1_PrimId_PhReadyToSendInd: + break; + case GsmL1_PrimId_PhDataInd: + break; + case GsmL1_PrimId_PhRaInd: + break; + default: + LOGP(DL1IF, LOGL_ERROR, "unknown L1 primitive %u\n", id); + break; + } + return &prim->u; +} + +struct sapi_dir { + GsmL1_Sapi_t sapi; + GsmL1_Dir_t dir; +}; + +static const struct sapi_dir pdtch_sapis[] = { + { GsmL1_Sapi_Pdtch, GsmL1_Dir_TxDownlink }, + { GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink }, + { GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink }, + { GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink }, +#if 0 + { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, + { GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink }, +#endif +}; + + +/* connect PDTCH */ +int l1if_connect_pdch(void *obj, uint8_t ts) +{ + struct femtol1_hdl *fl1h = obj; + struct msgb *msg = l1p_msgb_alloc(); + GsmL1_MphConnectReq_t *cr; + + cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConnectReq, fl1h); + cr->u8Tn = ts; + cr->logChComb = GsmL1_LogChComb_XIII; + + return l1if_req_pdch(fl1h, msg); +} + +static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h, + GsmL1_PhReadyToSendInd_t *rts_ind) +{ + struct gsm_time g_time; + int rc = 0; + + gsm_fn2gsmtime(&g_time, rts_ind->u32Fn); + + DEBUGP(DL1IF, "Rx PH-RTS.ind %02u/%02u/%02u SAPI=%s\n", + g_time.t1, g_time.t2, g_time.t3, + get_value_string(femtobts_l1sapi_names, rts_ind->sapi)); + + switch (rts_ind->sapi) { + case GsmL1_Sapi_Pdtch: + case GsmL1_Sapi_Pacch: + rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn, + rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); + case GsmL1_Sapi_Ptcch: + // FIXME + default: + break; + } + + return rc; +} + +static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t *l1_meas) +{ + meas->rssi = (int8_t) (l1_meas->fRssi); + meas->have_rssi = 1; + meas->ber = (uint8_t) (l1_meas->fBer * 100); + meas->have_ber = 1; + meas->bto = (int16_t) (l1_meas->i16BurstTiming); + meas->have_bto = 1; + meas->link_qual = (int16_t) (l1_meas->fLinkQuality); + meas->have_link_qual = 1; +} + +static int handle_ph_data_ind(struct femtol1_hdl *fl1h, + GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) +{ + int rc = 0; + struct pcu_l1_meas meas = {0}; + + DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n", + get_value_string(femtobts_l1sapi_names, data_ind->sapi), + data_ind->hLayer2, + osmo_hexdump(data_ind->msgUnitParam.u8Buffer, + data_ind->msgUnitParam.u8Size)); + + pcu_rx_block_time(data_ind->u16Arfcn, data_ind->u32Fn, data_ind->u8Tn); + + /* + * TODO: Add proper bad frame handling here. This could be used + * to switch the used CS. Avoid a crash with the PCU right now + * feed "0 - 1" amount of data. + */ + if (data_ind->msgUnitParam.u8Size == 0) + return -1; + + gsmtap_send(fl1h->gsmtap, data_ind->u16Arfcn | GSMTAP_ARFCN_F_UPLINK, + data_ind->u8Tn, GSMTAP_CHANNEL_PACCH, 0, + data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1, + data_ind->msgUnitParam.u8Size-1); + + get_meas(&meas, &data_ind->measParam); + + switch (data_ind->sapi) { + case GsmL1_Sapi_Pdtch: + case GsmL1_Sapi_Pacch: + /* drop incomplete UL block */ + if (data_ind->msgUnitParam.u8Buffer[0] + != GsmL1_PdtchPlType_Full) + break; + /* PDTCH / PACCH frame handling */ + pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn, + data_ind->msgUnitParam.u8Buffer + 1, + data_ind->msgUnitParam.u8Size - 1, + data_ind->u32Fn, + &meas); + break; + case GsmL1_Sapi_Ptcch: + // FIXME + break; + default: + LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n", + get_value_string(femtobts_l1sapi_names, data_ind->sapi)); + break; + } + + return rc; +} + +#define MIN_QUAL_RACH 5.0f + +static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) +{ + uint8_t acc_delay; + + pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn); + + if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) + return 0; + + DEBUGP(DL1IF, "Rx PH-RA.ind"); + + /* check for under/overflow / sign */ + if (ra_ind->measParam.i16BurstTiming < 0) + acc_delay = 0; + else + acc_delay = ra_ind->measParam.i16BurstTiming >> 2; + + LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", + acc_delay); + +#warning "The (P)RACH request is just dropped here" + +#if 0 + if (acc_delay > bts->max_ta) { + LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", + acc_delay, btsb->max_ta); + return 0; + } +#endif + + return 0; +} + + +/* handle any random indication from the L1 */ +int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg) +{ + GsmL1_Prim_t *l1p = msgb_l1prim(msg); + int rc = 0; + + LOGP(DL1IF, LOGL_DEBUG, "Rx L1 prim %s on queue %d\n", + get_value_string(femtobts_l1prim_names, l1p->id), wq); + + switch (l1p->id) { +#if 0 + case GsmL1_PrimId_MphTimeInd: + rc = handle_mph_time_ind(fl1h, &l1p->u.mphTimeInd); + break; + case GsmL1_PrimId_MphSyncInd: + break; + case GsmL1_PrimId_PhConnectInd: + break; +#endif + case GsmL1_PrimId_PhReadyToSendInd: + rc = handle_ph_readytosend_ind(fl1h, &l1p->u.phReadyToSendInd); + break; + case GsmL1_PrimId_PhDataInd: + rc = handle_ph_data_ind(fl1h, &l1p->u.phDataInd, msg); + break; + case GsmL1_PrimId_PhRaInd: + rc = handle_ph_ra_ind(fl1h, &l1p->u.phRaInd); + break; + default: + break; + } + + msgb_free(msg); + + return rc; +} + +int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) +{ + return -ENOTSUP; +} + +/* send packet data request to L1 */ +int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, + uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len) +{ + struct femtol1_hdl *fl1h = obj; + struct msgb *msg; + GsmL1_Prim_t *l1p; + GsmL1_PhDataReq_t *data_req; + GsmL1_MsgUnitParam_t *msu_param; + struct gsm_time g_time; + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1IF, "TX packet data %02u/%02u/%02u is_ptcch=%d ts=%d " + "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2, + g_time.t3, is_ptcch, ts, block_nr, arfcn, len); + + msg = l1p_msgb_alloc(); + l1p = msgb_l1prim(msg); + l1p->id = GsmL1_PrimId_PhDataReq; + data_req = &l1p->u.phDataReq; + data_req->hLayer1 = fl1h->hLayer1; + data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch; + data_req->subCh = GsmL1_SubCh_NA; + data_req->u8BlockNbr = block_nr; + data_req->u8Tn = ts; + data_req->u32Fn = fn; + msu_param = &data_req->msgUnitParam; + msu_param->u8Size = len; + memcpy(msu_param->u8Buffer, data, len); + + gsmtap_send(fl1h->gsmtap, arfcn, data_req->u8Tn, GSMTAP_CHANNEL_PACCH, + 0, data_req->u32Fn, 0, 0, + data_req->msgUnitParam.u8Buffer, + data_req->msgUnitParam.u8Size); + + + /* transmit */ + if (osmo_wqueue_enqueue(&fl1h->write_q[MQ_PDTCH_WRITE], msg) != 0) { + LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n"); + msgb_free(msg); + } + + return 0; +} + +void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) +{ + struct femtol1_hdl *fl1h; + int rc; + + fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl); + if (!fl1h) + return NULL; + + fl1h->hLayer1 = hlayer1; + fl1h->priv = priv; + fl1h->clk_cal = 0; + /* default clock source: OCXO */ + fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo; + + rc = l1if_transport_open(MQ_PDTCH_WRITE, fl1h); + if (rc < 0) { + talloc_free(fl1h); + return NULL; + } + + fl1h->gsmtap = gsmtap; + + return fl1h; +} + +int l1if_close_pdch(void *obj) +{ + struct femtol1_hdl *fl1h = obj; + if (fl1h) + l1if_transport_close(MQ_PDTCH_WRITE, fl1h); + talloc_free(fl1h); + return 0; +} + diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.h b/src/osmo-bts-sysmo/sysmo_l1_if.h new file mode 100644 index 0000000..6b50d4e --- /dev/null +++ b/src/osmo-bts-sysmo/sysmo_l1_if.h @@ -0,0 +1,91 @@ +#ifndef _SYSMO_L1_IF_H +#define _SYSMO_L1_IF_H + +#include <osmocom/core/select.h> +#include <osmocom/core/write_queue.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/gsm/gsm_utils.h> +#include "femtobts.h" + +enum { + MQ_SYS_READ, + MQ_L1_READ, +#ifndef HW_SYSMOBTS_V1 + MQ_TCH_READ, + MQ_PDTCH_READ, +#endif + _NUM_MQ_READ +}; + +enum { + MQ_SYS_WRITE, + MQ_L1_WRITE, +#ifndef HW_SYSMOBTS_V1 + MQ_TCH_WRITE, + MQ_PDTCH_WRITE, +#endif + _NUM_MQ_WRITE +}; + +struct femtol1_hdl { + struct gsm_time gsm_time; + uint32_t hLayer1; /* handle to the L1 instance in the DSP */ + uint32_t dsp_trace_f; + int clk_cal; + uint8_t clk_src; + struct llist_head wlc_list; + + struct gsmtap_inst *gsmtap; + uint32_t gsmtap_sapi_mask; + + void *priv; /* user reference */ + + struct osmo_timer_list alive_timer; + unsigned int alive_prim_cnt; + + struct osmo_fd read_ofd[_NUM_MQ_READ]; /* osmo file descriptors */ + struct osmo_wqueue write_q[_NUM_MQ_WRITE]; + + struct { + uint8_t dsp_version[3]; + uint8_t fpga_version[3]; + uint32_t band_support; /* bitmask of GSM_BAND_* */ + } hw_info; +}; + +#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) +#define msgb_sysprim(msg) ((SuperFemto_Prim_t *)(msg)->l1h) + +typedef int l1if_compl_cb(struct msgb *l1_msg, void *data); + +/* send a request primitive to the L1 and schedule completion call-back */ +int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, + int is_system_prim, l1if_compl_cb *cb, void *data); + +int l1if_reset(struct femtol1_hdl *hdl); +int l1if_activate_rf(struct femtol1_hdl *hdl, int on); +int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags); +int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power); + +struct msgb *l1p_msgb_alloc(void); +struct msgb *sysp_msgb_alloc(void); + +uint32_t l1if_lchan_to_hLayer2(struct gsm_lchan *lchan); +struct gsm_lchan *l1if_hLayer2_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer2); + +int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg); +int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg); + +/* tch.c */ +int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg); +int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); +struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan); + +/* + * The implementation of these functions is selected by either compiling and + * linking sysmo_l1_hw.c or sysmo_l1_fwd.c + */ +int l1if_transport_open(int q, struct femtol1_hdl *hdl); +int l1if_transport_close(int q, struct femtol1_hdl *hdl); + +#endif /* _SYSMO_L1_IF_H */ diff --git a/src/sysmo_l1_fwd.c b/src/sysmo_l1_fwd.c deleted file mode 100644 index 535a7f0..0000000 --- a/src/sysmo_l1_fwd.c +++ /dev/null @@ -1,145 +0,0 @@ -/* Interface handler for Sysmocom L1 (forwarding) */ - -/* (C) 2011 by Harald Welte laforge@gnumonks.org - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/core/utils.h> -#include <osmocom/core/select.h> -#include <osmocom/core/write_queue.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/timer.h> -#include <osmocom/gsm/gsm_utils.h> - -#include <sysmocom/femtobts/superfemto.h> -#include <sysmocom/femtobts/gsml1prim.h> -#include <sysmocom/femtobts/gsml1const.h> -#include <sysmocom/femtobts/gsml1types.h> - -#include "gprs_debug.h" -#include "sysmo_l1_if.h" - - -#define L1FWD_L1_PORT 9999 -#define L1FWD_SYS_PORT 9998 -#define L1FWD_TCH_PORT 9997 -#define L1FWD_PDTCH_PORT 9996 - -static const uint16_t fwd_udp_ports[] = { - [MQ_SYS_WRITE] = L1FWD_SYS_PORT, - [MQ_L1_WRITE] = L1FWD_L1_PORT, - [MQ_TCH_WRITE] = L1FWD_TCH_PORT, - [MQ_PDTCH_WRITE]= L1FWD_PDTCH_PORT, -}; - -static int fwd_read_cb(struct osmo_fd *ofd) -{ - struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128, - 128, "udp_rx"); - struct femtol1_hdl *fl1h = ofd->data; - int rc; - - if (!msg) - return -ENOMEM; - - msg->l1h = msg->data; - rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg)); - if (rc < 0) { - LOGP(DL1IF, LOGL_ERROR, "Short read from UDP\n"); - msgb_free(msg); - return rc; - } else if (rc == 0) { - LOGP(DL1IF, LOGL_ERROR, "Len=0 from UDP\n"); - msgb_free(msg); - return rc; - } - msgb_put(msg, rc); - - if (ofd->priv_nr == MQ_SYS_WRITE) - rc = l1if_handle_sysprim(fl1h, msg); - else - rc = l1if_handle_l1prim(ofd->priv_nr, fl1h, msg); - - return rc; -} - -static int prim_write_cb(struct osmo_fd *ofd, struct msgb *msg) -{ - /* write to the fd */ - return write(ofd->fd, msg->head, msg->len); -} - -int l1if_transport_open(int q, struct femtol1_hdl *fl1h) -{ - int rc; - char *bts_host = getenv("L1FWD_BTS_HOST"); - - printf("sizeof(GsmL1_Prim_t) = %zu\n", sizeof(GsmL1_Prim_t)); - printf("sizeof(SuperFemto_Prim_t) = %zu\n", sizeof(SuperFemto_Prim_t)); - - if (!bts_host) { - fprintf(stderr, "You have to set the L1FWD_BTS_HOST environment variable\n"); - exit(2); - } - - struct osmo_wqueue *wq = &fl1h->write_q[q]; - struct osmo_fd *ofd = &wq->bfd; - - osmo_wqueue_init(wq, 10); - wq->write_cb = prim_write_cb; - wq->read_cb = fwd_read_cb; - - ofd->data = fl1h; - ofd->priv_nr = q; - ofd->when |= BSC_FD_READ; - - rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, - bts_host, fwd_udp_ports[q], - OSMO_SOCK_F_CONNECT); - if (rc < 0) - return rc; - - return 0; -} - -int l1if_transport_close(int q, struct femtol1_hdl *fl1h) -{ - struct osmo_wqueue *wq = &fl1h->write_q[q]; - struct osmo_fd *ofd = &wq->bfd; - - osmo_wqueue_clear(wq); - osmo_fd_unregister(ofd); - close(ofd->fd); - - return 0; -} diff --git a/src/sysmo_l1_hw.c b/src/sysmo_l1_hw.c deleted file mode 100644 index 8351d68..0000000 --- a/src/sysmo_l1_hw.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Interface handler for Sysmocom L1 (real hardware) */ - -/* (C) 2011 by Harald Welte laforge@gnumonks.org - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -#include <assert.h> -#include <stdint.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> - -#include <sys/types.h> -#include <sys/stat.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/core/utils.h> -#include <osmocom/core/select.h> -#include <osmocom/core/write_queue.h> -#include <osmocom/core/timer.h> -#include <osmocom/gsm/gsm_utils.h> - -#include <sysmocom/femtobts/superfemto.h> -#include <sysmocom/femtobts/gsml1prim.h> -#include <sysmocom/femtobts/gsml1const.h> -#include <sysmocom/femtobts/gsml1types.h> - -#include "gprs_debug.h" -#include "femtobts.h" -#include "sysmo_l1_if.h" - - -#ifdef HW_SYSMOBTS_V1 -#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/femtobts_dsp2arm" -#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/femtobts_arm2dsp" -#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_dsp2arm" -#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_arm2dsp" -#else -#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/superfemto_dsp2arm" -#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/superfemto_arm2dsp" -#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_sig_dsp2arm" -#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_sig_arm2dsp" - -#define DEV_TCH_DSP2ARM_NAME "/dev/msgq/gsml1_tch_dsp2arm" -#define DEV_TCH_ARM2DSP_NAME "/dev/msgq/gsml1_tch_arm2dsp" -#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm" -#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp" -#endif - -static const char *rd_devnames[] = { - [MQ_SYS_READ] = DEV_SYS_DSP2ARM_NAME, - [MQ_L1_READ] = DEV_L1_DSP2ARM_NAME, -#ifndef HW_SYSMOBTS_V1 - [MQ_TCH_READ] = DEV_TCH_DSP2ARM_NAME, - [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME, -#endif -}; - -static const char *wr_devnames[] = { - [MQ_SYS_WRITE] = DEV_SYS_ARM2DSP_NAME, - [MQ_L1_WRITE] = DEV_L1_ARM2DSP_NAME, -#ifndef HW_SYSMOBTS_V1 - [MQ_TCH_WRITE] = DEV_TCH_ARM2DSP_NAME, - [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME, -#endif -}; - -/* callback when there's something to read from the l1 msg_queue */ -static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what) -{ - //struct msgb *msg = l1p_msgb_alloc(); - struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128, - 128, "1l_fd"); - struct femtol1_hdl *fl1h = ofd->data; - int rc; - - msg->l1h = msg->data; - rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg)); - if (rc < 0) { - if (rc != -1) - LOGP(DL1IF, LOGL_ERROR, "error reading from L1 msg_queue: %s\n", - strerror(errno)); - msgb_free(msg); - return rc; - } - msgb_put(msg, rc); - - switch (ofd->priv_nr) { - case MQ_SYS_WRITE: - if (rc != sizeof(SuperFemto_Prim_t)) - LOGP(DL1IF, LOGL_NOTICE, "%u != " - "sizeof(SuperFemto_Prim_t)\n", rc); - return l1if_handle_sysprim(fl1h, msg); - case MQ_L1_WRITE: -#ifndef HW_SYSMOBTS_V1 - case MQ_TCH_WRITE: - case MQ_PDTCH_WRITE: -#endif - if (rc != sizeof(GsmL1_Prim_t)) - LOGP(DL1IF, LOGL_NOTICE, "%u != " - "sizeof(GsmL1_Prim_t)\n", rc); - return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg); - default: - /* The compiler can't know that priv_nr is an enum. Assist. */ - LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n", - ofd->priv_nr); - exit(0); - break; - } -}; - -/* callback when we can write to one of the l1 msg_queue devices */ -static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg) -{ - int rc; - - rc = write(ofd->fd, msg->l1h, msgb_l1len(msg)); - if (rc < 0) { - LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n", - strerror(errno)); - return rc; - } else if (rc < msg->len) { - LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: " - "%u < %u\n", rc, msg->len); - return -EIO; - } - - return 0; -} - -int l1if_transport_open(int q, struct femtol1_hdl *hdl) -{ - int rc; - - /* Step 1: Open all msg_queue file descriptors */ - struct osmo_fd *read_ofd = &hdl->read_ofd[q]; - struct osmo_wqueue *wq = &hdl->write_q[q]; - struct osmo_fd *write_ofd = &hdl->write_q[q].bfd; - - rc = open(rd_devnames[q], O_RDONLY); - if (rc < 0) { - LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n", - strerror(errno)); - return rc; - } - read_ofd->fd = rc; - read_ofd->priv_nr = q; - read_ofd->data = hdl; - read_ofd->cb = l1if_fd_cb; - read_ofd->when = BSC_FD_READ; - rc = osmo_fd_register(read_ofd); - if (rc < 0) { - close(read_ofd->fd); - read_ofd->fd = -1; - return rc; - } - - rc = open(wr_devnames[q], O_WRONLY); - if (rc < 0) { - LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n", - strerror(errno)); - goto out_read; - } - osmo_wqueue_init(wq, 10); - wq->write_cb = l1fd_write_cb; - write_ofd->fd = rc; - write_ofd->priv_nr = q; - write_ofd->data = hdl; - write_ofd->when = BSC_FD_WRITE; - rc = osmo_fd_register(write_ofd); - if (rc < 0) { - close(write_ofd->fd); - write_ofd->fd = -1; - goto out_read; - } - - return 0; - -out_read: - close(hdl->read_ofd[q].fd); - osmo_fd_unregister(&hdl->read_ofd[q]); - - return rc; -} - -int l1if_transport_close(int q, struct femtol1_hdl *hdl) -{ - struct osmo_fd *read_ofd = &hdl->read_ofd[q]; - struct osmo_fd *write_ofd = &hdl->write_q[q].bfd; - - osmo_fd_unregister(read_ofd); - close(read_ofd->fd); - read_ofd->fd = -1; - - osmo_fd_unregister(write_ofd); - close(write_ofd->fd); - write_ofd->fd = -1; - - return 0; -} diff --git a/src/sysmo_l1_if.c b/src/sysmo_l1_if.c deleted file mode 100644 index c7c54dd..0000000 --- a/src/sysmo_l1_if.c +++ /dev/null @@ -1,394 +0,0 @@ - -#include <string.h> -#include <errno.h> - -#include <sysmocom/femtobts/superfemto.h> -#include <sysmocom/femtobts/gsml1prim.h> -#include <sysmocom/femtobts/gsml1const.h> -#include <sysmocom/femtobts/gsml1types.h> - -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/timer.h> -#include <sysmo_l1_if.h> -#include <gprs_debug.h> -#include <pcu_l1_if.h> - -extern void *tall_pcu_ctx; - -uint32_t l1if_ts_to_hLayer2(uint8_t trx, uint8_t ts) -{ - return (ts << 16) | (trx << 24); -} - -/* allocate a msgb containing a GsmL1_Prim_t */ -struct msgb *l1p_msgb_alloc(void) -{ - struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim"); - - if (msg) - msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t)); - - return msg; -} - -static int l1if_req_pdch(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - struct osmo_wqueue *wqueue = &fl1h->write_q[MQ_PDTCH_WRITE]; - - if (osmo_wqueue_enqueue(wqueue, msg) != 0) { - LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n"); - msgb_free(msg); - } - - return 0; -} - -static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct femtol1_hdl *gl1) -{ - prim->id = id; - - /* for some reason the hLayer1 field is not always at the same position - * in the GsmL1_Prim_t, so we have to have this ugly case statement here... */ - switch (id) { - case GsmL1_PrimId_MphInitReq: - //prim->u.mphInitReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphCloseReq: - prim->u.mphCloseReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphConnectReq: - prim->u.mphConnectReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphDisconnectReq: - prim->u.mphDisconnectReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphActivateReq: - prim->u.mphActivateReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphDeactivateReq: - prim->u.mphDeactivateReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphConfigReq: - prim->u.mphConfigReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphMeasureReq: - prim->u.mphMeasureReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_MphInitCnf: - case GsmL1_PrimId_MphCloseCnf: - case GsmL1_PrimId_MphConnectCnf: - case GsmL1_PrimId_MphDisconnectCnf: - case GsmL1_PrimId_MphActivateCnf: - case GsmL1_PrimId_MphDeactivateCnf: - case GsmL1_PrimId_MphConfigCnf: - case GsmL1_PrimId_MphMeasureCnf: - break; - case GsmL1_PrimId_MphTimeInd: - break; - case GsmL1_PrimId_MphSyncInd: - break; - case GsmL1_PrimId_PhEmptyFrameReq: - prim->u.phEmptyFrameReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_PhDataReq: - prim->u.phDataReq.hLayer1 = gl1->hLayer1; - break; - case GsmL1_PrimId_PhConnectInd: - break; - case GsmL1_PrimId_PhReadyToSendInd: - break; - case GsmL1_PrimId_PhDataInd: - break; - case GsmL1_PrimId_PhRaInd: - break; - default: - LOGP(DL1IF, LOGL_ERROR, "unknown L1 primitive %u\n", id); - break; - } - return &prim->u; -} - -struct sapi_dir { - GsmL1_Sapi_t sapi; - GsmL1_Dir_t dir; -}; - -static const struct sapi_dir pdtch_sapis[] = { - { GsmL1_Sapi_Pdtch, GsmL1_Dir_TxDownlink }, - { GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink }, - { GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink }, - { GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink }, -#if 0 - { GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink }, - { GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink }, -#endif -}; - - -/* connect PDTCH */ -int l1if_connect_pdch(void *obj, uint8_t ts) -{ - struct femtol1_hdl *fl1h = obj; - struct msgb *msg = l1p_msgb_alloc(); - GsmL1_MphConnectReq_t *cr; - - cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConnectReq, fl1h); - cr->u8Tn = ts; - cr->logChComb = GsmL1_LogChComb_XIII; - - return l1if_req_pdch(fl1h, msg); -} - -static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h, - GsmL1_PhReadyToSendInd_t *rts_ind) -{ - struct gsm_time g_time; - int rc = 0; - - gsm_fn2gsmtime(&g_time, rts_ind->u32Fn); - - DEBUGP(DL1IF, "Rx PH-RTS.ind %02u/%02u/%02u SAPI=%s\n", - g_time.t1, g_time.t2, g_time.t3, - get_value_string(femtobts_l1sapi_names, rts_ind->sapi)); - - switch (rts_ind->sapi) { - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn, - rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); - case GsmL1_Sapi_Ptcch: - // FIXME - default: - break; - } - - return rc; -} - -static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t *l1_meas) -{ - meas->rssi = (int8_t) (l1_meas->fRssi); - meas->have_rssi = 1; - meas->ber = (uint8_t) (l1_meas->fBer * 100); - meas->have_ber = 1; - meas->bto = (int16_t) (l1_meas->i16BurstTiming); - meas->have_bto = 1; - meas->link_qual = (int16_t) (l1_meas->fLinkQuality); - meas->have_link_qual = 1; -} - -static int handle_ph_data_ind(struct femtol1_hdl *fl1h, - GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) -{ - int rc = 0; - struct pcu_l1_meas meas = {0}; - - DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n", - get_value_string(femtobts_l1sapi_names, data_ind->sapi), - data_ind->hLayer2, - osmo_hexdump(data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size)); - - pcu_rx_block_time(data_ind->u16Arfcn, data_ind->u32Fn, data_ind->u8Tn); - - /* - * TODO: Add proper bad frame handling here. This could be used - * to switch the used CS. Avoid a crash with the PCU right now - * feed "0 - 1" amount of data. - */ - if (data_ind->msgUnitParam.u8Size == 0) - return -1; - - gsmtap_send(fl1h->gsmtap, data_ind->u16Arfcn | GSMTAP_ARFCN_F_UPLINK, - data_ind->u8Tn, GSMTAP_CHANNEL_PACCH, 0, - data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1, - data_ind->msgUnitParam.u8Size-1); - - get_meas(&meas, &data_ind->measParam); - - switch (data_ind->sapi) { - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - /* drop incomplete UL block */ - if (data_ind->msgUnitParam.u8Buffer[0] - != GsmL1_PdtchPlType_Full) - break; - /* PDTCH / PACCH frame handling */ - pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn, - data_ind->msgUnitParam.u8Buffer + 1, - data_ind->msgUnitParam.u8Size - 1, - data_ind->u32Fn, - &meas); - break; - case GsmL1_Sapi_Ptcch: - // FIXME - break; - default: - LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n", - get_value_string(femtobts_l1sapi_names, data_ind->sapi)); - break; - } - - return rc; -} - -#define MIN_QUAL_RACH 5.0f - -static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind) -{ - uint8_t acc_delay; - - pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn); - - if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH) - return 0; - - DEBUGP(DL1IF, "Rx PH-RA.ind"); - - /* check for under/overflow / sign */ - if (ra_ind->measParam.i16BurstTiming < 0) - acc_delay = 0; - else - acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - - LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n", - acc_delay); - -#warning "The (P)RACH request is just dropped here" - -#if 0 - if (acc_delay > bts->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } -#endif - - return 0; -} - - -/* handle any random indication from the L1 */ -int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg) -{ - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - int rc = 0; - - LOGP(DL1IF, LOGL_DEBUG, "Rx L1 prim %s on queue %d\n", - get_value_string(femtobts_l1prim_names, l1p->id), wq); - - switch (l1p->id) { -#if 0 - case GsmL1_PrimId_MphTimeInd: - rc = handle_mph_time_ind(fl1h, &l1p->u.mphTimeInd); - break; - case GsmL1_PrimId_MphSyncInd: - break; - case GsmL1_PrimId_PhConnectInd: - break; -#endif - case GsmL1_PrimId_PhReadyToSendInd: - rc = handle_ph_readytosend_ind(fl1h, &l1p->u.phReadyToSendInd); - break; - case GsmL1_PrimId_PhDataInd: - rc = handle_ph_data_ind(fl1h, &l1p->u.phDataInd, msg); - break; - case GsmL1_PrimId_PhRaInd: - rc = handle_ph_ra_ind(fl1h, &l1p->u.phRaInd); - break; - default: - break; - } - - msgb_free(msg); - - return rc; -} - -int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - return -ENOTSUP; -} - -/* send packet data request to L1 */ -int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, - uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len) -{ - struct femtol1_hdl *fl1h = obj; - struct msgb *msg; - GsmL1_Prim_t *l1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - struct gsm_time g_time; - - gsm_fn2gsmtime(&g_time, fn); - - DEBUGP(DL1IF, "TX packet data %02u/%02u/%02u is_ptcch=%d ts=%d " - "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2, - g_time.t3, is_ptcch, ts, block_nr, arfcn, len); - - msg = l1p_msgb_alloc(); - l1p = msgb_l1prim(msg); - l1p->id = GsmL1_PrimId_PhDataReq; - data_req = &l1p->u.phDataReq; - data_req->hLayer1 = fl1h->hLayer1; - data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch; - data_req->subCh = GsmL1_SubCh_NA; - data_req->u8BlockNbr = block_nr; - data_req->u8Tn = ts; - data_req->u32Fn = fn; - msu_param = &data_req->msgUnitParam; - msu_param->u8Size = len; - memcpy(msu_param->u8Buffer, data, len); - - gsmtap_send(fl1h->gsmtap, arfcn, data_req->u8Tn, GSMTAP_CHANNEL_PACCH, - 0, data_req->u32Fn, 0, 0, - data_req->msgUnitParam.u8Buffer, - data_req->msgUnitParam.u8Size); - - - /* transmit */ - if (osmo_wqueue_enqueue(&fl1h->write_q[MQ_PDTCH_WRITE], msg) != 0) { - LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n"); - msgb_free(msg); - } - - return 0; -} - -void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) -{ - struct femtol1_hdl *fl1h; - int rc; - - fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl); - if (!fl1h) - return NULL; - - fl1h->hLayer1 = hlayer1; - fl1h->priv = priv; - fl1h->clk_cal = 0; - /* default clock source: OCXO */ - fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo; - - rc = l1if_transport_open(MQ_PDTCH_WRITE, fl1h); - if (rc < 0) { - talloc_free(fl1h); - return NULL; - } - - fl1h->gsmtap = gsmtap; - - return fl1h; -} - -int l1if_close_pdch(void *obj) -{ - struct femtol1_hdl *fl1h = obj; - if (fl1h) - l1if_transport_close(MQ_PDTCH_WRITE, fl1h); - talloc_free(fl1h); - return 0; -} - diff --git a/src/sysmo_l1_if.h b/src/sysmo_l1_if.h deleted file mode 100644 index 6b50d4e..0000000 --- a/src/sysmo_l1_if.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _SYSMO_L1_IF_H -#define _SYSMO_L1_IF_H - -#include <osmocom/core/select.h> -#include <osmocom/core/write_queue.h> -#include <osmocom/core/gsmtap_util.h> -#include <osmocom/gsm/gsm_utils.h> -#include "femtobts.h" - -enum { - MQ_SYS_READ, - MQ_L1_READ, -#ifndef HW_SYSMOBTS_V1 - MQ_TCH_READ, - MQ_PDTCH_READ, -#endif - _NUM_MQ_READ -}; - -enum { - MQ_SYS_WRITE, - MQ_L1_WRITE, -#ifndef HW_SYSMOBTS_V1 - MQ_TCH_WRITE, - MQ_PDTCH_WRITE, -#endif - _NUM_MQ_WRITE -}; - -struct femtol1_hdl { - struct gsm_time gsm_time; - uint32_t hLayer1; /* handle to the L1 instance in the DSP */ - uint32_t dsp_trace_f; - int clk_cal; - uint8_t clk_src; - struct llist_head wlc_list; - - struct gsmtap_inst *gsmtap; - uint32_t gsmtap_sapi_mask; - - void *priv; /* user reference */ - - struct osmo_timer_list alive_timer; - unsigned int alive_prim_cnt; - - struct osmo_fd read_ofd[_NUM_MQ_READ]; /* osmo file descriptors */ - struct osmo_wqueue write_q[_NUM_MQ_WRITE]; - - struct { - uint8_t dsp_version[3]; - uint8_t fpga_version[3]; - uint32_t band_support; /* bitmask of GSM_BAND_* */ - } hw_info; -}; - -#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) -#define msgb_sysprim(msg) ((SuperFemto_Prim_t *)(msg)->l1h) - -typedef int l1if_compl_cb(struct msgb *l1_msg, void *data); - -/* send a request primitive to the L1 and schedule completion call-back */ -int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, - int is_system_prim, l1if_compl_cb *cb, void *data); - -int l1if_reset(struct femtol1_hdl *hdl); -int l1if_activate_rf(struct femtol1_hdl *hdl, int on); -int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags); -int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power); - -struct msgb *l1p_msgb_alloc(void); -struct msgb *sysp_msgb_alloc(void); - -uint32_t l1if_lchan_to_hLayer2(struct gsm_lchan *lchan); -struct gsm_lchan *l1if_hLayer2_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer2); - -int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg); -int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg); - -/* tch.c */ -int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg); -int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); -struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan); - -/* - * The implementation of these functions is selected by either compiling and - * linking sysmo_l1_hw.c or sysmo_l1_fwd.c - */ -int l1if_transport_open(int q, struct femtol1_hdl *hdl); -int l1if_transport_close(int q, struct femtol1_hdl *hdl); - -#endif /* _SYSMO_L1_IF_H */
From: Max msuraev@sysmocom.de
Use uint8_t for TRX numbering everywhere (we don't expect hardware with more than 256 transceivers in the near future). This change helps to avoid unnecessary casts and make API much clearer. --- src/osmo-bts-sysmo/sysmo_l1_if.c | 8 ++++---- src/osmo-bts-sysmo/sysmo_l1_if.h | 2 +- src/pcu_l1_if.cpp | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c index c7c54dd..4bfcecd 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.c +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -155,7 +155,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h, switch (rts_ind->sapi) { case GsmL1_Sapi_Pdtch: case GsmL1_Sapi_Pacch: - rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn, + rc = pcu_rx_rts_req_pdtch(fl1h->trx, rts_ind->u8Tn, rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); case GsmL1_Sapi_Ptcch: // FIXME @@ -215,7 +215,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h, != GsmL1_PdtchPlType_Full) break; /* PDTCH / PACCH frame handling */ - pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn, + pcu_rx_data_ind_pdtch(fl1h->trx, data_ind->u8Tn, data_ind->msgUnitParam.u8Buffer + 1, data_ind->msgUnitParam.u8Size - 1, data_ind->u32Fn, @@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, return 0; }
-void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) +void *l1if_open_pdch(uint8_t trx, uint32_t hlayer1, struct gsmtap_inst *gsmtap) { struct femtol1_hdl *fl1h; int rc; @@ -367,7 +367,7 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) return NULL;
fl1h->hLayer1 = hlayer1; - fl1h->priv = priv; + fl1h->trx = trx; fl1h->clk_cal = 0; /* default clock source: OCXO */ fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo; diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.h b/src/osmo-bts-sysmo/sysmo_l1_if.h index 6b50d4e..83ca481 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.h +++ b/src/osmo-bts-sysmo/sysmo_l1_if.h @@ -38,7 +38,7 @@ struct femtol1_hdl { struct gsmtap_inst *gsmtap; uint32_t gsmtap_sapi_mask;
- void *priv; /* user reference */ + uint8_t trx;
struct osmo_timer_list alive_timer; unsigned int alive_prim_cnt; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 67272ab..2acf8ce 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -44,7 +44,7 @@ extern "C" {
// FIXME: move this, when changed from c++ to c. extern "C" { -void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap); +void *l1if_open_pdch(uint8_t trx, uint32_t hlayer1, struct gsmtap_inst *gsmtap); int l1if_connect_pdch(void *obj, uint8_t ts); int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); @@ -330,9 +330,8 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) struct gprs_bssgp_pcu *pcu; struct gprs_rlcmac_pdch *pdch; struct in_addr ia; - int rc = 0; - int trx, ts; - int i; + int rc = 0, ts, i; + uint8_t trx;
if (info_ind->version != PCU_IF_VERSION) { fprintf(stderr, "PCU interface version number of BTS (%d) is " @@ -450,7 +449,7 @@ bssgp_failed: info_ind->trx[trx].hlayer1); if (!bts->trx[trx].fl1h) bts->trx[trx].fl1h = l1if_open_pdch( - (void *)trx, + trx, info_ind->trx[trx].hlayer1, bts->gsmtap); if (!bts->trx[trx].fl1h) {
On Thu, Apr 21, 2016 at 02:35:57PM +0200, msuraev@sysmocom.de wrote:
- void *priv; /* user reference */
- uint8_t trx;
So I presume you are certain that priv was so far only used for the trx number, that there are no other callers using priv, and that it makes sense to not have a priv pointer anymore?
Looking at the patch it does look like priv was never really a priv in the arbitrary-backpointer case, but IMHO it would be good to clarify that in the log message.
- int rc = 0;
- int trx, ts;
- int i;
- int rc = 0, ts, i;
Unrelated cosmetic change, keep that out of this patch, i.e. only remove the trx int, the point being that I noticed only on the second glance. Also I believe we prefer to have each variable on its own line.
~Neels
Thanks. Comments are inline.
On 04/26/2016 01:06 PM, Neels Hofmeyr wrote:
On Thu, Apr 21, 2016 at 02:35:57PM +0200, msuraev@sysmocom.de wrote:
- void *priv; /* user reference */
- uint8_t trx;
So I presume you are certain that priv was so far only used for the trx number, that there are no other callers using priv, and that it makes sense to not have a priv pointer anymore?
Yes.
Looking at the patch it does look like priv was never really a priv in the arbitrary-backpointer case, but IMHO it would be good to clarify that in the log message.
- int rc = 0;
- int trx, ts;
- int i;
- int rc = 0, ts, i;
Unrelated cosmetic change, keep that out of this patch, i.e. only remove the trx int, the point being that I noticed only on the second glance.
Noted.
Also I believe we prefer to have each variable on its own line.
It doesn't look that way from looking at the other code. It also decreases readability by cluttering the code with useless repetitions.
On Tue, Apr 26, 2016 at 01:14:54PM +0200, Max wrote:
Also I believe we prefer to have each variable on its own line.
It doesn't look that way from looking at the other code. It also decreases readability by cluttering the code with useless repetitions.
but removing/adding variables where there are more than one per line makes the patches less readable, and potentially introduces more merge conflicts than necessary...
I used to be against one-per-line but have changed my opinion quite some time ago :)
~Neels
osmocom-net-gprs@lists.osmocom.org