aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.gitignore29
-rw-r--r--Makefile.am7
-rw-r--r--README.md52
-rw-r--r--TODO-RELEASE12
-rw-r--r--configure.ac80
-rw-r--r--contrib/Makefile.am2
-rw-r--r--contrib/ber/Makefile.am28
-rw-r--r--contrib/ber/README26
-rw-r--r--contrib/ber/codec_bit_class.h59
-rw-r--r--contrib/ber/rtp_ber.c483
-rw-r--r--contrib/ber/rtp_gen_map.c145
-rwxr-xr-xcontrib/jenkins_bts_trx.sh4
-rw-r--r--contrib/jenkins_common.sh5
-rwxr-xr-xcontrib/jenkins_lc15.sh3
-rwxr-xr-xcontrib/jenkins_oc2g.sh3
-rwxr-xr-xcontrib/jenkins_oct.sh3
-rwxr-xr-xcontrib/jenkins_oct_and_bts_trx.sh4
-rwxr-xr-xcontrib/jenkins_sysmobts.sh4
-rw-r--r--contrib/systemd/lc15bts-mgr.service4
-rw-r--r--contrib/systemd/oc2gbts-mgr.service4
-rw-r--r--contrib/systemd/osmo-bts-lc15.service11
-rw-r--r--contrib/systemd/osmo-bts-oc2g.service11
-rw-r--r--contrib/systemd/osmo-bts-sysmo.service11
-rw-r--r--contrib/systemd/osmo-bts-trx.service13
-rw-r--r--contrib/systemd/osmo-bts-virtual.service13
-rw-r--r--contrib/systemd/sysmobts-mgr.service4
-rw-r--r--debian/changelog1396
-rw-r--r--debian/compat2
-rw-r--r--debian/control35
-rwxr-xr-xdebian/osmo-bts-trx.postinst39
-rw-r--r--debian/osmo-bts-virtual.install1
-rwxr-xr-xdebian/osmo-bts-virtual.postinst39
-rw-r--r--doc/control_interface.txt2
-rw-r--r--doc/examples/Makefile.am26
-rw-r--r--doc/examples/litecell15/lc15bts-mgr.cfg6
-rw-r--r--doc/examples/litecell15/osmo-bts-lc15.cfg4
-rw-r--r--doc/examples/oc2g/oc2gbts-mgr.cfg6
-rw-r--r--doc/examples/oc2g/osmo-bts-oc2g.cfg4
-rw-r--r--doc/examples/octphy/osmo-bts-octphy.cfg4
-rw-r--r--doc/examples/octphy/osmo-bts-trx2dsp1.cfg4
-rw-r--r--doc/examples/sysmo/osmo-bts-sysmo.cfg4
-rw-r--r--doc/examples/sysmo/sysmobts-mgr.cfg5
-rw-r--r--doc/examples/trx/osmo-bts-trx-calypso.cfg14
-rw-r--r--doc/examples/trx/osmo-bts-trx.cfg5
-rw-r--r--doc/examples/virtual/openbsc-virtual.cfg151
-rw-r--r--doc/examples/virtual/osmo-bts-virtual.cfg9
-rw-r--r--doc/manuals/Makefile.am29
-rw-r--r--doc/manuals/abis/oml.adoc221
-rw-r--r--doc/manuals/abis/rsl.adoc396
-rw-r--r--doc/manuals/chapters/architecture.adoc4
-rw-r--r--doc/manuals/chapters/bts-models.adoc17
-rw-r--r--doc/manuals/chapters/configuration.adoc63
-rw-r--r--doc/manuals/chapters/interfaces.adoc2
-rw-r--r--doc/manuals/chapters/osmux_bts.adoc39
-rw-r--r--doc/manuals/chapters/overview.adoc2
-rw-r--r--doc/manuals/chapters/qos-example.adoc50
-rw-r--r--doc/manuals/osmobts-abis-docinfo.xml38
-rw-r--r--doc/manuals/osmobts-abis.adoc2
-rw-r--r--doc/manuals/osmobts-usermanual-docinfo.xml13
-rw-r--r--doc/manuals/osmobts-usermanual.adoc7
-rw-r--r--doc/manuals/rtp-amr-docinfo.xml28
-rw-r--r--doc/manuals/rtp-amr.adoc162
-rw-r--r--doc/manuals/vty/Makefile.vty-reference.inc37
-rw-r--r--doc/manuals/vty/bts_vty_additions.xml27
-rw-r--r--doc/manuals/vty/bts_vty_reference.xml1742
-rw-r--r--doc/manuals/vty/osmobts-vty-reference.xml (renamed from doc/manuals/osmobts-vty-reference.xml)13
-rw-r--r--doc/startup.txt5
-rw-r--r--doc/trx_sched_tch.txt98
-rw-r--r--include/osmo-bts/Makefile.am44
-rw-r--r--include/osmo-bts/abis.h16
-rw-r--r--include/osmo-bts/abis_osmo.h10
-rw-r--r--include/osmo-bts/amr.h1
-rw-r--r--include/osmo-bts/asci.h43
-rw-r--r--include/osmo-bts/bts.h440
-rw-r--r--include/osmo-bts/bts_model.h26
-rw-r--r--include/osmo-bts/bts_shutdown_fsm.h43
-rw-r--r--include/osmo-bts/bts_sm.h48
-rw-r--r--include/osmo-bts/bts_trx.h74
-rw-r--r--include/osmo-bts/cbch.h2
-rw-r--r--include/osmo-bts/control_if.h3
-rw-r--r--include/osmo-bts/csd_v110.h23
-rw-r--r--include/osmo-bts/gsm_data.h228
-rw-r--r--include/osmo-bts/gsm_data_shared.h882
-rw-r--r--include/osmo-bts/l1sap.h83
-rw-r--r--include/osmo-bts/lchan.h428
-rw-r--r--include/osmo-bts/logging.h11
-rw-r--r--include/osmo-bts/measurement.h12
-rw-r--r--include/osmo-bts/msg_utils.h3
-rw-r--r--include/osmo-bts/nm_common_fsm.h123
-rw-r--r--include/osmo-bts/notification.h61
-rw-r--r--include/osmo-bts/oml.h45
-rw-r--r--include/osmo-bts/osmux.h48
-rw-r--r--include/osmo-bts/paging.h61
-rw-r--r--include/osmo-bts/pcu_if.h19
-rw-r--r--include/osmo-bts/pcuif_proto.h129
-rw-r--r--include/osmo-bts/phy_link.h33
-rw-r--r--include/osmo-bts/power_control.h87
-rw-r--r--include/osmo-bts/rsl.h22
-rw-r--r--include/osmo-bts/rtp_input_preen.h20
-rw-r--r--include/osmo-bts/scheduler.h212
-rw-r--r--include/osmo-bts/scheduler_backend.h88
-rw-r--r--include/osmo-bts/signal.h6
-rw-r--r--include/osmo-bts/ta_control.h5
-rw-r--r--include/osmo-bts/tx_power.h32
-rw-r--r--include/osmo-bts/vty.h16
-rw-r--r--src/Makefile.am2
-rw-r--r--src/common/Makefile.am88
-rw-r--r--src/common/abis.c436
-rw-r--r--src/common/abis_osmo.c135
-rw-r--r--src/common/amr.c142
-rw-r--r--src/common/asci.c211
-rw-r--r--src/common/bts.c718
-rw-r--r--src/common/bts_ctrl_commands.c37
-rw-r--r--src/common/bts_ctrl_lookup.c9
-rw-r--r--src/common/bts_shutdown_fsm.c283
-rw-r--r--src/common/bts_sm.c95
-rw-r--r--src/common/bts_trx.c256
-rw-r--r--src/common/cbch.c42
-rw-r--r--src/common/csd_v110.c188
-rw-r--r--src/common/dtx_dl_amr_fsm.c2
-rw-r--r--src/common/gsm_data.c348
-rw-r--r--src/common/gsm_data_shared.c831
-rw-r--r--src/common/handover.c11
-rw-r--r--src/common/l1sap.c1706
-rw-r--r--src/common/lchan.c646
-rw-r--r--src/common/load_indication.c15
-rw-r--r--src/common/logging.c80
-rw-r--r--src/common/main.c219
-rw-r--r--src/common/measurement.c577
-rw-r--r--src/common/msg_utils.c21
-rw-r--r--src/common/nm_bb_transc_fsm.c325
-rw-r--r--src/common/nm_bts_fsm.c230
-rw-r--r--src/common/nm_bts_sm_fsm.c209
-rw-r--r--src/common/nm_channel_fsm.c317
-rw-r--r--src/common/nm_common_fsm.c45
-rw-r--r--src/common/nm_gprs_cell_fsm.c260
-rw-r--r--src/common/nm_gprs_nse_fsm.c280
-rw-r--r--src/common/nm_gprs_nsvc_fsm.c259
-rw-r--r--src/common/nm_radio_carrier_fsm.c285
-rw-r--r--src/common/notification.c256
-rw-r--r--src/common/oml.c1325
-rw-r--r--src/common/osmux.c545
-rw-r--r--src/common/paging.c388
-rw-r--r--src/common/pcu_sock.c712
-rw-r--r--src/common/phy_link.c81
-rw-r--r--src/common/power_control.c568
-rw-r--r--src/common/probes.d2
-rw-r--r--src/common/rsl.c2032
-rw-r--r--src/common/rtp_input_preen.c151
-rw-r--r--src/common/scheduler.c1031
-rw-r--r--src/common/scheduler_mframe.c6
-rw-r--r--src/common/sysinfo.c119
-rw-r--r--src/common/ta_control.c102
-rw-r--r--src/common/tx_power.c105
-rw-r--r--src/common/vty.c1828
-rw-r--r--src/osmo-bts-lc15/Makefile.am102
-rw-r--r--src/osmo-bts-lc15/calib_file.c (renamed from src/osmo-bts-litecell15/calib_file.c)4
-rw-r--r--src/osmo-bts-lc15/hw_misc.c (renamed from src/osmo-bts-litecell15/hw_misc.c)2
-rw-r--r--src/osmo-bts-lc15/hw_misc.h (renamed from src/osmo-bts-litecell15/hw_misc.h)0
-rw-r--r--src/osmo-bts-lc15/l1_if.c (renamed from src/osmo-bts-litecell15/l1_if.c)259
-rw-r--r--src/osmo-bts-lc15/l1_if.h (renamed from src/osmo-bts-litecell15/l1_if.h)21
-rw-r--r--src/osmo-bts-lc15/l1_transp.h (renamed from src/osmo-bts-litecell15/l1_transp.h)0
-rw-r--r--src/osmo-bts-lc15/l1_transp_hw.c (renamed from src/osmo-bts-litecell15/l1_transp_hw.c)28
-rw-r--r--src/osmo-bts-lc15/lc15bts.c (renamed from src/osmo-bts-litecell15/lc15bts.c)23
-rw-r--r--src/osmo-bts-lc15/lc15bts.h101
-rw-r--r--src/osmo-bts-lc15/lc15bts_vty.c (renamed from src/osmo-bts-litecell15/lc15bts_vty.c)249
-rw-r--r--src/osmo-bts-lc15/main.c (renamed from src/osmo-bts-litecell15/main.c)73
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_bid.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_bid.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_bid.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_bid.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_bts.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_bts.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_bts.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_bts.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_clock.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_clock.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_clock.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_clock.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_led.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_led.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_led.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_led.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr.c)33
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr_calib.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr_nl.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr_nl.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr_temp.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_mgr_vty.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_mgr_vty.c)49
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_misc.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_misc.c)4
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_misc.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_misc.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_nl.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_nl.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_nl.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_nl.h)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_par.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_par.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_par.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_par.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_power.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_power.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_power.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_power.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_swd.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_swd.c)4
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_swd.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_swd.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_temp.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_temp.c)2
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_temp.h (renamed from src/osmo-bts-litecell15/misc/lc15bts_temp.h)0
-rw-r--r--src/osmo-bts-lc15/misc/lc15bts_util.c (renamed from src/osmo-bts-litecell15/misc/lc15bts_util.c)2
-rw-r--r--src/osmo-bts-lc15/oml.c (renamed from src/osmo-bts-litecell15/oml.c)495
-rw-r--r--src/osmo-bts-lc15/tch.c (renamed from src/osmo-bts-litecell15/tch.c)60
-rw-r--r--src/osmo-bts-lc15/utils.c (renamed from src/osmo-bts-litecell15/utils.c)2
-rw-r--r--src/osmo-bts-lc15/utils.h (renamed from src/osmo-bts-litecell15/utils.h)0
-rw-r--r--src/osmo-bts-litecell15/Makefile.am38
-rw-r--r--src/osmo-bts-litecell15/lc15bts.h64
-rw-r--r--src/osmo-bts-litecell15/oml_router.c132
-rw-r--r--src/osmo-bts-litecell15/oml_router.h13
-rw-r--r--src/osmo-bts-oc2g/Makefile.am100
-rw-r--r--src/osmo-bts-oc2g/calib_file.c4
-rw-r--r--src/osmo-bts-oc2g/hw_misc.c2
-rw-r--r--src/osmo-bts-oc2g/l1_if.c155
-rw-r--r--src/osmo-bts-oc2g/l1_if.h11
-rw-r--r--src/osmo-bts-oc2g/l1_transp_hw.c28
-rw-r--r--src/osmo-bts-oc2g/main.c72
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_bid.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_bts.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_clock.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_led.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_mgr.c33
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_mgr_calib.c15
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_mgr_nl.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_mgr_temp.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_mgr_vty.c45
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_misc.c4
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_nl.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_nl.h2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_par.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_power.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_swd.c4
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_temp.c2
-rw-r--r--src/osmo-bts-oc2g/misc/oc2gbts_util.c2
-rw-r--r--src/osmo-bts-oc2g/oc2gbts.c2
-rw-r--r--src/osmo-bts-oc2g/oc2gbts.h22
-rw-r--r--src/osmo-bts-oc2g/oc2gbts_vty.c96
-rw-r--r--src/osmo-bts-oc2g/oml.c359
-rw-r--r--src/osmo-bts-oc2g/oml_router.c132
-rw-r--r--src/osmo-bts-oc2g/oml_router.h13
-rw-r--r--src/osmo-bts-oc2g/tch.c68
-rw-r--r--src/osmo-bts-oc2g/utils.c2
-rw-r--r--src/osmo-bts-octphy/Makefile.am36
-rw-r--r--src/osmo-bts-octphy/l1_if.c146
-rw-r--r--src/osmo-bts-octphy/l1_oml.c176
-rw-r--r--src/osmo-bts-octphy/l1_oml.h2
-rw-r--r--src/osmo-bts-octphy/l1_tch.c29
-rw-r--r--src/osmo-bts-octphy/l1_utils.h10
-rw-r--r--src/osmo-bts-octphy/main.c3
-rw-r--r--src/osmo-bts-octphy/octphy_hw_api.c2
-rw-r--r--src/osmo-bts-octphy/octphy_vty.c16
-rw-r--r--src/osmo-bts-octphy/octpkt.c2
-rw-r--r--src/osmo-bts-omldummy/Makefile.am26
-rw-r--r--src/osmo-bts-omldummy/bts_model.c66
-rw-r--r--src/osmo-bts-omldummy/main.c133
-rw-r--r--src/osmo-bts-sysmo/Makefile.am74
-rw-r--r--src/osmo-bts-sysmo/calib_file.c2
-rw-r--r--src/osmo-bts-sysmo/eeprom.c24
-rw-r--r--src/osmo-bts-sysmo/femtobts.c2
-rw-r--r--src/osmo-bts-sysmo/femtobts.h30
-rw-r--r--src/osmo-bts-sysmo/hw_misc.c2
-rw-r--r--src/osmo-bts-sysmo/l1_fwd_main.c6
-rw-r--r--src/osmo-bts-sysmo/l1_if.c421
-rw-r--r--src/osmo-bts-sysmo/l1_if.h7
-rw-r--r--src/osmo-bts-sysmo/l1_transp_fwd.c7
-rw-r--r--src/osmo-bts-sysmo/l1_transp_hw.c28
-rw-r--r--src/osmo-bts-sysmo/main.c68
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts-layer1.c2
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_eeprom.h1
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr.c33
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c2
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_calib.c20
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c2
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c4
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c28
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_misc.c8
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_nl.c2
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_nl.h2
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_par.c4
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_util.c2
-rw-r--r--src/osmo-bts-sysmo/oml.c375
-rw-r--r--src/osmo-bts-sysmo/oml_router.c129
-rw-r--r--src/osmo-bts-sysmo/oml_router.h13
-rw-r--r--src/osmo-bts-sysmo/sysmobts_ctrl.c10
-rw-r--r--src/osmo-bts-sysmo/sysmobts_vty.c66
-rw-r--r--src/osmo-bts-sysmo/tch.c92
-rw-r--r--src/osmo-bts-sysmo/utils.c2
-rw-r--r--src/osmo-bts-trx/Makefile.am77
-rw-r--r--src/osmo-bts-trx/amr_loop.c107
-rw-r--r--src/osmo-bts-trx/amr_loop.h16
-rw-r--r--src/osmo-bts-trx/l1_if.c763
-rw-r--r--src/osmo-bts-trx/l1_if.h136
-rw-r--r--src/osmo-bts-trx/loops.c322
-rw-r--r--src/osmo-bts-trx/loops.h27
-rw-r--r--src/osmo-bts-trx/main.c125
-rw-r--r--src/osmo-bts-trx/probes.d7
-rw-r--r--src/osmo-bts-trx/sched_lchan_fcch_sch.c89
-rw-r--r--src/osmo-bts-trx/sched_lchan_pdtch.c221
-rw-r--r--src/osmo-bts-trx/sched_lchan_rach.c214
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchf.c677
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchh.c580
-rw-r--r--src/osmo-bts-trx/sched_lchan_xcch.c205
-rw-r--r--src/osmo-bts-trx/sched_utils.h51
-rw-r--r--src/osmo-bts-trx/scheduler_trx.c1942
-rw-r--r--src/osmo-bts-trx/trx_if.c1095
-rw-r--r--src/osmo-bts-trx/trx_if.h44
-rw-r--r--src/osmo-bts-trx/trx_provision_fsm.c740
-rw-r--r--src/osmo-bts-trx/trx_provision_fsm.h68
-rw-r--r--src/osmo-bts-trx/trx_vty.c433
-rw-r--r--src/osmo-bts-virtual/Makefile.am50
-rw-r--r--src/osmo-bts-virtual/bts_model.c106
-rw-r--r--src/osmo-bts-virtual/l1_if.c206
-rw-r--r--src/osmo-bts-virtual/l1_if.h8
-rw-r--r--src/osmo-bts-virtual/main.c66
-rw-r--r--src/osmo-bts-virtual/osmo_mcast_sock.c114
-rw-r--r--src/osmo-bts-virtual/osmo_mcast_sock.h28
-rw-r--r--src/osmo-bts-virtual/scheduler_virtbts.c420
-rw-r--r--src/osmo-bts-virtual/virtual_um.c79
-rw-r--r--src/osmo-bts-virtual/virtual_um.h2
-rw-r--r--src/osmo-bts-virtual/virtualbts_vty.c33
-rw-r--r--tests/Makefile.am30
-rw-r--r--tests/agch/Makefile.am25
-rw-r--r--tests/agch/agch_test.c12
-rw-r--r--tests/amr/Makefile.am26
-rw-r--r--tests/amr/amr_test.c71
-rw-r--r--tests/amr/amr_test.err3
-rw-r--r--tests/amr/amr_test.ok9
-rw-r--r--tests/cipher/Makefile.am25
-rw-r--r--tests/cipher/cipher_test.c12
-rw-r--r--tests/csd/Makefile.am25
-rw-r--r--tests/csd/csd_test.c157
-rw-r--r--tests/csd/csd_test.err126
-rw-r--r--tests/handover/Makefile.am25
-rw-r--r--tests/handover/handover_test.c62
-rw-r--r--tests/meas/Makefile.am27
-rw-r--r--tests/meas/meas_test.c210
-rw-r--r--tests/meas/meas_test.err8241
-rw-r--r--tests/meas/meas_test.ok4
-rw-r--r--tests/meas/meas_testcases.h6
-rw-r--r--tests/misc/Makefile.am25
-rw-r--r--tests/misc/misc_test.c62
-rw-r--r--tests/osmo-bts.vty323
-rw-r--r--tests/paging/Makefile.am25
-rw-r--r--tests/paging/paging_test.c182
-rw-r--r--tests/power/Makefile.am32
-rw-r--r--tests/power/bs_power_loop_test.c515
-rw-r--r--tests/power/bs_power_loop_test.err191
-rw-r--r--tests/power/bs_power_loop_test.ok360
-rw-r--r--tests/power/ms_power_loop_test.c433
-rw-r--r--tests/power/ms_power_loop_test.err65
-rw-r--r--tests/power/ms_power_loop_test.ok179
-rw-r--r--tests/power/power_test.c88
-rw-r--r--tests/power/power_test.ok7
-rw-r--r--tests/stubs.c31
-rw-r--r--tests/sysmobts/Makefile.am41
-rw-r--r--tests/sysmobts/sysmobts_test.c7
-rw-r--r--tests/ta_control/Makefile.am23
-rw-r--r--tests/ta_control/ta_control_test.c76
-rw-r--r--tests/ta_control/ta_control_test.ok609
-rw-r--r--tests/testsuite.at36
-rw-r--r--tests/tx_power/Makefile.am22
-rw-r--r--tests/tx_power/tx_power_test.c86
-rw-r--r--tests/tx_power/tx_power_test.err88
-rw-r--r--tests/tx_power/tx_power_test.ok9
357 files changed, 40739 insertions, 13769 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..7592debf
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+open_collective: osmocom
diff --git a/.gitignore b/.gitignore
index 305553ff..34d55b8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,10 +35,10 @@ src/osmo-bts-sysmo/osmo-bts-sysmo-remote
src/osmo-bts-sysmo/sysmobts-mgr
src/osmo-bts-sysmo/sysmobts-util
-src/osmo-bts-litecell15/lc15bts-mgr
-src/osmo-bts-litecell15/lc15bts-util
-src/osmo-bts-litecell15/misc/.dirstamp
-src/osmo-bts-litecell15/osmo-bts-lc15
+src/osmo-bts-lc15/lc15bts-mgr
+src/osmo-bts-lc15/lc15bts-util
+src/osmo-bts-lc15/misc/.dirstamp
+src/osmo-bts-lc15/osmo-bts-lc15
src/osmo-bts-trx/osmo-bts-trx
@@ -47,8 +47,15 @@ src/osmo-bts-octphy/osmo-bts-octphy
src/osmo-bts-virtual/osmo-bts-virtual
src/osmo-bts-omldummy/osmo-bts-omldummy
+src/osmo-bts-oc2g/osmo-bts-oc2g
+src/osmo-bts-oc2g/oc2gbts-mgr
+src/osmo-bts-oc2g/oc2gbts-util
+src/osmo-bts-oc2g/misc/.dirstamp
+
tests/atconfig
tests/package.m4
+tests/amr/amr_test
+tests/csd/csd_test
tests/agch/agch_test
tests/paging/paging_test
tests/cipher/cipher_test
@@ -57,6 +64,9 @@ tests/meas/meas_test
tests/misc/misc_test
tests/handover/handover_test
tests/tx_power/tx_power_test
+tests/ta_control/ta_control_test
+tests/power/ms_power_loop_test
+tests/power/bs_power_loop_test
tests/testsuite
tests/testsuite.log
@@ -79,15 +89,24 @@ debian/*.substvars
debian/osmo-bts-trx-dbg/
debian/osmo-bts-trx/
debian/tmp/
-/tests/power/power_test
# manuals
doc/manuals/*.html
doc/manuals/*.svg
doc/manuals/*.pdf
+doc/manuals/vty/*.pdf
doc/manuals/*__*.png
doc/manuals/*.check
doc/manuals/generated/
+doc/manuals/vty/osmobts-*-vty-reference.xml
+doc/manuals/vty/osmobts-*-vty-reference.xml.inc.gen
+doc/manuals/vty/osmobts-*-vty-reference.xml.inc.merged
doc/manuals/osmomsc-usermanual.xml
doc/manuals/common
doc/manuals/build
+
+contrib/osmo-bts.spec
+contrib/ber/rtp_ber
+contrib/ber/rtp_gen_map
+
+arm-poky-linux-gnueabi-libtool
diff --git a/Makefile.am b/Makefile.am
index 62bad698..6dad46cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,9 +5,12 @@ SUBDIRS = include src tests doc contrib
# package the contrib and doc
EXTRA_DIST = \
+ .version \
+ README.md \
contrib/dump_docs.py \
- git-version-gen .version \
- README.md
+ debian \
+ git-version-gen \
+ $(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
diff --git a/README.md b/README.md
index 7e26d823..b9c45fd8 100644
--- a/README.md
+++ b/README.md
@@ -20,34 +20,50 @@ Several kinds of BTS hardware are supported:
* sysmocom sysmoBTS
* Octasic octphy
* Nutaq litecell 1.5
+ * OpenCellular 2G (OC-2G)
* software-defined radio based osmo-bts-trx (e.g. USRP B210, UmTRX, LimeSDR)
Homepage
--------
The official homepage of the project is
-https://osmocom.org/projects/osmobts/wiki
+<https://osmocom.org/projects/osmobts/wiki>
GIT Repository
--------------
You can clone from the official osmo-bts.git repository using
- git clone git://git.osmocom.org/osmo-bts.git
+ git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-bts
-There is a cgit interface at http://git.osmocom.org/osmo-bts/
+There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-bts>
Documentation
-------------
-We provide a
-[User Manual](http://ftp.osmocom.org/docs/latest/osmobts-usermanual.pdf)
-as well as a
-[VTY Reference Manual](http://ftp.osmocom.org/docs/latest/osmobsc-vty-reference.pdf)
-and a
-[Abis refrence MAnual](http://ftp.osmocom.org/docs/latest/osmobts-abis.pdf)
+User Manuals and VTY reference manuals are [optionally] built in PDF form
+as part of the build process.
+
+Pre-rendered PDF version of the current "master" can be found at
+[User Manual](https://ftp.osmocom.org/docs/latest/osmobts-usermanual.pdf)
+as well as the VTY reference manuals
+* [VTY Reference Manual for osmo-bts-sysmo](https://ftp.osmocom.org/docs/latest/osmobts-sysmo-vty-reference.pdf)
+* [VTY Reference Manual for osmo-bts-trx](https://ftp.osmocom.org/docs/latest/osmobts-trx-vty-reference.pdf)
+* [VTY Reference Manual for osmo-bts-lc15](https://ftp.osmocom.org/docs/latest/osmobts-lc15-vty-reference.pdf)
+* [VTY Reference Manual for osmo-bts-oc2g](https://ftp.osmocom.org/docs/latest/osmobts-oc2g-vty-reference.pdf)
+* [VTY Reference Manual for osmo-bts-octphy](https://ftp.osmocom.org/docs/latest/osmobts-octphy-vty-reference.pdf)
+
+There also is an
+[Abis reference Manual](https://ftp.osmocom.org/docs/latest/osmobts-abis.pdf)
describing the OsmoBTS specific A-bis dialect.
+Forum
+-----
+
+We welcome any osmo-bts related discussions in the
+[Cellular Network Infrastructure -> 2G RAN (GERAN)](https://discourse.osmocom.org/c/cni/geran)
+section of the osmocom discourse (web based Forum).
+
Mailing List
------------
@@ -60,6 +76,13 @@ Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
+Issue Tracker
+-------------
+
+We use the [issue tracker of the osmo-bts project on osmocom.org](https://osmocom.org/projects/osmobts/issues) for
+tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
+us out by resolving existing issues.
+
Contributing
------------
@@ -77,7 +100,7 @@ https://gerrit.osmocom.org/#/q/project:osmo-bts+status:open
Known Limitations
=================
-As of March 17, 2017, the following known limitations exist in this
+As of January 2021, the following known limitations exist in this
implementation:
Common Core
@@ -87,10 +110,6 @@ Common Core
* System Information limited to 1,2,2bis,2ter,2quater,3,4,5,6,9,13
* No RATSCCH in AMR
* Will reject TS 12.21 STARTING TIME in SET BTS ATTR / SET CHAN ATTR
- * No support for frequency hopping
- * No reporting of interference levels as part of TS 08.58 RF RES IND
- * No error reporting in case PAGING COMMAND fails due to queue overflow
- * No use of TS 08.58 BS Power and MS Power parameters
* No support of TS 08.58 MultiRate Control
* No support of TS 08.58 Supported Codec Types
* No support of Bter frame / ENHANCED MEASUREMENT REPORT
@@ -117,8 +136,3 @@ osmo-bts-octphy
* no clear indication of nominal transmit power, various power related
computations are likely off
* no OML attribute validation during bts_model_check_oml()
-
-osmo-bts-trx
-------------
-
- * No BER value delivered to OsmoPCU (https://osmocom.org/issues/1855)
diff --git a/TODO-RELEASE b/TODO-RELEASE
new file mode 100644
index 00000000..96426a51
--- /dev/null
+++ b/TODO-RELEASE
@@ -0,0 +1,12 @@
+# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
+# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
+# In short:
+# LIBVERSION=c:r:a
+# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
+# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
+# If any interfaces have been added since the last public release: c:r:a + 1.
+# If any interfaces have been removed or changed since the last public release: c:r:0.
+#library what description / commit summary line
+libosmogsm >1.9.0 added new PRIM_INFO to include/osmocom/gsm/l1sap.h
+libosmogsm >1.9.0 use of RLP code in libosmogsm
+libosmoctrl >1.9.0 use ctrl_cmd_send2()
diff --git a/configure.ac b/configure.ac
index b70d934d..79958dd1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,8 @@ AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_TESTDIR(tests)
+CFLAGS="$CFLAGS -std=gnu11"
+
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -22,6 +24,11 @@ AC_PROG_CC
AC_PROG_INSTALL
LT_INIT
+dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
+AS_CASE(["$LD"],[*clang*],
+ [AS_CASE(["${host_os}"],
+ [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
+
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
@@ -62,14 +69,15 @@ then
fi
dnl checks for libraries
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.2.0)
-PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
-PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 0.6.0)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
+PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.5.0)
+PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
AC_MSG_CHECKING([whether to enable support for sysmobts calibration tool])
AC_ARG_ENABLE(sysmobts-calib,
@@ -342,6 +350,56 @@ then
AC_SUBST([OSMO_GSM_MANUALS_DIR])
fi
+AC_ARG_ENABLE([external_tests],
+ AC_HELP_STRING([--enable-external-tests],
+ [Include the VTY/CTRL tests in make check [default=no]]),
+ [enable_ext_tests="$enableval"],[enable_ext_tests="no"])
+if test "x$enable_ext_tests" = "xyes" ; then
+ AC_CHECK_PROG(PYTHON3_AVAIL,python3,yes)
+ if test "x$PYTHON3_AVAIL" != "xyes" ; then
+ AC_MSG_ERROR([Please install python3 to run the VTY/CTRL tests.])
+ fi
+ AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
+ if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
+ AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
+ fi
+fi
+AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
+AC_MSG_RESULT([$enable_ext_tests])
+AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
+
+#
+# SystemTap support
+#
+AC_MSG_CHECKING([whether to include systemtap tracing support])
+AC_ARG_ENABLE([systemtap],
+ [AS_HELP_STRING([--enable-systemtap],
+ [Enable inclusion of systemtap trace support])],
+ [ENABLE_SYSTEMTAP="${enableval}"], [ENABLE_SYSTEMTAP='no'])
+AM_CONDITIONAL([ENABLE_SYSTEMTAP], [test x$ENABLE_SYSTEMTAP = xyes])
+AC_MSG_RESULT(${ENABLE_SYSTEMTAP})
+
+if test "x${ENABLE_SYSTEMTAP}" = xyes; then
+ # Additional configuration for --enable-systemtap is HERE
+ AC_CHECK_PROGS(DTRACE, dtrace)
+ if test -z "$DTRACE"; then
+ AC_MSG_ERROR([dtrace not found])
+ fi
+ AC_CHECK_HEADER([sys/sdt.h], [SDT_H_FOUND='yes'],
+ [SDT_H_FOUND='no';
+ AC_MSG_ERROR([systemtap support needs sys/sdt.h header])])
+ AC_DEFINE([HAVE_SYSTEMTAP], [1], [Define to 1 if using SystemTap probes.])
+ AC_ARG_WITH([tapset-install-dir],
+ [AS_HELP_STRING([--with-tapset-install-dir],
+ [The absolute path where the tapset dir will be installed])],
+ [if test "x${withval}" = x; then
+ ABS_TAPSET_DIR="\$(datadir)/systemtap/tapset"
+ else
+ ABS_TAPSET_DIR="${withval}"
+ fi], [ABS_TAPSET_DIR="\$(datadir)/systemtap/tapset"])
+ AC_SUBST(ABS_TAPSET_DIR)
+fi
+
# https://www.freedesktop.org/software/systemd/man/daemon.html
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
@@ -369,7 +427,7 @@ AC_OUTPUT(
src/osmo-bts-virtual/Makefile
src/osmo-bts-omldummy/Makefile
src/osmo-bts-sysmo/Makefile
- src/osmo-bts-litecell15/Makefile
+ src/osmo-bts-lc15/Makefile
src/osmo-bts-oc2g/Makefile
src/osmo-bts-trx/Makefile
src/osmo-bts-octphy/Makefile
@@ -382,12 +440,16 @@ AC_OUTPUT(
tests/sysmobts/Makefile
tests/misc/Makefile
tests/handover/Makefile
+ tests/ta_control/Makefile
tests/tx_power/Makefile
tests/power/Makefile
tests/meas/Makefile
+ tests/amr/Makefile
+ tests/csd/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
contrib/Makefile
+ contrib/ber/Makefile
contrib/systemd/Makefile
Makefile)
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index 3439c97b..5594199b 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -1 +1 @@
-SUBDIRS = systemd
+SUBDIRS = systemd ber
diff --git a/contrib/ber/Makefile.am b/contrib/ber/Makefile.am
new file mode 100644
index 00000000..9bd7f404
--- /dev/null
+++ b/contrib/ber/Makefile.am
@@ -0,0 +1,28 @@
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ -I$(builddir) \
+ $(NULL)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(NULL)
+
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(NULL)
+
+noinst_PROGRAMS = rtp_ber rtp_gen_map
+
+rtp_ber_SOURCES = rtp_ber.c codec_bit_class.h
+
+rtp_gen_map_SOURCES = rtp_gen_map.c
+
+update_codec_bit_class_h: rtp_gen_map
+ $(AM_V_GEN)./$< > $(top_srcdir)/contrib/ber/codec_bit_class.h
diff --git a/contrib/ber/README b/contrib/ber/README
new file mode 100644
index 00000000..07c4a785
--- /dev/null
+++ b/contrib/ber/README
@@ -0,0 +1,26 @@
+BER testing tool
+----------------
+
+* Check all configs (MSC/BSC/BTS) for proper codec support
+ - FR enabled
+ - EFR enabled
+ - AMR 12.2 enabled (and all other modes disabled !)
+ - Use `amr-payload octet-aligned` in BSC config
+
+* Check BTS config
+ - Disable jitter buffer : `bts N / rtp jitter-buffer 0`
+
+* Check BSC config
+ - Disable radio timeout : `network / bts n / radio-link-timeout infinite`
+
+* Start BER testing tool
+ - `./rtp_ber 4000`
+
+* On the MSC CLI, start a silent-call, then request GSM to test loop
+ - `subscriber imsi <XXX> silent-call start tch/f speech-amr`
+ - `subscriber imsi <XXX> ms-test close-loop b`
+
+ Don't forget to terminate the loop and terminate the silent call !
+
+ - `subscriber imsi <XXX> ms-test open-loop`
+ - `subscriber imsi <XXX> silent-call stop`
diff --git a/contrib/ber/codec_bit_class.h b/contrib/ber/codec_bit_class.h
new file mode 100644
index 00000000..2a712e76
--- /dev/null
+++ b/contrib/ber/codec_bit_class.h
@@ -0,0 +1,59 @@
+static const int gsm_fr_bitclass[] = {
+ -1, -1, -1, -1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 2, 2,
+ 0, 0, 1, 2, 2, 0, 0, 1, 2, 2, 0, 1, 1, 2, 0, 1,
+ 2, 2, 0, 1, 2, 1, 2, 2, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 0, 0, 0, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
+ 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1,
+ 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+ 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
+ 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
+ 1, 2, 1, 1, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 0, 0, 0, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
+ 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1,
+ 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+ 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2,
+ 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
+ 2, 2, 1, 2, 2, 1, 2, 2,
+};
+
+static const int gsm_efr_bitclass[] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 2, 2, 1, 2,
+};
+
+static const int gsm_amr_12_2_bitclass[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, -1, -1, -1, -1,
+};
+
diff --git a/contrib/ber/rtp_ber.c b/contrib/ber/rtp_ber.c
new file mode 100644
index 00000000..01c1441a
--- /dev/null
+++ b/contrib/ber/rtp_ber.c
@@ -0,0 +1,483 @@
+/* RTP based GSM BER testing for osmo-bts, implementing ideas described in
+ * https://osmocom.org/projects/osmobts/wiki/BER_Testing
+ *
+ * In short: The command transmits a PRBS sequence encapsulated in RTP frames, which are sent
+ * to the BTS, which transmits that data in the (unimpaired) downlink. The mobile station
+ * receives the data and is instructed to loop it back in the (possibly impaired) uplink.
+ * The BTS receives that uplink, puts in in RTP frames which end up being received back by this
+ * very tool. By correlating the received RTP with the PRBS sequence, this tool can compute
+ * the BER (Bit Error Rate) of the (possibly impaired) uplink. Doing this with different
+ * RF channel model simulators in the uplink allows to establish BER at different levels and
+ * channel conditions. */
+
+/* (C) 2019 sysmocom - s.f.m.c. GmbH; Author: Sylvain Munaut
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocom/codec/codec.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/prbs.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/trau/osmo_ortp.h>
+
+#include <codec_bit_class.h>
+
+
+struct app_state {
+ struct osmo_rtp_socket *rs;
+
+ enum {
+ WAIT_CONN = 0, /* Wait for incoming connection */
+ WAIT_LOOP, /* Wait for a somewhat valid packet to start measuring */
+ RUNNING, /* Main state */
+ } state;
+
+ int pt;
+
+ int ref_len;
+ uint8_t ref_bytes[GSM_FR_BYTES]; /* FR is the largest possible one */
+ ubit_t ref_bits[8*GSM_FR_BYTES];
+
+ struct osmo_timer_list rtp_timer;
+
+ uint16_t rx_last_seq;
+ uint32_t rx_last_ts;
+ uint32_t rx_idx;
+ uint32_t tx_idx;
+
+ const int *err_tbl; /* Classification table */
+ int err_frames; /* Number of accumulated frames */
+ int err_cnt[3]; /* Bit error counter */
+ int err_tot[3]; /* Total # bits in that class */
+};
+
+#define FLOW_REG_TX_MAX_ADVANCE 200
+#define FLOW_REG_TX_MIN_ADVANCE 50
+
+
+const struct log_info log_info;
+
+
+static const uint8_t amr_size_by_ft[] = {
+ [0] = 12, /* 4.75 */
+ [1] = 13, /* 5.15 */
+ [2] = 15, /* 5.9 */
+ [3] = 17, /* 6.7 */
+ [4] = 19, /* 7.4 */
+ [5] = 20, /* 7.95 */
+ [6] = 26, /* 10.2 */
+ [7] = 31, /* 12.2 */
+ [8] = 5, /* SID */
+};
+
+static const char * const amr_rate_by_ft[] = {
+ [0] = "4.75",
+ [1] = "5.15",
+ [2] = "5.9",
+ [3] = "6.7",
+ [4] = "7.4",
+ [5] = "7.95",
+ [6] = "10.2",
+ [7] = "12.2",
+ [8] = "SID",
+};
+
+
+static void
+_gsm_fr_gen_ref(struct app_state *as)
+{
+ struct osmo_prbs_state pn9;
+
+ /* Length */
+ as->ref_len = GSM_FR_BYTES;
+
+ /* Marker */
+ as->ref_bits[0] = 1;
+ as->ref_bits[1] = 1;
+ as->ref_bits[2] = 0;
+ as->ref_bits[3] = 1;
+
+ /* PN */
+ osmo_prbs_state_init(&pn9, &osmo_prbs9);
+ pn9.state = 31;
+ osmo_prbs_get_ubits(&as->ref_bits[4], 260, &pn9);
+
+ /* Convert to bytes */
+ osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 8*GSM_FR_BYTES, 0);
+
+ /* Init error classes */
+ as->err_tot[0] = 50;
+ as->err_tot[1] = 132;
+ as->err_tot[2] = 78;
+ as->err_tbl = gsm_fr_bitclass;
+}
+
+static void
+_gsm_efr_gen_ref(struct app_state *as)
+{
+ struct osmo_prbs_state pn9;
+
+ /* Length */
+ as->ref_len = GSM_EFR_BYTES;
+
+ /* Marker */
+ as->ref_bits[0] = 1;
+ as->ref_bits[1] = 1;
+ as->ref_bits[2] = 0;
+ as->ref_bits[3] = 0;
+
+ /* PN */
+ osmo_prbs_state_init(&pn9, &osmo_prbs9);
+ pn9.state = 31;
+ osmo_prbs_get_ubits(&as->ref_bits[4], 244, &pn9);
+
+ /* Convert to bytes */
+ osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 8*GSM_EFR_BYTES, 0);
+
+ /* Init error classes */
+ as->err_tot[0] = 50;
+ as->err_tot[1] = 125;
+ as->err_tot[2] = 73;
+ as->err_tbl = gsm_efr_bitclass;
+}
+
+static void
+_gsm_amr_gen_ref(struct app_state *as)
+{
+ struct osmo_prbs_state pn9;
+ uint8_t hdr[2];
+
+ /* Length */
+ as->ref_len = 33;
+
+ /* Header */
+ hdr[0] = 0x70;
+ hdr[1] = 0x3c;
+ osmo_pbit2ubit_ext(as->ref_bits, 0, hdr, 0, 16, 0);
+
+ /* PN */
+ osmo_prbs_state_init(&pn9, &osmo_prbs9);
+ pn9.state = 31;
+ osmo_prbs_get_ubits(&as->ref_bits[16], 244, &pn9);
+
+ /* Unused bits */
+ as->ref_bits[260] = 0;
+ as->ref_bits[261] = 0;
+ as->ref_bits[262] = 0;
+ as->ref_bits[263] = 0;
+
+ /* Convert to bytes */
+ osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 264, 0);
+
+ /* Init error classes */
+ as->err_tot[0] = 81;
+ as->err_tot[1] = 163;
+ as->err_tot[2] = -1;
+ as->err_tbl = gsm_amr_12_2_bitclass;
+}
+
+
+static void
+_gsm_gen_ref(struct app_state *as)
+{
+ switch (as->pt) {
+ case RTP_PT_GSM_FULL:
+ _gsm_fr_gen_ref(as);
+ break;
+ case RTP_PT_GSM_EFR:
+ _gsm_efr_gen_ref(as);
+ break;
+ case RTP_PT_AMR:
+ _gsm_amr_gen_ref(as);
+ break;
+ default:
+ fprintf(stderr, "[!] Unsupported payload type for BER measurement\n");
+ }
+}
+
+static int
+_gsm_ber(struct app_state *as, const uint8_t *payload, unsigned int payload_len)
+{
+ ubit_t rx_bits[8*33];
+ int err[3]; /* Class 1a, 1b, 2 */
+ int ones;
+ int i, j;
+
+ if (payload) {
+ /* Process real-payload */
+ osmo_pbit2ubit_ext(rx_bits, 0, payload, 0, 8*payload_len, 0);
+
+ err[0] = err[1] = err[2] = 0;
+ ones = 0;
+
+ for (i = 0; i < 8 * payload_len; i++) {
+ j = as->err_tbl[i];
+ if (j >= 0) {
+ err[j] += rx_bits[i] ^ as->ref_bits[i];
+ ones += rx_bits[i];
+ }
+ }
+
+ if (ones < 32) { // This frames is probably us underrunning Tx, don't use it
+ fprintf(stderr, "[w] Frame ignored as probably TX underrun %d %d\n", as->tx_idx, as->rx_idx);
+ return 1;
+ }
+ } else {
+ /* No payload -> Lost frame completely */
+ err[0] = as->err_tot[0] / 2;
+ err[1] = as->err_tot[1] / 2;
+ err[2] = as->err_tot[2] / 2;
+ }
+
+ if (as->state == RUNNING) {
+ /* Update records */
+ if (err[0] != 0) {
+ /* Class 1a bits bad -> Frame error */
+ as->err_cnt[0]++;
+ }
+
+ as->err_cnt[1] += err[1]; /* Class 1b */
+ as->err_cnt[2] += err[2]; /* class 2 */
+
+ as->err_frames++;
+
+ /* Enough for a read-out ? */
+ if (as->err_frames == 200) {
+ printf("FBER: %4.2f C1b RBER: %5.3f C2 RBER: %5.3f\n",
+ 100.0f * as->err_cnt[0] / as->err_frames,
+ 100.0f * as->err_cnt[1] / (as->err_tot[1] * as->err_frames),
+ 100.0f * as->err_cnt[2] / (as->err_tot[2] * as->err_frames)
+ );
+ memset(as->err_cnt, 0, sizeof(as->err_cnt));
+ as->err_frames = 0;
+ }
+ }
+
+ return err[0] != 0;
+}
+
+static int
+_rtp_check_payload_type(const uint8_t *payload, unsigned int payload_len)
+{
+ uint8_t ft;
+ int pt = -1;
+
+ switch (payload_len) {
+ case GSM_FR_BYTES: /* FR or AMR 12.2k */
+ /* Check for AMR */
+ ft = (payload[1] >> 3) & 0xf;
+ if (ft == 7)
+ pt = RTP_PT_AMR;
+
+ /* Check for FR */
+ else if ((payload[0] & 0xF0) == 0xD0)
+ pt = RTP_PT_GSM_FULL;
+
+ /* None of the above */
+ else
+ fprintf(stderr, "[!] FR without 0xD0 signature or AMR with unknwon Frame Type ?!?\n");
+
+ break;
+ case GSM_EFR_BYTES: /* EFR */
+ if ((payload[0] & 0xF0) != 0xC0)
+ fprintf(stderr, "[!] EFR without 0xC0 signature ?!?\n");
+ pt = RTP_PT_GSM_EFR;
+ break;
+ case GSM_HR_BYTES: /* HR */
+ pt = RTP_PT_GSM_HALF;
+ break;
+ default: /* AMR */
+ {
+ uint8_t cmr, cmi, sti;
+ cmr = payload[0] >> 4;
+ ft = (payload[1] >> 3) & 0xf;
+
+ if (payload_len != amr_size_by_ft[ft]+2)
+ fprintf(stderr, "AMR FT %u(%s) but size %u\n",
+ ft, amr_rate_by_ft[ft], payload_len);
+
+ switch (ft) {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ cmi = ft;
+ printf("AMR SPEECH with FT/CMI %u(%s), "
+ "CMR %u\n",
+ cmi, amr_rate_by_ft[cmi],
+ cmr);
+ break;
+ case 8: /* SID */
+ cmi = (payload[2+4] >> 1) & 0x7;
+ sti = payload[2+4] & 0x10;
+ printf("AMR SID %s with CMI %u(%s), CMR %u(%s)\n",
+ sti ? "UPDATE" : "FIRST",
+ cmi, amr_rate_by_ft[cmi],
+ cmr, amr_rate_by_ft[cmr]);
+ break;
+ }
+ }
+ break;
+ }
+
+ return pt;
+}
+
+static void
+rtp_timer_cb(void *priv)
+{
+ struct app_state *as = (struct app_state *)priv;
+
+ /* Send at least one frame if we're not too far ahead */
+ if (as->tx_idx < (as->rx_idx + FLOW_REG_TX_MAX_ADVANCE)) {
+ osmo_rtp_send_frame(as->rs, as->ref_bytes, as->ref_len, GSM_RTP_DURATION);
+ as->tx_idx++;
+ } else {
+ fprintf(stderr, "Skipped\n");
+ }
+
+ /* Then maybe a second one to try and catch up to RX */
+ if (as->tx_idx < (as->rx_idx + FLOW_REG_TX_MIN_ADVANCE)) {
+ osmo_rtp_send_frame(as->rs, as->ref_bytes, as->ref_len, GSM_RTP_DURATION);
+ as->tx_idx++;
+ }
+
+ /* Re-schedule */
+ osmo_timer_schedule(&as->rtp_timer, 0, 20000);
+}
+
+static int
+rtp_seq_num_diff(uint16_t new, uint16_t old)
+{
+ int d = (int)new - (int)old;
+ while (d > 49152)
+ d -= 65536;
+ while (d < -49152)
+ d += 65536;
+ return d;
+}
+
+static void
+rtp_rx_cb(struct osmo_rtp_socket *rs,
+ const uint8_t *payload, unsigned int payload_len,
+ uint16_t seq_number, uint32_t timestamp, bool marker)
+{
+ struct app_state *as = (struct app_state *)rs->priv;
+ int pt, rc, d;
+
+// printf("Rx(%u, %d, %d, %d): %s\n", payload_len, seq_number, timestamp, marker, osmo_hexdump(payload, payload_len));
+
+ /* Identify payload */
+ pt = _rtp_check_payload_type(payload, payload_len);
+
+ /* First packet ? */
+ if (as->state == WAIT_CONN) {
+ /* Setup for this payload type */
+ as->pt = pt;
+ osmo_rtp_socket_set_pt(as->rs, pt);
+ _gsm_gen_ref(as);
+
+ /* Timer every 20 ms */
+ osmo_timer_setup(&as->rtp_timer, rtp_timer_cb, as);
+ osmo_timer_add(&as->rtp_timer);
+ osmo_timer_schedule(&as->rtp_timer, 0, 20000);
+
+ /* Init our time tracking */
+ as->rx_last_seq = seq_number;
+ as->rx_last_ts = timestamp;
+
+ /* Now we wait for a loop */
+ as->state = WAIT_LOOP;
+ }
+
+ /* RX sequence & timstamp tracking */
+ if (rtp_seq_num_diff(seq_number, as->rx_last_seq) > 1)
+ fprintf(stderr, "[!] RTP sequence number discontinuity (%d -> %d)\n", as->rx_last_seq, seq_number);
+
+ d = (timestamp - as->rx_last_ts) / GSM_RTP_DURATION;
+
+ as->rx_idx += d;
+ as->rx_last_seq = seq_number;
+ as->rx_last_ts = timestamp;
+
+ /* Account for missing frames in BER tracking */
+ if (d > 1) {
+ fprintf(stderr, "[!] RTP %d missing frames assumed lost @%d\n", d-1, seq_number);
+ while (--d)
+ _gsm_ber(as, NULL, 0);
+ }
+
+ /* BER analysis */
+ rc = _gsm_ber(as, payload, payload_len);
+
+ if ((as->state == WAIT_LOOP) && (rc == 0))
+ as->state = RUNNING;
+}
+
+
+int main(int argc, char **argv)
+{
+ struct app_state _as, *as = &_as;
+ int rc, port;
+
+ /* Args */
+ if (argc < 2)
+ return -1;
+
+ port = atoi(argv[1]);
+
+ /* App init */
+ memset(as, 0x00, sizeof(struct app_state));
+
+ log_init(&log_info, NULL);
+ osmo_rtp_init(NULL);
+
+ /* Start auto-connect RTP socket */
+ as->rs = osmo_rtp_socket_create(NULL, 0);
+
+ as->rs->priv = as;
+ as->rs->rx_cb = rtp_rx_cb;
+
+ /* Jitter buffer gets in the way, we want the raw traffic */
+ osmo_rtp_socket_set_param(as->rs, OSMO_RTP_P_JIT_ADAP, 0);
+ osmo_rtp_socket_set_param(as->rs, OSMO_RTP_P_JITBUF, 0);
+
+ /* Bind to requested port */
+ fprintf(stderr, "[+] Binding RTP socket on port %u...\n", port);
+ rc = osmo_rtp_socket_bind(as->rs, "0.0.0.0", port);
+ if (rc < 0) {
+ fprintf(stderr, "[!] error binding RTP socket: %d\n", rc);
+ return rc;
+ }
+
+ /* We 'connect' to the first source we hear from */
+ osmo_rtp_socket_autoconnect(as->rs);
+
+ /* Main loop */
+ while (1)
+ osmo_select_main(0);
+
+ return 0;
+}
diff --git a/contrib/ber/rtp_gen_map.c b/contrib/ber/rtp_gen_map.c
new file mode 100644
index 00000000..40b70253
--- /dev/null
+++ b/contrib/ber/rtp_gen_map.c
@@ -0,0 +1,145 @@
+/* utility to generate codec_bit_class.h, a file with structures
+ * describing which [protection] class each bit of a given codec frame belongs to */
+
+/* (C) 2019 sysmocom - s.f.m.c. GmbH; Author: Sylvain Munaut
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdio.h>
+
+#include <osmocom/codec/codec.h>
+
+
+static int
+gen_table_fr(int *tbl)
+{
+ int i, j;
+
+ tbl[0] = tbl[1] = tbl[2] = tbl[3] = -1;
+
+ for (i = 0; i < 260; i++) {
+ j = 4 + gsm610_bitorder[i];
+ if (i < 50)
+ tbl[j] = 0; /* Class 1a */
+ else if (i < 182)
+ tbl[j] = 1; /* Class 1b */
+ else
+ tbl[j] = 2; /* Class 2 */
+ }
+
+ return GSM_FR_BYTES * 8;
+}
+
+static int
+gen_table_efr(int *tbl)
+{
+ int i, j, k;
+
+ tbl[0] = tbl[1] = tbl[2] = tbl[3] = -1;
+
+ for (i = 0; i < 260; i++) {
+ j = gsm660_bitorder[i];
+
+ if (j < 71)
+ k = j;
+ else if (j < 73)
+ k = 71;
+ else if (j < 123)
+ k = j - 2;
+ else if (j < 125)
+ k = 119;
+ else if (j < 178)
+ k = j - 4;
+ else if (j < 180)
+ k = 172;
+ else if (j < 230)
+ k = j - 6;
+ else if (j < 232)
+ k = 222;
+ else if (j < 252)
+ k = j - 8;
+ else
+ continue;
+
+ if (i < 50)
+ tbl[k] = 0; /* Class 1a */
+ else if (i < 182)
+ tbl[k] = 1; /* Class 1b */
+ else
+ tbl[k] = 2; /* Class 2 */
+ }
+
+ return GSM_EFR_BYTES * 8;
+}
+
+static int
+gen_table_amr_12_2(int *tbl)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ tbl[i] = -1;
+
+ for (i = 0; i < 244; i++)
+ tbl[i+16] = i < 81 ? 0 : 1;
+
+ for (i = 0; i < 4; i++)
+ tbl[i+16+244] = -1;
+
+ return 8 * 33;
+}
+
+
+static void
+print_table(const char *name, int *tbl, int len)
+{
+ int i;
+
+ printf("static const int %s[] = {\n", name);
+
+ for (i = 0; i < len; i++) {
+ if ((i & 15) == 0)
+ printf("\t");
+
+ printf("%2d", tbl[i]);
+
+ if (((i & 15) == 15) || (i == len-1))
+ printf(",\n");
+ else
+ printf(", ");
+ }
+
+ printf("};\n\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ int tbl[33*8];
+ int rv;
+
+ rv = gen_table_fr(tbl);
+ print_table("gsm_fr_bitclass", tbl, rv);
+
+ rv = gen_table_efr(tbl);
+ print_table("gsm_efr_bitclass", tbl, rv);
+
+ rv = gen_table_amr_12_2(tbl);
+ print_table("gsm_amr_12_2_bitclass", tbl, rv);
+
+ return 0;
+}
diff --git a/contrib/jenkins_bts_trx.sh b/contrib/jenkins_bts_trx.sh
index 54efa56f..9ac820d0 100755
--- a/contrib/jenkins_bts_trx.sh
+++ b/contrib/jenkins_bts_trx.sh
@@ -9,7 +9,8 @@ export LD_LIBRARY_PATH="$inst/lib"
osmo-build-dep.sh libosmocore "" --disable-doxygen
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
@@ -17,6 +18,7 @@ configure_flags="\
--enable-sanitize \
--enable-werror \
--enable-trx \
+ --enable-external-tests \
"
build_bts "osmo-bts-trx" "$configure_flags"
diff --git a/contrib/jenkins_common.sh b/contrib/jenkins_common.sh
index 6e4fa7e3..0c0060a9 100644
--- a/contrib/jenkins_common.sh
+++ b/contrib/jenkins_common.sh
@@ -43,7 +43,6 @@ build_bts() {
conf_flags="$*"
if [ "$WITH_MANUALS" = "1" ]; then
conf_flags="$conf_flags --enable-manuals"
- osmo-build-dep.sh osmo-gsm-manuals
export PATH="$inst/bin:$PATH"
fi
@@ -51,12 +50,12 @@ build_bts() {
./configure $conf_flags
$MAKE $PARALLEL_MAKE
$MAKE check || cat-testlogs.sh
- DISTCHECK_CONFIGURE_FLAGS="$conf_flags" $MAKE distcheck || cat-testlogs.sh
+ DISTCHECK_CONFIGURE_FLAGS="$conf_flags" $MAKE $PARALLEL_MAKE distcheck || cat-testlogs.sh
# Manuals: publish
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
$MAKE -C "$base/doc/manuals" publish
fi
- $MAKE maintainer-clean
+ $MAKE $PARALLEL_MAKE maintainer-clean
}
diff --git a/contrib/jenkins_lc15.sh b/contrib/jenkins_lc15.sh
index c7d62c96..89dd54b6 100755
--- a/contrib/jenkins_lc15.sh
+++ b/contrib/jenkins_lc15.sh
@@ -9,7 +9,8 @@ osmo-build-dep.sh libosmocore "" --disable-doxygen
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
osmo-layer1-headers.sh lc15 "$FIRMWARE_VERSION"
diff --git a/contrib/jenkins_oc2g.sh b/contrib/jenkins_oc2g.sh
index b8badce6..e4795cf5 100755
--- a/contrib/jenkins_oc2g.sh
+++ b/contrib/jenkins_oc2g.sh
@@ -9,7 +9,8 @@ osmo-build-dep.sh libosmocore "" --disable-doxygen
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
osmo-layer1-headers.sh oc2g "$FIRMWARE_VERSION"
diff --git a/contrib/jenkins_oct.sh b/contrib/jenkins_oct.sh
index bd57dd18..d1b6aee2 100755
--- a/contrib/jenkins_oct.sh
+++ b/contrib/jenkins_oct.sh
@@ -9,7 +9,8 @@ osmo-build-dep.sh libosmocore "" --disable-doxygen
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
osmo-layer1-headers.sh oct "$FIRMWARE_VERSION"
diff --git a/contrib/jenkins_oct_and_bts_trx.sh b/contrib/jenkins_oct_and_bts_trx.sh
index 67f67aa4..f188147d 100755
--- a/contrib/jenkins_oct_and_bts_trx.sh
+++ b/contrib/jenkins_oct_and_bts_trx.sh
@@ -9,7 +9,8 @@ export LD_LIBRARY_PATH="$inst/lib"
osmo-build-dep.sh libosmocore "" --disable-doxygen
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
@@ -20,6 +21,7 @@ configure_flags="\
--with-octsdr-2g=$deps/layer1-headers/ \
--enable-octphy \
--enable-trx \
+ --enable-external-tests \
"
build_bts "osmo-bts-octphy+trx" "$configure_flags"
diff --git a/contrib/jenkins_sysmobts.sh b/contrib/jenkins_sysmobts.sh
index d0d05ae6..87a98f33 100755
--- a/contrib/jenkins_sysmobts.sh
+++ b/contrib/jenkins_sysmobts.sh
@@ -9,7 +9,8 @@ osmo-build-dep.sh libosmocore "" --disable-doxygen
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-osmo-build-dep.sh libosmo-abis
+osmo-build-dep.sh libosmo-abis "" --disable-dahdi
+osmo-build-dep.sh libosmo-netif "" --disable-doxygen
cd "$deps"
osmo-layer1-headers.sh sysmo "$FIRMWARE_VERSION"
@@ -21,6 +22,7 @@ configure_flags="\
--enable-werror \
--enable-sysmocom-bts \
--with-sysmobts=$inst/include/ \
+ --enable-external-tests \
"
# This will not work for the femtobts
diff --git a/contrib/systemd/lc15bts-mgr.service b/contrib/systemd/lc15bts-mgr.service
index bf788e61..350a1a24 100644
--- a/contrib/systemd/lc15bts-mgr.service
+++ b/contrib/systemd/lc15bts-mgr.service
@@ -2,11 +2,15 @@
Description=osmo-bts manager for LC15 / sysmoBTS 2100
After=lc15-sysdev-remap.service
Wants=lc15-sysdev-remap.service
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
NotifyAccess=all
WatchdogSec=21780s
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
diff --git a/contrib/systemd/oc2gbts-mgr.service b/contrib/systemd/oc2gbts-mgr.service
index ed915b33..883e0ba0 100644
--- a/contrib/systemd/oc2gbts-mgr.service
+++ b/contrib/systemd/oc2gbts-mgr.service
@@ -2,11 +2,15 @@
Description=osmo-bts manager for OC-2G
After=oc2g-sysdev-remap.service
Wants=oc2g-sysdev-remap.service
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
NotifyAccess=all
WatchdogSec=21780s
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
diff --git a/contrib/systemd/osmo-bts-lc15.service b/contrib/systemd/osmo-bts-lc15.service
index 7c511100..03341bd3 100644
--- a/contrib/systemd/osmo-bts-lc15.service
+++ b/contrib/systemd/osmo-bts-lc15.service
@@ -1,17 +1,22 @@
[Unit]
Description=osmo-bts for LC15 / sysmoBTS 2100
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/osmo-bts-lc15 -t 2 -s -c /etc/osmocom/osmo-bts-lc15.cfg -M
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
RuntimeDirectory=osmo-bts
Restart=always
RestartSec=2
-RestartPreventExitStatus=1
-# The msg queues must be read fast enough
+# CPU scheduling policy:
CPUSchedulingPolicy=rr
-CPUSchedulingPriority=1
+# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
+CPUSchedulingPriority=11
+# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target
diff --git a/contrib/systemd/osmo-bts-oc2g.service b/contrib/systemd/osmo-bts-oc2g.service
index 860aeb1f..bc64a54c 100644
--- a/contrib/systemd/osmo-bts-oc2g.service
+++ b/contrib/systemd/osmo-bts-oc2g.service
@@ -1,17 +1,22 @@
[Unit]
Description=osmo-bts for OC-2G
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/osmo-bts-oc2g -s -c /etc/osmocom/osmo-bts-oc2g.cfg -M
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
RuntimeDirectory=osmo-bts
Restart=always
RestartSec=2
-RestartPreventExitStatus=1
-# The msg queues must be read fast enough
+# CPU scheduling policy:
CPUSchedulingPolicy=rr
-CPUSchedulingPriority=1
+# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
+CPUSchedulingPriority=11
+# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target
diff --git a/contrib/systemd/osmo-bts-sysmo.service b/contrib/systemd/osmo-bts-sysmo.service
index 92558172..3d996554 100644
--- a/contrib/systemd/osmo-bts-sysmo.service
+++ b/contrib/systemd/osmo-bts-sysmo.service
@@ -1,5 +1,7 @@
[Unit]
Description=osmo-bts for sysmocom sysmoBTS
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
@@ -7,13 +9,16 @@ ExecStartPre=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
ExecStart=/usr/bin/osmo-bts-sysmo -s -c /etc/osmocom/osmo-bts-sysmo.cfg -M
ExecStopPost=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
ExecStopPost=/bin/sh -c 'cat /lib/firmware/sysmobts-v?.bit > /dev/fpgadl_par0 ; sleep 3s; cat /lib/firmware/sysmobts-v?.out > /dev/dspdl_dm644x_0; sleep 1s'
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
-RestartPreventExitStatus=1
-# The msg queues must be read fast enough
+# CPU scheduling policy:
CPUSchedulingPolicy=rr
-CPUSchedulingPriority=1
+# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
+CPUSchedulingPriority=20
+# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target
diff --git a/contrib/systemd/osmo-bts-trx.service b/contrib/systemd/osmo-bts-trx.service
index 97c2b070..99e981c4 100644
--- a/contrib/systemd/osmo-bts-trx.service
+++ b/contrib/systemd/osmo-bts-trx.service
@@ -1,15 +1,24 @@
[Unit]
Description=Osmocom osmo-bts for osmo-trx
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/osmo-bts-trx -s -c /etc/osmocom/osmo-bts-trx.cfg
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
+User=osmocom
+Group=osmocom
+AmbientCapabilities=CAP_SYS_NICE
-# Let it process messages quickly enough
+# CPU scheduling policy:
CPUSchedulingPolicy=rr
-CPUSchedulingPriority=1
+# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
+CPUSchedulingPriority=11
+# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target
diff --git a/contrib/systemd/osmo-bts-virtual.service b/contrib/systemd/osmo-bts-virtual.service
index 16332669..2bca83be 100644
--- a/contrib/systemd/osmo-bts-virtual.service
+++ b/contrib/systemd/osmo-bts-virtual.service
@@ -1,15 +1,24 @@
[Unit]
Description=Osmocom GSM BTS for virtual Um layer based on GSMTAP/UDP
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/osmo-bts-virtual -s -c /etc/osmocom/osmo-bts-virtual.cfg
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
+User=osmocom
+Group=osmocom
+AmbientCapabilities=CAP_SYS_NICE
-# Let it process messages quickly enough
+# CPU scheduling policy:
CPUSchedulingPolicy=rr
-CPUSchedulingPriority=1
+# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
+CPUSchedulingPriority=11
+# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target
diff --git a/contrib/systemd/sysmobts-mgr.service b/contrib/systemd/sysmobts-mgr.service
index 4346991d..ef2751c7 100644
--- a/contrib/systemd/sysmobts-mgr.service
+++ b/contrib/systemd/sysmobts-mgr.service
@@ -1,9 +1,13 @@
[Unit]
Description=osmo-bts manager for sysmoBTS
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/sysmobts-mgr -ns -c /etc/osmocom/sysmobts-mgr.cfg
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
diff --git a/debian/changelog b/debian/changelog
index 5cb0f0ac..410c549a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,1399 @@
+osmo-bts (1.7.0) unstable; urgency=medium
+
+ [ arehbein ]
+ * common: Fix memleak in get_smscb_block()
+ * doc: Adapt to use of 'telnet_init_default'
+ * common: Remove redundant checks
+ * common: Remove unused function gsm_objclass2nmstate()
+ * gsm_objclass2mo(): Change signature/set NACK cause
+ * gsm_objclass2obj(): Change signature/set NACK cause
+ * PCU interface: Log version when starting listener
+ * common: Have PCU socket connection use osmo_wqueue
+ * common: Make socket queue max. length configurable
+
+ [ Max ]
+ * bts-virtual: fix segfault
+ * osmo-bts-trx: log TRXC/TRXD connection address
+ * osmo-bts-trx: use bool for true/false flags
+ * GSMTAP: allow configuring local address
+ * license: fix typos
+
+ [ Vadim Yanitskiy ]
+ * paging_add_imm_ass(): remove meaningless from_pcu argument
+ * osmo-bts-{trx,virtual}: clean up bts_model_l1sap_down()
+ * osmo-bts-{trx,virtual}: check lchan against NULL in bts_model_l1sap_down()
+ * osmo-bts-{trx,virtual}: set rc on error in bts_model_l1sap_down()
+ * GSMTAP: print 'gsmtap-local-host' if not NULL
+ * osmo-bts-virtual: indicate BTS_FEAT_[E]GPRS to the BSC
+ * rsl: remove redundant gsm_lchan_name() in rsl_tx_rf_rel_ack()
+ * rsl: reduce logging verbosity on some messages
+ * tests: use -no-install libtool flag to avoid ./lt-* scripts
+ * scheduler: log pchan value in trx_sched_set_pchan()
+ * osmo-bts-virtual: properly handle dynamic TS in vbts_set_ts()
+ * contrib/osmo-bts.spec.in: do not depend on libosmogb
+ * osmo-bts-trx: properly activate [CBCH/]BCCH/CCCH
+ * rsl: rsl_handle_chan_mod_ie(): add missing GSM48_CMODE_* values
+ * osmo-bts-{sysmo,lc15,oc2g}: fix segfault in ph_tch_req()
+ * tests: $(BUILT_SOURCES) is not defined, depend on osmo-bts-virtual
+ * osmo-bts-virtual: properly activate [CBCH/]BCCH/CCCH
+ * flags: add missing entries to bts_impl_flag_desc[]
+ * flags: group BTS_INTERNAL_FLAG_* into an enum
+ * flags: ensure completeness of bts_impl_flag_desc[]
+ * fixup: common: Remove unused function gsm_objclass2nmstate()
+ * oml: gsm_objclass2{mo,obj}(): cosmetic: return immediately
+ * oml: gsm_objclass2{mo,obj}(): set cause for unknown obj_class
+ * oml: reset BCCH carrier power reduction mode (if enabled)
+ * copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
+ * osmo-bts-trx: alloc/free burst buffers in trx_sched_set_lchan()
+ * osmo-bts-trx: use direct pointer to chan_state->{ul,dl}_bursts
+ * osmo-bts-trx: tch_dl_dequeue(): do not drop CSD frames
+ * osmo-bts-trx: tx_pdtch_fn(): use msgb_l2len()
+ * osmo-bts-trx: fix recent regression in Tx lchan handlers
+ * osmo-bts-trx: remove redundant memset() on receipt of NOPE.ind
+ * l1sap: use gsm0502_fn2ccch_block() from libosmogsm
+ * scheduler: fix wrong union field in _sched_compose_tch_ind()
+ * scheduler: use msgb_hexdump_l2() in _sched_compose_tch_ind()
+ * scheduler: unify argument names/order for _sched_compose_*_ind()
+ * scheduler: constify *data pointer in _sched_compose_*_ind()
+ * scheduler: use size_t for data_len in _sched_compose_*_ind()
+ * fix bts_supports_cm(): properly check feature flags for VGCS/VBS
+ * measurement: suppress unsupported tch_mode warnings for CSD
+ * osmo-bts-trx: pull the AMR header in tch_dl_dequeue()
+ * osmo-bts-trx: implement CSD scheduling support
+ * osmo-bts-trx: implement FACCH/[FH] support for CSD
+ * osmo-bts-trx: implement TCH/F2.4 support for CSD
+ * osmo-bts-trx: visualize rx_tch[fh]_fn() functions
+ * osmo-bts-trx: unify and enrich 'Received bad data' logging
+ * osmo-bts-trx: rx_tchf_fn(): move compute_ber10k() above
+ * osmo-bts-trx: rx_tch[fh]_fn(): combine rc-checking ifs
+ * osmo-bts-trx: change 'Received bad data' back to LOGL_DEBUG
+ * osmo-bts-trx: tx_tch[fh]_fn(): fix NULL pointer dereference
+ * osmo-bts-trx: document/clarify the meaning of BUFMAX=24
+ * l1sap: proper rate adaptation for CSD (RFC4040 'clearmode')
+ * csd_v110_rtp_encode(): properly set E1/E2/E3 bits
+ * osmo-bts-trx: bts_supports_cm_data(): allow non-transparent modes
+ * rsl: rsl_handle_chan_mod_ie(): set lchan->csd_mode
+ * rsl: rsl_handle_chan_mod_ie(): do not use legacy defines
+ * csd_v110: fix comments in csd_v110_rtp_{en,de}code()
+ * csd_v110: properly set E1/E2/E3 for non-transparent data
+ * csd_v110: handle empty/incomplete Uplink frames gracefully
+
+ [ Philipp Maier ]
+ * pcu_sock: rename rc to fd
+ * pcu_sock: cosmetic: remove whitespace after type cast
+ * pcu_sock: cosmetic: remove unnecessary line breaks
+ * pcu_sock: do not mess with the osmo fd flags directly
+ * sched_lchan_tchx: use GSM_HR_BYTES_RTP_RFC5993 constant
+ * l1sap: fix wording in comment
+ * pcu_sock: don not continue when running out of TRX space
+ * paging: cosmetic: rename all IMM.ASS references to MAC block
+ * paging: parse PCUIF data indication outside of paging.c
+ * paging: do not confirm PAGING COMMAND messages
+ * pcu_sock: move variable declaration of imsi[4] into related scope
+ * l1sap: cosmetic: rename payload_len to rtp_pl_len
+ * pcu_sock: use PCUIF version 11 (direct TLLI)
+ * paging: also accept zero length IMSI strings 3
+ * pcuif_proto: rename tlli to msg_id
+ * pcu_sock: get rid of fn parameter in pcu_tx_pch_data_cnf
+ * pcuif_proto: remove unnecessary members from gsm_pcu_if_data_cnf_dt
+ * pcuif_proto: get rid of _DT, _dt (Direct TLLI)
+ * bts: make bts_agch_dequeue static
+ * pcuif_proto: use confirm flag in struct gsm_pcu_if_pch
+ * pcu_sock: use PCU_IF_SAPI_AGCH_2 instead PCU_IF_SAPI_AGCH
+ * pcu_sock: print SAPI and msg_id when sending confirmation
+
+ [ Pau Espin Pedrol ]
+ * bts-trx: Fix no NM Radio{Carrier,Channel} switching to Enabled if one TRX is rf_locked
+ * pcu_sock: Submit all DATA.ind regardless of link quality
+ * pcu_sock.c: Call osmo_fd_unregister() before closing and changing bfd->fd
+ * Rewrite pcu_sock_write()
+ * lchan: Improve error path logging in gsm_pchan2chan_nr()
+ * cosmetic: gsm_pchan2chan_nr(): Update spec documentation
+ * cosmetic: bts_trx.h: Fix whitespace
+ * Avoid tx RF Resource Ind for disabled TRX
+ * bts-trx: Avoid pushing interf_meas for disabled TRX
+ * contrib/ber: Avoid regenerating codec_bit_class.h every build
+ * bts-trx: Drop unused param to internal function
+ * Clarify configuration of TSC on each timeslot
+ * bts_model_apply_oml(): Drop unneded code
+ * oml.c: Remove dot character at the end of log lines
+ * nm: Apply BTS/TRX/TS OML Attributes through NM FSMs
+ * nm: Drop NM_EV_SETATTR_{ACK/NACK}
+ * oml: Get rid of unused tlv_parsed param in bts_model_apply_oml()
+ * bts_model_apply_oml(): Improve definition of parameter
+ * lc15,oc2g,sysmo: Update GPRS NM object state at the right time
+ * Simplify implementation of bts_model_opstart() in all bts types
+ * nm: Apply OPSTART through NM FSMs
+ * NM: NACK received OML OPSTART if no attributes were set beforehand
+ * Introduce NM FSM for GPRS NSE object
+ * Fix octet 2 of NM GPRS Cell
+ * Introduce NM FSM for GPRS Cell object
+ * Rearrange declaration of struct gsm_bts_gprs_nsvc
+ * Move NSVC structs to be part of NSE
+ * bts: Simplify lifecycle of BTS inside bts_list
+ * Introduce NM FSM for GPRS NSVC object
+ * nm: Dispatch NM_EV_SW_ACT in cascade to BTS SiteMgr children
+ * Merge gsm_network into gsm_bts_sm and place gsm_bts under it
+ * Move GPRS NSE under BTS SiteMgr
+ * Drop NM_EV_BBTRANSC_INSTALLED in favour of generic NM_EV_SW_ACT
+ * nm: Document current state of SW_ACT in TRX related objects
+ * Properly report all states through NM FSM upon OML link up
+ * Update g_bts_sm->num_bts when bts is added/removed from bts list
+ * Move pcu_sock_state to gprs section of bts_sm
+ * pcu_sock: Allocate pcu_sock_state using g_bts_sm talloc context
+ * pcu_sock: Drop bts_sm pointer
+ * oml: Fix potential null ptr access on trx object
+ * bts-sysmo: Fix pinst->version filled too early
+ * bts-sysmo: Delay marking phy_link as connected until L1 reset + got info
+ * vty.c: Use already available tpp pointer
+ * octphy: Fix clearly wrong noop assignment
+ * bbtransc/rcarrier: Fix statechg done twice upon NM_EV_RX_OPSTART
+ * Increase PCUIF wqueue size
+ * bts-trx: Fix CCCH not enabled if BS_AG_BLKS_RES!=1 is provided by BSC
+ * rsl: Improve logic reactivating CCCH upon SI3 BS_AG_BLKS_RES change
+
+ [ Oliver Smith ]
+ * gitignore: add vty pdf
+ * doc: rsl: add RSL_IE_IPAC_RTP_CSD_FORMAT
+ * rsl_rx_ipac_XXcx: parse csd_fmt_d/ir
+ * debian: set compat level to 10
+ * systemd: depend on networking-online.target
+ * gitignore: add arm-poky-linux-gnueabi-libtool
+ * osmo-bts-sysmo: trx_mute_on_init_cb: call bts_update_status
+ * osmo-bts-sysmo: activate_rf: no dispatch on fail
+ * osmo-bts-sysmo/l1_if: move mute_rf_compl_cb up
+ * osmo-bts-sysmo: mute PHY until OML is ready
+
+ [ Harald Welte ]
+ * DTX: bts-{sysmo,oc2g,lc15}: Print DEBUG messages about ONSET
+ * cosmetic: Replace %i with %d
+ * Introduce LOGPLCFN() for logging lchan-name + frame number
+ * bts-{sysmo,oc2g,lc15}: Fix RTP of AMR SID_FIRST_P1
+ * common/vty: Print AMR MultiRate Configuration in "show lchan"
+ * bts-{sysmo,oc2g,lc15}: Dump logical channel params during MPH-ACTIVATE.req
+ * cosmetic: use __func__ instead of __FUNCTION__
+ * lc15: fix compiler warning about wrong indent
+ * lc15: Remove unused warning
+ * lc15/oc2g: remove unused variables
+ * oc2g: Fix 'unused variable' compiler warning
+ * cosmetic: Remove "FIXME?" from Odd AMR CMI phase
+ * lc15: fix compiler warning about unused variable cell_size
+ * Replace explicit gsm_lchan_name() calls with LOGPLCHAN
+ * logging: Introduce LOGPLCGT()
+ * cosmetic: Change LOGPLCFN argument order
+ * paging: Add support for generating NLN/NLN-Status in P1 Rest Octets
+ * Add ASCI (advanced speech call items) log sub-system
+ * ASCI: NCH / NOTIFICATION support
+ * validate RSL "channel rate and type" against VGCS/VBS flags
+ * Store "Channel rate and type" from RSL Channel Mode IE in BTS
+ * ASCI: VGCS/VBS RACH -> RSL TALKER/LISTENER DETECT
+ * sysmo: Enable VGSCS + VBS feature flags
+ * omldummy: Claim to support VBS + VGCS towards BSC
+
+ [ Mychaela N. Falconia ]
+ * trx: detect UL SID in EFR just like in FR
+ * sysmo: fix handling of SID in EFR
+ * common: implement rtp continuous-streaming mode
+ * rtp continuous-streaming: fix BFI in the quality-suppressed case
+ * sysmo: emit empty RTP ticks during FACCH stealing on TCH/F
+ * bts-{lc15,oc2g,sysmo}: support EFR in repeat_last_sid()
+ * RTP input, FR & EFR: preen incoming payloads for SID errors
+ * lc15,oc2g: fix handling of SID in EFR
+ * all models, FR/EFR UL: change SID check to _is_any_sid()
+ * trx: remove model-specific BFI packet formats
+ * refactor: replace rtppayload_is_valid() with preening before enqueue
+ * all models, HR1 codec: accept both TS101318 and RFC5993 formats
+ * trx: fix HR1 codec breakage from format change
+ * trx, HR1 codec: change UL PHY output format to TS 101 318
+ * all models, HR1 codec: select RTP output format via vty option
+ * FR/HR/EFR TCH DL: implement DTX rules
+ * HR1 codec: validate ToC header in RFC5993 RTP input
+ * HR1 codec: act on SID indication in RFC5993 RTP input
+ * trx TCH DL: transmit invalid speech blocks instead of dummy FACCH
+ * ECU in UL path: make it optional per vty config
+ * ECU in UL path: move state alloc/free to l1sap
+ * ECU in UL path: move it from trx model to l1sap
+
+ [ Sylvain Munaut ]
+ * contrib: Add BER testing tool
+
+ [ Andreas Eversberg ]
+ * Change return value of bts_supports_cm() from int to bool
+ * ASCI: Add function to reactivate channel
+ * ASCI: Retrieve NCH position from System Information 1
+ * ASCI: Add Notification CHannel (NCH) support
+ * ASCI: Add support for rest octets in Paging request type 2 and 3
+ * ASCI: Send only NLN on Paging request type 1 rest octets
+ * ASCI: Add Notification/FACCH support
+ * ASCI: Repeat UPLINK FREE message until uplink becomes busy
+ * Add test cases for rest octets of Paging Requests
+ * ASCI: Enable UPLINK ACCESS on various BTS models
+
+ [ Keith ]
+ * Fix incorrect order of params passed to logging macro
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 16:05:30 +0200
+
+osmo-bts (1.6.0) unstable; urgency=medium
+
+ [ Vadim Yanitskiy ]
+ * osmo-bts-trx: call osmo_timer_del() unconditionally
+ * osmo-bts-trx: amr_loop: trigger the loop unconditionally
+ * osmo-bts-trx: fix handling of ciphering params in PRIM_INFO_MODIFY
+ * osmo-bts-trx: rx_rach_fn(): properly detect handover RACH
+ * osmo-bts-trx: handle MTS 0b0110 indicating an Access Burst
+ * osmo-bts-trx: use lookup tables for checking AMR CMI/CMR on Downlink
+ * osmo-bts-trx: drop ul_amr_fn_is_cmi() / dl_amr_fn_is_cmi()
+
+ [ Pau Espin Pedrol ]
+ * rsl: rx ipac crcx/mdcx: Log payload_type2
+ * logging: Move category descriptions to be in order with enum
+ * Clean up osmo-bts-*/Makefile.am
+ * Split out lchan rtp socket creation from rsl handling code
+ * Avoid counting lchan->dl_tch_queue length every time a msg is enqueued
+ * Use libosmocore API msgb_queue_free() to free lists
+ * rsl: Reduce scope of variable
+ * Move lchan_dl_tch_queue_enqueue to lchan.c and make it public
+ * cosmetic: Fix formatting of if-else block brackets
+ * Depend on libosmo-netif
+ * Clarify RTP AMR header offset in TCH enc/dec
+ * tests/*/Makefile.am: Fix typo in LIBOSMONETIF_CFLAGS
+ * tests/*/Makefile.am: Add missing libosmo-netif cflags
+ * oc2g: Makefile.am Fix typo in LIBOSMONETIF_LIBS
+ * Introduce Osmux support
+ * abis: Avoid TCP/IPA RSL sockets continue conn establishment while shutting down
+ * osmux: Log sendto() error
+ * lchan: Reset Abis RTP/Osmux config during lchan release
+ * vty: Fix SPEECH_MODE printed with hex prefix but dec value
+ * vty: Print Osmux CID on lchans using Osmux
+ * Allocate struct osmux_in_handle through new libosmo-netif APIs
+ * osmux: Drop logging of osmux internal counters
+ * osmux: Match remote address in osmux_lchan_find()
+ * osmux: Log remote address upon rx of osmux pkt
+ * osmux: Lower log level when osmux batch received for unknown CID
+ * osmux: nullify osmux.rtpst after freeing it
+ * osmux: Skip lchans in lookup which still have no remote associated
+ * osmux: Close osmux socket when bts is freed
+ * osmux: Fix null ptr dereference sending UL data before the remote is configured
+ * osmux: Rotate over available Osmux CID when allocating a new one
+ * osmux: Use new osmux_xfrm_input API to set name on each link
+ * vty: Fix typo in write-config: osmux / local-port
+ * vty: Fix typo in symbol name
+
+ [ Max ]
+ * Set working directory in systemd service file
+ * Don't manually create pid file
+ * Document realtime options in .service units
+ * Update realtime scheduling priority in service file
+ * ctrl: take both address and port from vty config
+ * Add SI10 support
+
+ [ Philipp Maier ]
+ * pcu_sock: fix sourcecode formatting
+ * measurement: do not call msgb_l3len without checking
+ * l1sap: do not call msgb_l2hlen without checking
+ * rsl: use unsigned int
+ * pcuif_proto: cosmetic: add constant PCU_IF_NUM_NSVC and replace magic numbers
+ * sched_lchan_tchf: replace numeric constant with define constant
+ * l1sap: remove unused pointer variable
+ * pcuif_proto: use define constant to specify nax number of trx
+ * pcu_sock: use ARRAY_SIZE rather then magic number
+
+ [ Keith ]
+ * osmo-bts-trx: respond to tx-attenuation config in real time.
+
+ [ Harald Welte ]
+ * update outdated vty copyright statement
+
+ [ Daniel Willmann ]
+ * shutdown_fsm: Only ramp down power when stopping bts through Ctrl-C
+ * shutdown_fsm: Add power_ramp_force() to jump straight to the tgt power
+
+ [ daniel ]
+ * Revert "shutdown_fsm: Only ramp down power when stopping bts through Ctrl-C"
+
+ [ Alexander Couzens ]
+ * OML: NSVC[1] MO should have the same initial state as NVSC[0]
+
+ [ Oliver Smith ]
+ * oc2gbts_mgr_calib: fix build against gpsd >= 3.20
+ * contrib/jenkins: build libosmo-abis without dahdi
+
+ [ arehbein ]
+ * osmo-bts: Transition to use of 'telnet_init_default'
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:15:52 +0100
+
+osmo-bts (1.5.0) unstable; urgency=medium
+
+ [ Pau Espin Pedrol ]
+ * bts_shutdown_fsm.h: Remove wrong comment describing enum
+ * bts: Properly free bts->shutdown_fi when struct gsm_bts is freed
+ * bts-trx: amr: Fix return code of osmo_amr_rtp_dec() checked too late
+ * Change some log levels NOTICE->INFO
+ * rsl: Conditionally decrease log level if cause is normal event
+ * bts-trx: Log lchan if avaialble in Meas Avg
+ * doc: rsl: Fix description of 'IP Connection Statistics' IE
+ * bts-trx: sched_lchan_tchh.c: Workaround gcc false positive error
+ * bts-sysmo: Replace use of deprecated ipa_client_conn_create API
+
+ [ Harald Welte ]
+ * cbch: Fix bts_smscb_state_reset() to avoid double-free
+ * cbch: Fix dangling cur_msg leading to double-free in bts_cbch_reset()
+ * [lc15,oc2g,octphy] Fix memory leak on write queue overflow
+ * update git URLs (git -> https; gitea)
+
+ [ Oliver Smith ]
+ * debian/control: add osmo-bts meta-package
+ * treewide: remove FSF address
+ * model_init: order features alphabetically
+ * model_init: set BTS_FEAT_PAGINATION_COORDINATION
+ * model_init: order features alphabetically, part 2
+ * src/common/bts.c: set BTS_FEAT_PAGING_COORDINATION
+ * src/common/bts.c: set BTS_FEAT_CCN
+
+ [ Vadim Yanitskiy ]
+ * oml: use proper talloc context in oml_rx_set_radio_attr()
+ * oml: use ts->trx as talloc-context in oml_rx_set_chan_attr()
+ * oml: fix copy-pasted comments in oml_rx_set_*_attr()
+ * oml: assign unique names to 'struct tlv_parsed' chunks
+ * osmo-bts-trx: use l1ts as talloc context for burst buffers
+ * osmo-bts-trx: fix a memleak in trx_sched_set_lchan()
+ * cbch: cosmetic: use talloc_zero() in bts_process_smscb_cmd()
+ * phy_instance_destroy(): fix NULL pointer dereference
+ * logging: get rid of logging category DSUM
+ * osmo-bts-trx: make use of OSMO_UNLIKELY() when handling TRXD PDUs
+ * osmo-bts-trx: cosmetic: use rate_ctr_inc2() instead of rate_ctr_inc()
+ * osmo-bts-trx: new rate counter 'trx_sched:dl_fh_cache_miss'
+ * VTY: fix ambiguity in BTS specific command definitions
+ * osmo-bts-trx: do not run osmo_{fr,hr}_check_sid() on FACCH/U frames
+ * osmo-bts-trx: rx_tchh_fn(): do not calculate BER10k for FACCH twice
+ * rsl: fix wrong IE being checked in rsl_rx_chan_activ()
+ * osmo-bts-trx: rx_tchh_fn(): fix HR SID detection (wrong offset)
+ * osmo-bts-trx: rx_tchh_fn(): mark valid SID frames as such
+ * osmo-bts-trx: use consistent naming for 'enum sched_meas_avg_mode'
+ * osmo-bts-trx: use a lookup table in trx_sched_meas_avg()
+ * osmo-bts-trx: rx_tchh_fn(): use proper meas averaging mode
+ * trx_sched_ul_burst(): get rid of the 'switch' statement
+ * fix gsm_bts_get_cbch(): CBCH can be allocated on Cn
+ * osmo-bts-trx: rx_tchh_fn(): indicate BER10k=0 for FACCH BFIs
+ * osmo-bts-trx: rx_tchh_fn(): get rid of chan_state->meas_avg_facch
+ * osmo-bts-trx: rx_{tchf,tchh}_fn(): also use meas_avg for BFI
+ * osmo-bts-trx: rx_{tchf,tchh}_fn(): shift Rx burst buffer on bid=0
+ * osmo-bts-trx: rx_{tchf,tchh}_fn(): ensure complete set of bursts
+ * osmo-bts-trx: rx_{tchf,tchh}_fn(): get TDMA FN from meas history
+ * osmo-bts-trx: rx_{tchh,tchf}_fn(): use AMR CMI lookup tables
+ * osmo-bts-trx: rx_{tchh,tchf}_fn(): use tch_mode directly
+ * osmo-bts-trx: rx_tchh_fn(): fix meas reporting in signalling mode
+ * osmo-bts-trx: move AMR CMI lookup tables to the respective files
+ * osmo-bts-trx: rx_tchh_fn(): fix indexes in the AMR CMI lookup table
+ * osmo-bts-trx: rx_tchf_fn(): clarify indexes in the AMR CMI lookup table
+ * power_ctrl_params_def_reset(): set .ctrl_interval for both UL/DL
+ * scheduler: remove redundant OSMO_ASSERT() statements
+ * scheduler: rts_tchh_fn(): use a lookup table for FACCH/H
+ * osmo-bts-trx: rx_tchh_fn(): use a lookup table for FACCH/H
+ * osmo-bts-{trx,virtual}: tx_tchh_fn(): remove FACCH/H alignment check
+ * osmo-bts-trx: rename 'loops.[ch]' to 'amr_loop.[ch]'
+ * osmo-bts-trx: use '#pragma once' in amr_loop.h
+ * osmo-bts-trx: amr_loop: remove unneeded #includes
+ * rsl: de-duplicate parsing of MultiRate configuration IE
+ * rsl: rsl_rx_chan_{activ,modif}: do not sent an Error Report
+ * rsl: parse_multirate_config(): check if AMR codec is used
+ * logging: use a different color tone for DLOOP
+ * rsl: always check return value of rsl_tlv_parse()
+ * rsl: misc / cosmetic fixes for tx_ipac_XXcx_nack()
+ * osmo-bts-virtual: remove unused 'codec_mode_request' argument
+ * l1sap: l1sap_chan_act(): alloc DTX FSM only for TCH
+ * l1sap: l1sap_chan_act(): remove unused *tp argument
+ * osmo-bts-trx: bts_report_interf_meas(): remove unused fn param
+ * rsl: use hard-coded defaults if the MultiRate conf IE is absent
+ * tests/amr/Makefile.am: use proper binary name prefix 'amr_test_'
+ * tests/amr: add a unit test for amr_parse_mr_conf()
+ * amr: fix parsing of threshold and hysteresis in amr_parse_mr_conf()
+ * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
+ * struct amr_multirate_conf: remove ms_mode[], raname bts_mode[]
+ * common: fix coding style: if is not a function
+ * osmo-bts-trx: amr_loop: simplify trx_loop_amr_set()
+ * osmo-bts-trx: use C/I in the AMR link adaptation loop
+ * osmo-bts-trx: amr_loop: improve logging in trx_loop_amr_input()
+ * osmo-bts-trx: amr_loop: allow upgrading codec mode > 0
+ * osmo-bts-trx: amr_loop: log if AMR mode remains unchanged
+ * osmo-bts-trx: amr_loop: do not miss C/I samples
+ * osmo-bts-trx: prioritize FACCH in s/tx_tch_common()/tch_dl_dequeue()/s
+ * osmo-bts-trx: tx_tchh_fn(): make handling of FACCH/H cleaner
+ * osmo-bts-trx: fix scheduling of dummy FACCH/H and FACCH/F
+ * VTY: fix NULL-pointer dereference in 'show transceiver'
+ * osmo-bts-trx: check if scheduling of [dummy] FACCH/H is allowed
+ * osmo-bts-trx: rx_{tchh,tchf}_fn(): improve logging of AMR DTX frames
+ * pcu_sock: comment out {dl,ul}_tbf_ext related warnings
+ * osmo-bts-trx: drop Uplink loss detection from Downlink path
+ * scheduler: trx_sched_is_sacch_fn(): make ts pointer const
+ * struct bts_ul_meas: reflect C/I units in field name s/c_i/ci_cb/
+ * tests/meas: improve logging in test_ts45008_83_is_sub_single()
+ * tests/meas: improve test_ts45008_83_is_sub_is_sub()
+ * measurement: log SUB/FULL as text in lchan_new_ul_meas()
+ * measurement: move SACCH detection to process_l1sap_meas_data()
+ * measurement: fix matching of SUB frames by TDMA FN
+ * osmo-bts-trx: rx_tchf_fn(): do not treat AFS_SID_UPDATE as SUB frame
+ * Revert "osmo-bts-trx: rx_tchf_fn(): do not treat AFS_SID_UPDATE as SUB frame"
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 29 Jun 2022 09:41:38 +0200
+
+osmo-bts (1.4.0) unstable; urgency=medium
+
+ [ Philipp Maier ]
+ * l1sap: Store status of SRR in an lchan struct memeber
+ * l1sap: add logging and VTY introspection for ACCH repetition
+ * sched_lchan_tchh: fix frame number and fill FACCH gap
+ * main,abis: change model name from sysmoBTS to osmo-bts
+ * paging: prioritize CS related paging over PS related pagings.
+ * allow to configure multiple oml remote-ip addresses
+ * sched_lchan_tch_x: do not use cmr as ft
+ * sched_lchan_tch_x: use functions to determine AMR tranmssion phase
+ * sched_lchan_tch_x: use ul_cmr and ul_ft when generating RTP bad frame
+ * rsl: simplfy parse_repeated_acch_capability
+ * rsl: parse temporary overpower value RSL CHAN ACT / MODIFY
+
+ [ Vadim Yanitskiy ]
+ * doc/examples: remove obsolete power control parameters
+ * doc/examples: enable stderr logging for osmo-bts-virtual.cfg
+ * osmo-bts-trx: fix: do not call trx_if_close() two times
+ * osmo-bts-trx: fix segfault on trx_phy_inst_open() failure
+ * l1sap: use the passed 'trx' pointer in l1sap_chan_act()
+ * l1sap: use TLVP_PRES_LEN() macro in l1sap_chan_act()
+ * l1sap: check BTS_FEAT_MULTI_TSC in l1sap_chan_act()
+ * l1sap: fix wrong IEI and parsing in l1sap_chan_act()
+ * manuals: fix wrong VTY node for 'gsmtap-sapi' command
+ * manuals: document GSMTAP 'enable-all' / 'disable-all'
+ * osmo-bts-trx: correct definition of 'osmotrx rx-gain' command
+ * rsl: do not blindly ignore unhandled/unknown Channel Mode
+ * manuals: remove deprecated command line parameters
+ * manuals: document new 'gsmtap-remote-host' command
+ * l1sap: fix incorrect pointer cast in l1sap_chan_act()
+ * rsl: rename, fix and refactor lchan_tchmode_from_cmode()
+ * rsl: add missing Channel Mode values to rsl_handle_chan_mod_ie()
+ * lchan2lch_par(): fix missing default branch in switch
+ * osmo-bts-trx: cosmetic: TRXD 'header version' -> 'PDU version'
+ * osmo-bts-trx: remove outdated TRXD protocol documentation
+ * osmo-bts-trx: cosmetic: use '#pragma once' in trx_if.h
+ * osmo-bts-trx: define TRXC/TRXD message buffer size
+ * osmo-bts-trx: 'burst type' is actually modulation type
+ * osmo-bts-trx: move MTS parser into trx_data_parse_mts()
+ * osmo-bts-trx: discard TRXD PDUs with unexpected version
+ * osmo-bts-trx: move TDMA frame number check to trx_data_read_cb()
+ * osmo-bts-trx: cosmetic: get rid of TRX_CHDR_LEN macro
+ * osmo-bts-trx: generalize checking of TRXD header length
+ * osmo-bts-trx: pass 'struct phy_instance' to TRXD dissectors
+ * osmo-bts-trx: refactor handling of version specific TRXD parts
+ * osmo-bts-trx: enlarge and share TRXD message buffer
+ * osmo-bts-trx: assert PDU version in trx_if_send_burst()
+ * osmo-bts-trx: reduce code nasting in trx_if_send_burst()
+ * vty: fix the use of deprecated osmo_bts_feature_name()
+ * common/abis: fix the use of deprecated e1inp_line_get() API
+ * osmo-bts-trx: refactor parse_rsp(), fix compilation warnings
+ * rsl: fix wrong value printed in rsl_handle_chan_mod_ie()
+ * struct gsm_bts_trx: remove unused leftovers from openbsc
+ * common/sysinfo: make struct gsm_bts_trx const in num_agch()
+ * osmo-bts-{lc15,oc2g}: drop redundant checks in VTY commands
+ * [VAMOS] struct gsm_bts_trx: fix the PHY instance pointer
+ * [VAMOS] Merge bts_trx_init() into gsm_bts_trx_alloc()
+ * [VAMOS] osmo-bts-trx: move {chan,bid} to trx_{dl,ul}_burst_{req,ind}
+ * osmo-bts-trx: implement TRXDv2 protocol support
+ * scheduler.h: cosmetic: use #pragma once
+ * osmo-bts-trx: cosmetic: s/trx_sched_fn/bts_sched_fn/g
+ * osmo-bts-trx: remove redundant assert() in bts_sched_fn()
+ * osmo-bts-trx: fix hopping pointer bug in bts_sched_fn()
+ * [VAMOS] Re-organize osmo-bts-trx specific structures
+ * osmo-bts-trx: clarify logging messages in trx_if_{open,close}()
+ * osmo-bts-{trx,virtual}: fix: pinst->trx may be NULL
+ * common: make the arguments of phy_{link,instance}_name() const
+ * [VAMOS] common: make 'struct gsm_bts_trx_ts' pointers const
+ * [VAMOS] gsm_data.h: fix wrong bit-mask in BSIC2BCC macro
+ * [VAMOS] gsm_data.h: introduce and use BTS_TSC macro
+ * common: phy_links_open(): warn about dangling PHY instances
+ * [VAMOS] osmo-bts-trx: rework and split up bts_sched_fn()
+ * Fix regression in 'osmo-bts-trx: rework and split up bts_sched_fn()'
+ * [VAMOS] osmo-bts-trx: implement and enable PDU batching for TRXDv2
+ * [VAMOS] osmo-bts-trx: indicate MTS in Downlink TRXDv2 PDUs
+ * [VAMOS] rsl_rx_mode_modif(): handle Channel Identification IE
+ * [VAMOS] rsl: call bts_supports_cm() from rsl_handle_chan_mod_ie()
+ * [VAMOS] bts_supports_cm(): handle RSL_CMOD_CRT_OSMO_TCH_VAMOS_{Bm,Lm}
+ * [VAMOS] common/scheduler: unify symbol names for training sequences
+ * [VAMOS] osmo-bts-trx: rework handling of Training Sequence
+ * [VAMOS] osmo-bts-trx: properly handle per-timeslot TSC values
+ * [VAMOS] scheduler: add new GMSK training sequences from 3GPP 45.002
+ * [VAMOS] l1sap_chan_act(): handle Osmocom specific TSC IE
+ * [VAMOS] common/oml: generalize checking BTS_FEAT_MULTI_TSC
+ * [VAMOS] gsm_pchan2chan_nr(): use ABIS_RSL_CHAN_NR_CBITS_* macros
+ * [VAMOS] rsl_lchan_lookup(): use ABIS_RSL_CHAN_NR_CBITS_* macros
+ * [VAMOS] rsl_lchan_lookup(): make it more readable
+ * [VAMOS] gsm_data: rework and rename gsm_lchan_name_compute()
+ * [VAMOS] l1sap: get_lchan_by_chan_nr() may return NULL
+ * [VAMOS] oml_rx_set_chan_attr(): clarify NM_ATT_CHAN_COMB handling
+ * manuals/abis/rsl.adoc: s/TS 08.58/TS 48.058/
+ * manuals/abis/rsl.adoc: rework Channel Number description
+ * manuals/abis/rsl.adoc: add missing CBCH Channel Number values
+ * manuals/abis/rsl.adoc: add VAMOS specific Channel Number values
+ * osmo-bts-trx: fix NULL pointer dereference in trx_if_send_burst()
+ * trx_sched_is_sacch_fn(): fix handling of dynamic timeslots
+ * [VAMOS] scheduler: drop meaningless channel number checks
+ * [VAMOS] conf_lchans_as_pchan(): improve readability
+ * [VAMOS] Implement the concept of 'shadow' timeslots
+ * [VAMOS] osmo-bts-trx: schedule bursts on 'shadow' timeslots
+ * l1sap: fix TDMA frame number wrap in l1sap_info_time_ind()
+ * conf_lchans_as_pchan(): fix GSM_LCHAN_{CCCH->CBCH} regression
+ * conf_lchans_as_pchan(): initialize all lchans with GSM_LCHAN_NONE
+ * measurement: remove over-defensive checks in is_meas_complete()
+ * [VAMOS] trx_sched_init_ts(): assign names to per-timeslot counters
+ * common/vty: facilitate finding duplicate PHY/TRX associations
+ * vty: ensure all warning messages are prefixed with '%%'
+ * osmo-bts-octphy: drop talloc_replace(), use osmo_talloc_replace_string()
+ * l1sap: fix TDMA frame number arithmetic in fn_ms_adj()
+ * osmo-bts-trx: fix typo: s/bisc/bsic/ in 'show transceiver'
+ * osmo-bts-trx: fix copy-pasted comment: s/sysmoBTS/osmo-bts-trx/
+ * oml: fix handling of NM_ATT_INTERF_BOUND attribute
+ * Report interference levels in RSL RF RESource INDication
+ * scheduler: reorder enum trx_chan_type, add TRX_CHAN_IS_DEDIC()
+ * osmo-bts-trx: report interference levels to the upper layers
+ * osmo-bts-{trx,virtual}: get rid of dummy tx_idle_fn()
+ * scheduler: unset TRX_CHAN_FLAG_AUTO_ACTIVE for TRXC_IDLE
+ * osmo-bts-trx: print timeslot brief info in 'show transceiver'
+ * osmo-bts-trx: measure interference levels on TRXC_IDLE
+ * osmo-bts-trx: report PDCH interference levels to the PCU
+ * scheduler: fix wrong union field in trx_sched_tch_req()
+ * scheduler: fix: use ts_pchan() in trx_sched_set_cipher()
+ * Revert "power_control: BS power shall not be reduced on C0"
+ * osmo-bts-omldummy: indicate BTS_FEAT_BCCH_POWER_RED as supported
+ * osmo-bts-trx: implement BCCH carrier power reduction mode
+ * power_control: constrain BS power reduction on BCCH carrier
+ * manuals/abis/rsl.adoc: clarify RF Resource Indication conformance
+ * rsl: use tlvp_val16be() in rsl_rx_ipac_XXcx()
+ * gsm_lchan_interf_meas_calc_band(): also print number of AVG samples
+ * osmo-bts-trx: send dummy FACCH in the absense of RTP frames
+ * osmo-bts-trx: return -ENODEV if 'bursts_p' is NULL
+ * l1sap: unify channel (de)activation/modification messages
+ * gsm_lchan2chan_nr(): separate RSL specific variant of this API
+ * osmo-bts-trx: bts_model_l1sap_down(): remove chan_nr patching
+ * trx_sched_set_lchan(): use LOGL_INFO for logging messages
+ * osmo-bts-trx: remove an 'else' branch in _sched_dl_burst()
+ * osmo-bts-trx: implement Temporary Overpower for SACCH/FACCH
+ * scheduler: fix comments explaining the interleaving of TCH/H
+ * fix handle_ms_meas_report(): properly count measurement reports
+ * abis: fix memory leak in abis_oml_sendmsg()
+ * rsl: remove redundant logging in rsl_rx_chan_activ()
+ * .gitignore: add tests/amr/amr_test
+ * rsl: prevent race condition during timeslot re-configuration
+ * rsl_tx_rf_res(): separate interference AVG / band calculation
+ * rsl_tx_rf_res(): also report noise levels for PDTCH
+ * osmo-bts-trx: report PDCH interference levels to L1SAP
+ * l1sap: check if BTS model supports interference reporting
+ * vty: show interference level / band in 'show lchan'
+ * trx_sched_clean_ts(): also free() the associated 'struct l1sched_ts'
+ * trx_sched_clean(): also free() the shadow timeslot
+ * osmo-bts-trx: refactor 'maxdly' / 'maxdlynb' commands
+ * rsl: rsl_tx_meas_res() does not change l3, make it const
+ * rsl: send NACK if BTS_FEAT_ACCH_REP is not supported
+ * measurement: handle_ms_meas_report() accepts const gh
+ * measurement: move repeated_dl_facch_active_decision() here
+ * measurement: make sure that DL measurements are valid
+ * cosmetic: s/repeated_acch_capability/rep_acch_cap/g
+ * struct gsm_lchan: group ACCH repetition state fields
+ * struct gsm_lchan: move tch.rep_facch to rep_acch.dl_facch
+ * measurement: fix wrong operator used in handle_ms_meas_report()
+ * osmo-bts-trx: fix potential NULL pointer dereference
+ * lchan_set_state(): also free pending messages if any
+ * lchan: introduce and use lchan_is_tch() helper
+ * [overpower] rsl: store full content of RSL_IE_OSMO_TEMP_OVP_ACCH_CAP
+ * [overpower] lchan_dump_full_vty(): print overpower state
+ * [overpower] scheduler: handle {sacch,facch}_enabled flags
+ * l1sap: fix handling of lchan->pending_rel_ind_msg
+ * l1sap: move false PTCCH/U detection into PDCH branch
+ * l1sap: use designated initializers in process_l1sap_meas_data()
+ * l1sap: process_l1sap_meas_data() accepts pointer to lchan
+ * l1sap: make 'l1sap' argument of process_l1sap_meas_data() const
+ * rsl: fix a memory leak in handle_gprs_susp_req()
+ * l1sap: rework handling of DATA.ind on SACCH
+ * lchan_meas_handle_sacch(): check if Measurement Result is valid
+ * measurement: get rid of *le in lchan_meas_handle_sacch()
+ * measurement: pass *mr to repeated_dl_facch_active_decision()
+ * measurement: pass *mr to lchan_bs_pwr_ctrl()
+ * [overpower] Turn it on and off depending on DL RxQual
+ * measurement: make use of gsm48_meas_res_is_valid()
+ * common/Makefile.am: reformat {AM_CPPFLAGS,AM_CFLAGS,LDADD}
+ * rsl: exclude disabled timeslots from interference reports
+ * oml: use ARRAY_SIZE() in oml_rx_set_bts_attr()
+ * gsm_lchan_interf_meas_calc_avg(): fix band calculation
+
+ [ Pau Espin Pedrol ]
+ * l1sap: Transmit pdtch invalid MAC blocks to PCU
+ * bts-trx: Always submit rx PDTCH DATA.ind to l1sap
+ * bts-trx: Avoid submitting first data_ind with FN=0 to upper layers
+ * bts-trx: Drop duplicate set of last_clk_ind
+ * bts-trx: reorder first timerfd schedule to decrease first timeout skew
+ * sysmo,oc2g,lc15: Make RadioChannel MO depend on RadioCarrier MO
+ * bts: Clean up TS selection in sign_link_up
+ * Fix regression in 'bts: Clean up TS selection in sign_link_up'
+ * Add missing value_string for NM_EV_* introduced recently
+ * pcuif: Set missing bsic field during Tx of info_ind
+ * Use new stat item/ctr getter APIs
+ * rsl: Use switch statement in rsl_rx_bcch_info()
+ * pcu_sock: Transmit SI2
+ * doc: rsl.adoc: Fix trailing whitespace
+ * gsm_data: Drop unused function gsm_pchan_parse()
+ * pcuif_proto.h: Add new container messages
+ * Support forwarding proto IPAC_PROTO_EXT_PCU BSC<->PCU
+ * Rename osmo dyn ts enums to contain SDCCH8
+ * Support SDCCH8 in osmo dyn ts
+ * Make gcc 11.1.0 false positivies happy
+ * rsl: Fix rx of multiple RSL_IPAC_EIE_MEAS_AVG_CFG IEs
+ * rsl: Support parsing up to 3 RSL_IPAC_EIE_MEAS_AVG_CFG IEs
+ * MS Power Control Loop: Take C/I into account
+ * MS Power Control Loop: Support EWMA algorithm for C/I measurements
+ * MS Power Control Loop: Improve logging
+ * BS Power Control Loop: refactor lchan_bs_pwr_ctrl() to look similar to lchan_ms_pwr_ctrl()
+ * BS Power Control Loop: Support EWMA average algo for RxQual meas
+ * BS Power Control Loop: Increase attenuation if RxQual is better than upper threshold
+ * MS/BS Power Control Loop: Do RxLEV meas avg & delta calculations directly on RxLevels
+ * MS/BS Power Control Loop: Fix downscaling averaging bug
+ * Power Control Loop: Move skip loop logic to function helper
+ * comsetic: measurement.c: fix typo in comment
+ * l1sap: Take L1SACCH MS_PWR from bitfield instead of manual parsing
+ * TA loop: Take into account UL SACCH 'Actual Timing advance' field
+ * ta_control: Allow switching TA quicker
+ * lchan: Move TA CTRL param to its own substruct
+ * MS Power Control Loop: Feed UL RSSI from correct measurement period
+ * MS Power Control Loop: Feed UL C/I from correct measurement period
+ * TA Control Loop: Change toa256 switch threshold to 75% of a symbol
+ * Power Control Loop: Set P_CON_INTERVAL to 1 by default
+ * Support configuring TA loop SACCH block rate
+ * MS Power Control Loop: Fix sub vs full being passed to algo
+ * abis: Clear code and drop code not executed
+ * abis.h: Drop unused state
+ * cosmetic: fix typo in comment
+ * abis.c: Rearrange code to follow logic state order
+ * abis.c: Convert early return to assert()
+ * power_control: Drop unused param in function
+ * tests: MS Power Control Loop: Show oscillation among good power levels
+ * cosmetic: Fix formatting of conditional operator
+ * abis: Move FSM registration to constructor function
+ * abis: Shorten string names of events
+ * abis.c: Transition to CONNECTED state only when OML link is up
+ * abis.c: Fix mess with priv->bsc_oml_host
+ * abis.c: Loop over list of BSCs until connection succeeds
+ * trx_provision_fsm: Add missing state transition OPEN_WAIT_POWEROFF_CNF => OPEN_POWEROFF
+ * nm_*_fsm: Add missing item in event mask list for state ENABLED
+ * Allow setting administrative state through oml_mo_state_chg()
+ * nm_*_fsm: Set adminsitrative state 'shutting down' when shutdown procedure starts
+ * MS Power Control Loop: Fix oscillations within good MS Power Levels
+ * nm_*_fsm: Move to state Disabled NotInstalled Locked when shtudown proc ends
+ * abis: Drop internal OML msg queue
+ * nm_*fsm: Make FSMs aware of object being properly configured or not
+ * bts_shutdown_fsm: Fix event name
+ * trx_if: Set pointer to null after freeing it
+ * trx_if: Allow calling trx_if_flush/close from within TRXC callback
+ * trx_if: delete retrans timer when flushing the Tx queue
+ * trx_provision_fsm: Properly reset FSM state upon starting listening for events
+ * bts-trx: Submit TRX_PROV_EV_CFG_ARFCN for C0 during SetBtsAttr
+ * bts-trx: Get rid of check_transceiver_availability_trx()
+ * MS Power Control Loop: Disable threshold comparison on {LOWER,UPPER}_CMP_N=0
+ * l1sap: Support rx of empty rlcmac blocks from PCU
+ * bts-trx: Avoid race condition configuring TS-specific TSC values
+ * bts-trx: Submit TRX SW_ACT when PHY becomes connected
+ * trx_sched_clean_ts: Clean VAMOS shadow TS too
+ * phy_link: Introduce bts_model_phy_link_close() and use it in bts-trx
+ * nm_bts_fsm: Make sure PHYs are opened when SW_ACTivating it
+ * bts_shutdown_fsm: Allow configuring FSM to shutdown without exiting process
+ * abis: Call bts_model_abis_close() when Abis link goes down
+ * bts_trx: Drop non-executed path in trx_link_estab()
+ * Avoid sending Load Indications when BTS is not RSL-connected
+ * abis: Fix memory leak of bts->osmo_link upon link going down
+ * abis: Fix line leaked & recreated upon every reconnect
+ * bts-trx: Keep the process ongoing trying to reconnect on Abis link down
+ * Revert "bts-trx: Keep the process ongoing trying to reconnect on Abis link down"
+ * Revert "abis: Fix line leaked & recreated upon every reconnect"
+ * osmo-bts-omldummy: Fix crash accessing null phy
+ * bts-trx: Fix rxgain & maxdly VTY values being reset
+ * Decouple handling of Measurement Report from lapdm
+ * Move TA & Power Loops further up the stack, take DTXu flag into account
+ * scheduler: Fix lqual_cb not populated for TCH.ind
+ * abis: Fix line leaked & recreated upon every reconnect
+ * trx_provision_fsm: Fix TRX!=0 never going back to CLOSED state
+ * trx_provision_fsm: Support OPEN_POWEROFF->CLOSED transition
+ * bts-trx: Delay power ramp up until RCARRIER is ENABLED
+ * Delay abis reconnect while bts is shutting down
+ * bts-trx: Keep the process ongoing trying to reconnect on Abis link down
+ * trx_provision_fsm: Drop unneeded reset of fields
+ * trx_provision_fsm: Drop impossible paths
+ * trx_provision_fsm: poweronoff_sent flag: track POWERON and POWEROFF separately
+ * trx_provision_fsm: Fix shutdown while POWERON in transit
+ * rsl: NACK Chan Activation for lchans on disabled TS
+ * Introduce gsm_lchan_init() function helper
+ * MS Power Control Loop: Use P_CON_INTERVAL=2 by default
+ * load_indication.c: Avoid sending if CCCH is still not operational
+ * Move lchan,power_ctrl specific code from gsm_data.h to their own files
+ * Move lchan,power_control related code from gsm_data.c to their own files
+ * lchan.h: Add related ticket info to FIXME comment
+ * Introduce gsm_lchan_release function helper
+ * nm_channel_fsm: Release lchans after BTS shutdown
+ * nm_bts_fsm: Reset si_valid bitmask when BTS is shut down
+ * nm_*_fsm: Move reset state code to st_op_disabled_notinstalled_on_enter
+ * nm_*_fsm: reset mo.nm_attr from previous runs when entering state NOT_INSTALLED
+ * Add new gsm_bts_trx_free_shadow_ts() function
+ * Make sure lchan allocated memory from shadow_ts is properly freed
+ * rsl: Fix all shadow TS being Chan Act NACKed
+ * bts-trx: Guard call to trx_sched_clean with NULL trx ptr
+ * lchan: Setup early_rr_ia timer only once during init
+ * Move lchan related code to lchan.{c,h}
+ * lchan: Update log line level to use macro and level INFO
+ * lchan: Avoid applying transition changes if state new==old
+ * Move lchan_deactivate() to lchan.c
+ * Move lchan_init_lapdm inside lchan_set_state(LCHAN_S_ACTIVE)
+ * lchan: Call lapdm_channel_exit() when state changes to NONE
+ * bts_shutdown_fsm: Make sure pending power ramping are aborted before closing TRX
+ * gsm_pchan2chan_nr(): Properly assert if unexpected pchan is passed
+ * Reset CBCH state after BTS shutdown
+ * bts-trx: sched_lchan_pdtch: Refactor tx_pdtch_fn to get rid of goto tag
+ * bts-trx: sched: tx_pdtch_fn: Handle PCU idle blocks properly
+ * Revert "bts-trx: sched: tx_pdtch_fn: Handle PCU idle blocks properly"
+ * scheduler: Fix check against empty PDCH blocks
+ * bts-trx: sched: tx_pdtch_fn: Drop log line clogging logs
+ * l1sap: Avoid re-(de)activating already (de)active lchans
+ * scheduler: Avoid crash upon call to trx_sched_set_lchan if l1ts is uninitialized
+ * bts-trx: sched_lchan_tchf: Drop impossible code path
+ * scheduler: Fix FACCH msg with l2len==0 going to lower layers and logging errors
+ * bts-trx: sched_lchan_tchf: Change log level to debug for line informing about missing dl prim
+ * abis: Drop unneded if condition in else clause
+ * abis: Try one reconnect to previously connected BSC before trying next one
+ * gsm_ts_release(): Make sure pchan{,is_want} is reset to NONE
+
+ [ Neels Hofmeyr ]
+ * osmobts-abis.adoc: add missing bibliography
+ * Abis manual: s/TS 12.21/TS 52.021
+ * Abis manual: add Get Attributes, add BTS features
+ * Abis manual: add VAMOS to BTS features
+ * Abis manual: add RSL_IE_OSMO_TRAINING_SEQUENCE
+ * omldummy: introduce using getopt_long
+ * omldummy: add cmdline arg --features
+ * [VAMOS] osmo-bts-omldummy: allocate shadow timeslots
+ * remove unused LCHAN_S_INACTIVE
+ * enable Early Immediate Assignment
+ * add VTY transcript testing
+ * jenkins: enable new flag --enable-external-tests
+ * add osmo_tdef groups, exposing T timers on VTY config
+ * early IMM ASS: add configurable delay for RR IMM ASS
+ * early IA: change default X15 timer to 0 ms
+ * gsm_lchan_interf_meas_calc_avg(): adapt to the order of boundaries
+
+ [ Harald Welte ]
+ * Introduce ability to set socket priority of RTP sockets
+ * manual: Include QoS chapter and add osmo-bts specific example
+ * manual: Remove manual revision history; we don't use it anywawy
+ * manuals: Update copyright years
+ * l1sap/gsmtap: Don't log UI fill frames [zero information field]
+ * rsl: fix handling of REL IND in lapdm_rll_tx_cb()
+ * initial support for static userspace probes via systemtap
+
+ [ Keith ]
+ * sysmobts-mgr: Fix path to hwmon in /sys
+
+ [ Eric Wild ]
+ * osmo-bts-trx: indicate A5/4 support, handle Kc128
+
+ [ Oliver Smith ]
+ * debian/control: remove dh-systemd build-depend
+
+ [ Eric ]
+ * lc15, oc2g, sysmo: fix show dsp-trace-flags
+ * osmo-trx: fix maxdly
+
+ [ Martin Hauke ]
+ * osmo-bts-trx-calypso.cfg: Adjust settings to work with current osmo-bts versions
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 16:40:05 +0100
+
+osmo-bts (1.3.0) unstable; urgency=medium
+
+ [ Michael McTernan ]
+ * measurement: use signed integer for division of ta256b_sum
+
+ [ Vadim Yanitskiy ]
+ * common/vty.c: get rid of generic exit / end commands
+ * common/abis.c: make use of RSL TEI from OML IPA RSL Connect
+ * L1SAP: use LOGL_DEBUG for logging from rach_pass_filter()
+ * osmo-bts-sysmo/Makefile.am: fix: do not overwrite bin_PROGRAMS
+ * vty: fix left shift by 31 cannot be represented in type 'int'
+ * common/sysinfo: reduce criticality of a logging message
+ * osmo-bts-virtual: fix wrong endianness in gsmtap_hdr_stringify()
+ * osmo-bts-virtual: do not print redundant info in tx_to_virt_um()
+ * osmo-bts-virtual: do not log GSMTAP message sending failure twice
+ * l1sap: fix gsmtap_ph_rach(): properly pack 8-bit and 11-bit RA
+ * osmo-bts-{sysmo,oc2g,lc15}: fix segfault on 'dsp-trace-flag'
+ * osmo-bts-trx/scheduler: remove a left-over from UL TCH handlers
+ * oml: fix oml_mo_tx_sw_act_rep(): do not allocate FOM header twice
+ * fix typo in osmo_bts_variant_names: s/omso/osmo/g
+ * doc/manuals: fix typo in interfaces.adoc: s/Omsocom/Osmocom/g
+ * osmo-bts-omldummy: print a brief usage statement if argc < 3
+ * osmo-bts-omldummy: make number of transceivers configurable
+ * vty: get rid of unused ournode_{exit,end}_cmd declarations
+ * vty: cosmetic: make an error message more informative
+ * vty: use gsm48_chan_mode_name() from libosmocore
+ * gsm_data_shared: drop unused supports_egprs_11bit_rach
+ * gsm_data_shared: drop unused enum bts_gprs_mode
+ * gsm_data_shared: drop unused channel request reason definitions
+ * gsm_data_shared: get rid of unused HARDCODED_{ARFCN,BSIC}
+ * gsm_data_shared: get rid of unused HARDCODED_BTS{0,1,2}_TS
+ * gsm_data_shared: get rid of unused enum gsm_hooks
+ * gsm_data_shared: drop declaration of non-existing gsm_parse_reg()
+ * gsm_data_shared: drop unused A38_XOR_{MIN,MAX,COMP128}_KEY_LEN
+ * gsm_data_shared: drop unused MAX_EARFCN_LIST
+ * gsm_data_shared: drop unused LCHAN_SAPI_{UNUSED,MS,NET,REL}
+ * gsm_data_shared: drop unused struct bts_codec_conf
+ * gsm_data_shared: drop meaningless comments
+ * gsm_data_shared: drop unused sacch_deact from struct gsm_lchan
+ * gsm_data_shared: drop forward declaration of struct vty
+ * gsm_data_shared: drop unused *nmh from struct gsm_bts
+ * gsm_data_shared: drop unused dtxu from struct gsm_bts
+ * gsm_data_shared: drop unused ctrl_ack_type_use_block & net_ctrl_ord
+ * gsm_data_shared: drop unused rach_b_thresh & rach_ldavg_slots
+ * gsm_data_shared: drop force_combined_si & bcch_change_mark
+ * scheduler: drop non-existing extern declarations
+ * vty: fix bts_dump_vty(): properly print OML stream ID (TEI)
+ * rsl: refactor handling of RSL_IE_MR_CONFIG
+ * osmo-bts-trx: prettify Makefile.am: make it git friendly
+ * osmo-bts-trx: fix: use noinst_HEADERS instead of EXTRA_DIST
+ * osmo-bts-virtual: cosmetic: use LID_{SACCH,DEDIC} macros
+ * doc/examples: remove virtual/openbsc-virtual.cfg
+ * common/scheduler: fix unreachable code in trx_sched_set_lchan()
+ * common/scheduler: use boolean for channel activation state
+ * osmo-bts-trx/trx_if: fix memleak in trx_ctrl_cmd_cb()
+ * osmo-bts-trx/trx_if: cosmetic: s/ocommand/command/
+ * oml: fix TL16V length calculation in add_bts_feat()
+ * osmo-bts-trx: indicate BTS_FEAT_EGPRS support to BSC
+ * gsm_data_shared: use bitvec API to allocate the feature vector
+ * Do not mix public and private BTS features, use libosmocore's API
+ * osmo-bts-trx/scheduler: properly handle NOPE.ind during handover
+ * osmo-bts-trx: use osmo_store32be() in trx_if_send_burst()
+ * osmo-bts-trx: move logical channel handlers to separate files
+ * osmo-bts-trx: introduce and use struct trx_dl_burst_req
+ * osmo-bts-trx: store pointer to gsm_lchan in l1sched_chan_state
+ * osmo-bts-trx: include BS Power reduction in Downlink bursts
+ * A-bis/RSL: refactor handling of BS Power IE (power reduction)
+ * A-bis/OML: fix logging: do not print A-bis MO name twice
+ * Use libosmocore's TDMA frame number API (constatns & arithmetic)
+ * osmo-bts-trx: fix trx_sched_fn(): properly advance frame number
+ * osmo-bts-trx/scheduler: make mark trx_sched_fn() return void
+ * vty: fix missing separator in help for power ramp commands
+ * osmo-bts-trx/scheduler: get rid of _sched_fcch_burst
+ * A-bis/OML: handle hopping params in Set Channel Attributes
+ * osmo-bts-trx/scheduler: cosmetic: move trx_if_powered() check
+ * osmo-bts-trx/scheduler: get rid of unused 'meas' in l1sched_chan_state
+ * l1sap: do not print redundant info in l1sap_chan_act()
+ * Constify the 'trx' argument of trx_get_hlayer1() everywhere
+ * common: constify the argument of trx_ms_pwr_ctrl_is_osmo()
+ * pcu_sock: constify the argument of ts_should_be_pdch()
+ * osmo-bts-trx/scheduler: fix CLCK.ind handling during ramping down
+ * osmo-bts-trx/scheduler: refactor dummy burst scheduling
+ * oml: fix ARFCN range check in oml_rx_set_radio_attr()
+ * oml: fix ARFCN range check in oml_rx_set_bts_attr()
+ * pcu_sock: use a 'switch' statement in ts_should_be_pdch()
+ * pcu_sock: warn about maximum transceiver number constraints
+ * pcu_sock: separate trx / ts filling from pcu_tx_info_ind()
+ * pcu_sock: use LOGPTRX() in info_ind_fill_trx()
+ * osmo-bts-trx/scheduler: implement baseband frequency hopping
+ * osmo-bts-trx: indicate support of BTS_FEAT_HOPPING
+ * l1sap: radio_link_timeout(): clarify logging messages
+ * l1sap: radio_link_timeout(): use LOGPLCHAN() macro
+ * l1sap: radio_link_timeout(): bad_frame is a boolean
+ * rsl: constify the 'lchan' argument of rsl_tx_conn_fail()
+ * debian/control: change maintainer to the Osmocom team / mailing list
+ * osmo-bts-omldummy: enable BTS_FEAT_{CBCH,HOPPING} support
+ * vty: clarify documentation of '[no] gsmtap-sapi' command
+ * vty: add 'gsmtap-sapi (enable-all|disable-all)' command
+ * osmo-bts-trx/trx_provision_fsm: fix misleading comment in header
+ * osmo-bts-trx/trx_provision_fsm: cosmetic: switch is not a function
+ * osmo-bts-trx/l1_if: drop redundant logging message
+ * osmo-bts-trx: fix trx_init(): do not send OPSTART ACK blindly
+ * osmo-bts-trx/trx_provision_fsm: add missing default labels
+ * osmo-bts-trx: also print 'txtune-ack' in st_open_poweroff()
+ * struct gsm_bts_trx: remove unused per-TRX OML Link pointer
+ * struct gsm_bts_trx[_ts]: remove unused parsed NM attribute list
+ * gsm_data: rename hopping.{ma,ma_len} to hopping.arfcn_{list,num}
+ * pcuif_proto: version 10: add frequency hopping parameters
+ * osmo-bts-trx/scheduler: refactor UL burst measurement processing
+ * vty: fix bts_dump_vty_features(): properly check BTS model flags
+ * bts: cosmetic: make param 'net' of gsm_bts_num() const
+ * vty: cosmetic: use osmo_talloc_replace_string()
+ * tx_power: make trx/lchan struct pointers const where possible
+ * vty: make most struct pointers const in show/write commands
+ * osmo-bts-omldummy: fix: do not crash on OML connection drop/failure
+ * osmo-bts-omldummy: suppress 'Unimplemented bts_model_trx_deact_rf'
+ * vty: fix 'show bts' command: print proper BTS variant
+ * vty: fix 'show bts' command: BTS number is optional
+ * pcu_sock: cosmetic: use ARRAY_SIZE() in pcu_tx_info_ind()
+ * pcu_sock: cosmetic: make *nsvc a scoped and const variable
+ * pcu_sock: use llist_for_each_entry() in pcu_sock_close()
+ * pcu_sock: fix pcu_sock_close(): deactivate dynamic timeslots too
+ * oml: fix handling of NSVC local port in oml_ipa_mo_set_attr_nsvc()
+ * pcu_sock: fix {local,remote}_port byte ordering in pcu_tx_info_ind()
+ * pcu_sock: support handling multiple BTS instances in pcu_rx()
+ * gsm_data: check in and use enum lchan_rel_act_kind
+ * tests/power_test: also match stderr, not only stdout
+ * tests/power_test: move bts/trx/ts/lchan init to init_test()
+ * tests/power_test: do not assert in apply_power_test()
+ * power_control: clarify argument names of lchan_ms_pwr_ctrl()
+ * power_control: implement EWMA based Uplink power filtering
+ * fix pcu_if_signal_cb(): do not send INFO.ind if PCU is not connected
+ * scheduler: ensure PRIM_OP_REQUEST when adding to the queue
+ * scheduler: _sched_dequeue_prim(): make 'l1sap' a scoped pointer
+ * scheduler: use RSL_CHAN_NR_MASK in trx_sched_set_lchan()
+ * measurement: remove redundant 'break' statements in modulus_by_lchan()
+ * measurement: use LOGPLCHAN() macro in lchan_meas_check_compute()
+ * power_test: fix incorrect line termination in init_test()
+ * power_control: do nothing if 'rx-current' equals 'rx-target'
+ * power_control: tolerate small deviations from 'rx-target'
+ * scheduler: use RSL_CHAN_NR_MASK in trx_sched_set_cipher()
+ * scheduler: drop meaningless check in trx_sched_set_lchan()
+ * scheduler: drop redundant check in trx_sched_set_cipher()
+ * scheduler: get rid of useless TRX_CHAN_FLAG_PDCH
+ * scheduler: reduce nesting in trx_sched_set_lchan()
+ * scheduler: treat subsequent lchan (de)activation as error
+ * scheduler: join conditions in trx_sched_set_lchan()
+ * scheduler: remove pending Tx prims on lchan deactivation
+ * power_control: fix default EWMA smoothing coefficient (80% -> 50%)
+ * main: do not print deprecated '-r' / '--realtime' in help
+ * main: increase spacing between commands and description
+ * main: separate model-specific arguments in help
+ * main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
+ * osmo-bts-trx/scheduler: fix comments related to FACCH/H and BFI
+ * main: register VTY commands before handle_options()
+ * main: move general options from bts_vty_init()
+ * vty: fix double '%' in description of some commands
+ * vty: fix missing / wrong documentation for some commands
+ * vty: call bts_model_vty_init() from bts_vty_init()
+ * fixup: vty: call bts_model_vty_init() from bts_vty_init()
+ * main: do not print asciiart to stdout, use stderr instead
+ * osmo-bts-lc15: use consistent name for containing directory
+ * doc/manuals: generate XML VTY reference at build-time
+ * doc/manuals: also generate VTY reference for osmo-bts-virtual
+ * doc/manuals: move osmobts-vty-reference.xml to vty/
+ * osmo-bts-trx/scheduler: ensure no DL power attenuation on C0
+ * struct gsm_bts: move ul_power_{target,hysteresis} to ul_power_ctrl
+ * bts: rename MS_UL_PF_ALGO_{NONE,EWMA} to BTS_PF_ALGO_{NONE,EWMA}
+ * bts: generalize a struct for UL/DL power control parameters
+ * bts: add Downlink power control parameters
+ * l1sap: make sure that UL SACCH is always 23 octets long
+ * tests/power: rename s/power_test/ms_power_loop_test/
+ * power_control: generalize power control state structure
+ * power_control: lchan_ul_pf_ewma(): do not use lchan->meas.res_nr
+ * power_control: lchan_ms_pwr_ctrl(): use existing 'trx' pointer
+ * power_control: generalize and rename lchan_ul_pf_ewma()
+ * power_control: lchan_ms_pwr_ctrl(): make use of params/state pointers
+ * power_control: remove a logging statement and early return
+ * power_control: do not log averaged RSSI values as 'rx-current'
+ * power_control: derive calc_delta() from lchan_ms_pwr_ctrl()
+ * power_control: implement BS (Downlink) Power Control
+ * power_control: cosmetic: fix weird spacing
+ * power_control: clarify units in 'struct bts_power_ctrl_params'
+ * power_control: clarify units in 'struct lchan_power_ctrl_state'
+ * rsl: properly initialize MS/BS Power Control state
+ * power_control: make raise/lower step limitation configurable
+ * vty: resurrect per-lchan BS/MS Power Control information
+ * vty: fix dump_lchan_trx_ts(): dump dedicated channels only
+ * rsl: remove redundant boolean flag in rsl_rx_chan_activ()
+ * power_control: check-in new parameters and default values
+ * power_control: add VTY introspection commands for MS/BS params
+ * l1sap: fix: enable UL SACCH repetition if RxQual threshold is 0
+ * sysinfo: fix less-than-zero comparison of an unsigned value
+ * osmo-bts-trx: vty: clarify and improve some deprecation messages
+ * power_control: vty: re-use cfg_bts_ul_power_target()
+ * power_control: vty: deprecate 'uplink-power-control' commands
+ * power_control: handle MS/BS Power control params on A-bis/RSL
+ * vty: add a command to show GPRS related info
+ * power_control: migrate MS/BS control loops to the new params
+ * power_control: generalize measurement pre-processing state
+ * power_control: properly track the first initial state
+ * power_control: use more reasonable reduce step size
+ * power_control: rework handling of DL RxQual measurements
+ * power_control: BS power shall not be reduced on C0
+ * paging: refactor and optimize fill_paging_type_1()
+ * power_control: print current RxLev and lower/upper thresholds
+ * power_control: fix: properly print 'delta' applied to attenuation
+ * vty: fix error messages in lchan specific commands
+ * vty: add macro for 'bts <0-0> trx <0-0> ts <0-7> lchan <0-1>'
+ * vty: extend trx / lchan number range in BTS_T_T_L_CMD
+ * vty: make commands related to the loopback mode hidden
+ * vty: add expert commands for MS/BS power control
+ * power_control: add test for inc / red step size limitations
+ * l1sap: fix gsmtap_ph_{data,pdch,rach}(): use 'const'
+ * l1sap: include Uplink RSSI in GSMTAP packets
+ * power_control: clarify the meaning of 'delta' in logging messages
+ * pcu_sock: pcu_tx_si_all(): make 'si_types' const
+ * pcu_sock: pcu_tx_si_all(): cosmetic coding style change
+ * pcu_sock: pcu_tx_si_all(): fix returning ununitialized rc
+ * osmo-bts-trx/scheduler: use DMEAS in trx_sched_meas_avg()
+ * oml: cosmetic code style changes in rx_oml_ipa_rsl_connect()
+ * vty: register libosmocore's FSM introspection commands
+ * oml: avoid redundant ntohl() / htonl() conversion
+ * oml: make 'struct tlv_parsed' pointer const where possible
+ * oml: use regular TLVP_PRES() in rx_oml_ipa_rsl_connect()
+ * power_control: cosmetic: fix swapped {L,U}_RXQUAL_XX_P comments
+ * power_control: implement handling of P_Con_INTERVAL parameter
+ * oml: reuse the given msgb in oml_fom_ack_nack()
+ * oml: ensure that IPA RSL Connect ACK/NACK contains all IEs
+ * main: cosmetic: tweak deprecation warning messages
+ * GSMTAP: move 'gsmtap_sapi_names' from l1sap.c to vty.c
+ * GSMTAP: fix wrong naming of per-BTS SAPI commands
+ * GSMTAP: move 'struct gsmtap_inst' and masks to 'struct gsm_bts'
+ * ta_control: cosmetic: use correct naming for MIN/MAX constraints
+ * ta_control: make 'struct bts_ul_meas' parameters const
+ * ta_control: fix Timing Advance control for SDCCH channels
+
+ [ Harald Welte ]
+ * rsl.c: Fix compiler error on gcc-9.2.1
+ * virtual: Fix VTY commands to specify GSMTAP multicast groups
+ * l1sap: Use msgb_pull_l2() and unify l1sap_tch_ind + l1sap_ph_data_ind
+ * osmo-bts-virtual: implement GSMTAP_CHANNEL_VOICE
+ * osmo-bts-virtual: Add "virtual-um ttl <0-255>" VTY option
+ * osmo-bts-virtual: Fix "virtual-um net-device NETDEV"
+ * cosmetic: remove dead code from logging.c
+ * fix compilation with gcc-10
+ * osmo-bts-virtual: Avoid rejecting AMR in uplink
+ * virtual/scheduler: log unknown GSMTAP chan
+ * Ensure we include lchan name in all LAPDm log lines
+ * osmo-bts.spec.in: Use %config(noreplace) to retain current config file
+ * bts: Add VTY command to manually override Radio Link Timeout
+ * sysinfo: Only send SI13 if PCU is connected
+ * sysinfo: Don't broadcast SI4 GPRS INDICATOR if PCU is disconnected
+ * use osmo_fd_setup() everywhere
+ * remove dead oml_router code
+ * sysinfo.c: Fix SI4 GPRS patching which overwrote CBCH IE
+ * fix-up missed review comment in CBCH SI4 patching fix
+ * major README uppdate
+ * Use osmo_fd_*_{disable,enable}
+ * add support for sysmoBTS 1003 aka "1002 with GPS and PoE"
+
+ [ Philipp Maier ]
+ * ta_control: move timing advance code from osmo-bts-trx to common
+ * measurment: write irssi_full_sum variable correctly
+ * l1sap: merge MEAS IND into PRIM PH DATA / PRIM TCH
+ * Do not depend on pcu_direct flag when populating ph_data_ind
+ * osmo-bts-sysmo: merge measurement data and payload
+ * osmo-bts-trx: do not set rx-gain to 1 by default
+ * scheduler: always call Uplink burst handler on NOPE.ind
+ * logging: use only LOGL_NOTICE as defualt loglevel
+ * dtx: add detection of AMR DTX frames for osmo-bts-trx
+ * measurement: remove unecessary is_amr_sid_update parameter
+ * measurement: make measurements more debugable
+ * measurement: expect at least 1 SUB frame for AMR
+ * osmo-bts-trx/scheduler: fix measurement handling for SUB frames
+ * vty: add attributes to VTY commands indicating when they apply
+ * sched_lchan_tchh: initialize meas_avg with zeros
+ * main: add commandline option --vty-ref-xml
+ * cosmetic: add missing semicolon after OSMO_ASSERT()
+ * sched_lchan_tchf: count measurements for FACCH/F only once
+ * measurement: count all blocks as SUB for TCH/F in signalling mode
+ * measurement: fix expected number of measurements
+ * measurement.c: fix integer overflow problem
+ * rsl.adoc: add info about RSL_IE_OSMO_REP_ACCH_CAP
+ * l1sap: pre-initalize pointer with NULL to avoid gcc warning
+ * l1sap: add repeated downlink FACCH
+ * rsl.adoc: update documentation for RSL_IE_OSMO_REP_ACCH_CAP
+ * l1sap: also include SRR bit in RSL l1 info field.
+ * l1sap: add repeated downlink SACCH
+ * l1sap: add repeated uplink SACCH
+ * l1sap: acch_repetition fix hysthereis threshold table
+ * l1sap: use rxlev_full when no DTX was used
+ * pcu_sock: send SI1, SI3 and SI13 via PCUIF
+ * pcu_sock: fix uninitalized returncode value
+ * l1sap: fix repeated_dl_facch_active_decision()
+ * l1sap.c: be sure that FACCH repetition is turned off
+ * l1sap: be sure that UL-SACCH repetition is turned off
+ * l1sap: fix comment: sapi number is missing
+ * vty: dont put a colon after vty_out in cfg_out macro
+ * gsm_data: handle l1_info with structs
+
+ [ Pau Espin Pedrol ]
+ * l1_if: Fix strange formatting of Meas info logging
+ * l1sap: Change loglevel of Rx TCH.ind INFO->DEBUG
+ * bts-trx: trx_if.c: Fix some printf formats
+ * cosmetic: Fix some typos with codespell
+ * lc15: Fix returning values on void function
+ * lc15: Fix mismatching signature in callback provided
+ * oc2g: Fix returning values on void function
+ * oc2g: Fix mismatching signature in callback provided
+ * Use OSMO_FD_* instead of deprecated BSC_FD_*
+ * l1_utils.h: Avoid redefinition of global vars defined in l1_utils.c
+ * vty: Fix misleading define name
+ * tests/tx_power: Speed up test
+ * doc: Update vty reference xml file
+ * bts-trx: vty: Add 'nominal-tx-power' cmd
+ * bts-trx: phy_link: Improve logging fmt in phy_link_state_set()
+ * oml.c: Fix whitespace in log line
+ * oml.c: Log ADM STATE change locked/unlocked
+ * scheduler.c: Fix trailing whitespace
+ * pcu_sock: Change log about tx PCH confirm INFO->DEBUG
+ * bts-trx: Implement power ramping during BTS bring up
+ * bts-trx: Rename setpower TRXC functions to describe they use power attenuation
+ * bts-trx: Introduce helper func l1if_trx_set_nominal_power
+ * bts-trx: Use TRXC cmd NOMTXPOWER to retrieve nominal tx power from osmo-trx
+ * bts-trx: Re-apply tx power if nominal power is received after POWERON
+ * scheduler: Fix reading out of buffer during tx of dummy burst on PDCH TS with EGPRS enabled
+ * abis.c: Grab reference to e1inp_line_get if already created
+ * doc: Fix typos in bts-models.adoc
+ * scheduler: Improve logging about prim being out of range
+ * scheduler: Early return in _sched_dequeue_prim() and clarify FN cases
+ * scheduler: _sched_dequeue_prim(): Refactor goto paths
+ * scheduler: _sched_dequeue_prim(): Refactor found_msg goto path
+ * cosmetic: common/Makefile.am: split each source file in one line
+ * cosmetic: include/osmo-bts/Makefile.am: split each header file in one line
+ * Merge gsm_data_shared.h into gsm_data.h
+ * scheduler: Add rate_ctr informing about too low rts-advance
+ * scheduler: Add rate_ctr informing about Dl block not found
+ * handover_tests: Avoid redefining all bts_model stubs
+ * meas_tests: Avoid redefining all bts_model stubs
+ * tests/stubs.c: Add missing stub for bts_model_change_power
+ * cosmetic: {oc2g,lc15}bts_bty.c: Fix trailing whitespace
+ * Fix missing bts_model implementations in stubs.c and bts_model.c
+ * Introduce LOGPTRX macro and use it in tx_power.c
+ * power_ramp: Add support to get callback when ramping process completes
+ * bts-trx: Instruct user to set manually nominal-tx-power if NOMTXPOWER not supported
+ * tx_power: Log bypass param in power_ramp_start
+ * phy_link.h: Drop unimplemented function definition
+ * bts.c: Fix typo in log line and improve it
+ * abis.c: Use LOGPIL when logging signalling link down
+ * Introduce bts_shutdown FSM
+ * Implement tx power ramp down during BTS shutdown
+ * bts-trx: Split part of bts_model_trx_close() steps into bts_model_deact_rf
+ * bts_shutdown: First deact RF on all TRX, finally close them
+ * bts_model: Convert bts_model_trx_close() to return asynchronously
+ * bts_shutdown: Wait until all TRX are closed
+ * bts-virtual: Implement bts_model_trx_close
+ * bts-trx: Mark 'osmotrx power' VTY cmd as deprecated
+ * Fix shutdown in osmo-bts-{omldummy,virtual}
+ * bts-omldummy: Implement bts_model_trx_close
+ * bts-omldummy: Speed up shutdown (instantaneous ramp)
+ * tx_power: Support controlling BTS with nominal tx pwr < 0dBm
+ * bts-trx: Introduce rate counter for scheduler timerfd missed FNs
+ * bts_shutdown: Speed up shutdown if no TRX is operational
+ * pcu_sock: Avoid presenting TS from disabled TRX as available to PCU
+ * bts-trx: Implement ramp up/down during ADM state change
+ * gsm_data.h: Use enum type for NM state fields
+ * Move nm_state and Mo related code gsm_data.* => oml.*
+ * Move gsm_bts code gsm-data.* => bts.*
+ * bts-virt: Don't rely on gsmtap_makemsg() returning NULL for GSMTAP_CHANNEL_UNKNOWN
+ * Move struct gsm_bts_trx: gsm_data.* & bts.* => bts_trx.*
+ * bts-trx: Don't set OPSTATE enabled during trx_init
+ * common: Avoid changing OPSTATE to Enabled upon RSL up
+ * bts-trx: Remove unused function l1if_provision_transceiver()
+ * bts-trx: introduce TRX provisioning FSM
+ * tx_power_test: Disable using color in log output
+ * bts-trx: Use bool type for on/off state variables
+ * bts-trx: Integrate TRX provisioning logic more tightly into the FSM
+ * bts-trx: Delay TRXC POWERON cmd until all TRXs are provisioned
+ * rsl: Fix wrong param passed to gsm_pchan_name() in log line
+ * bts-trx: Fix osmocom dyn ts assert hit during Adm State Unlock
+ * bts-trx: prov_fsm: Fix mess with 1 event having 2 names
+ * bts_shutdown_fsm: Fix switching too quickly to state WAIT_TRX_CLOSED
+ * common: Avoid call to bts_model_chg_adm_state() if there's no ADM state change
+ * bts-trx: Fix handling ADM state change while previous one WIP
+ * vty: Allow setting power-ramp max-initial to negative values
+ * bts-trx: Fix assert hit when rf_locked in .cfg and TS TCH/F_PDCH
+ * tx_power: Take into account max-initial when ramping up bigger power lvl intervals
+ * doc: configuration.adoc: Document ramping down feature
+ * common: Support setting rt prio through new libosmovty sched VTY cmds
+ * tests: tx_power: Extend and add extra power_ramp buggy case
+ * common: tx_power: Fix bug in power ramp up below max-initial value
+ * Update dependency on libosmocore 1.4.0
+ * configure.ac: Fix trailing whitespace
+ * pcu_sock: Fix typo in log message
+ * bts-trx: Use TRXC RFMUTE instead of resetting the scheduler
+ * bts-trx: Ensure RFMUTE state is set properly at startup
+ * scheduler: Drop unused function trx_sched_reset()
+ * Fix RadioCarrier OML Operative State Change report not sent on some scenarios
+ * Improve logging around failing to (de)activate chan_nr
+ * Improve error handling and logging in gsm_pchan2chan_nr()
+ * Improve logging and error handling receiving act_req for dyn TS not yet configured
+ * pcu_sock: Only announce dyn TS already configured by lower layers
+ * Avoid sending RSL RF REL ACK if PDCH chan is disabled by administrative lock
+ * oml: Set RadioChannel operational state to Enabled only during OPSTART
+ * gsm_data.h: Drop unused struct field
+ * contrib/jenkins: Enable parallel make in make distcheck
+ * Drop unused param in oml_init()
+ * Change NM Channel availability Dependency->Offline when RadioCarrier becomes enabled
+ * Introduce NM BTS Site Manager FSM
+ * Introduce NM BTS FSM
+ * Introduce NM Radio Carrier and Baseband Transceiver FSMs
+ * Introduce NM Channel FSM
+ * bts_trx.c: Dispatch missing NM_EV_RSL_UP/DOWN to the bb_transc object
+ * oml: Set NM_OPSTATE_DISABLED by default
+ * common: Enable SIGABRT signal handler
+ * common: generate coredump and exit upon SIGABRT received
+ * sysmobts-mgr: generate coredump and exit upon SIGABRT received
+ * oc2g-mgr: generate coredump and exit upon SIGABRT received
+ * lc15-mgr: generate coredump and exit upon SIGABRT received
+ * nm_channel_fsm: Fix several FSM internal transitions not being made
+ * cosmetic: sysmobts-mgr: fix whitespace indentation
+ * tests: Explicitly drop category from log
+ * tests: Replace deprecated API log_set_print_filename
+
+ [ Oliver Smith ]
+ * rsl: make IP DSCP configurable
+ * VTY: add "test send-failure-event-report"
+ * contrib: import RPM spec
+ * contrib: integrate RPM spec
+ * Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
+ * contrib/jenkins: don't build osmo-gsm-manuals
+ * configure.ac: set -std=gnu11
+ * common/measurement.c: fix gcc 4 + -std=gnu11 error
+
+ [ Harld Welte ]
+ * trx: Fix reported BER for TCH/H
+ * trx: Use NOPE indications from OsmoTRX for TCH/F and TCH/H
+ * trx: Use NOPE indications on SDCCH
+
+ [ Eric ]
+ * configure.ac: fix libtool issue with clang and sanitizer
+
+ [ Rafael Diniz ]
+ * osmo-bts-litecell15: Implement missing features.
+
+ [ Alexander Couzens ]
+ * measurement: replace u_int64_t with uint64_t
+ * pcuif_proto: version 0xa: add support for IPv6 NSVCs
+ * pcuif_proto: fix typo in comment
+ * Revert "pcuif_proto: version 0xa: add support for IPv6 NSVCs"
+ * pcuif_proto: version 10: add support for IPv6 NSVCs
+ * Introduce the new OML NM_ATT_OSMO_NS_LINK_CFG to configure IPv6 NSVC for PCU
+ * common/bts: set feature IPV6_NSVC
+ * OML: correct parse the NM_ATT_OSMO_NS_LINK_CFG field address_family
+
+ [ Daniel Willmann ]
+ * osmo-bts-trx: Use much lower clock advance values towards PCU and TRX
+
+ [ Neels Hofmeyr ]
+ * rename to release_sapi_ul_rach(), simplify
+ * part 1 of: fix SAPIs for handover to match 48.058 4.1.{3,4}
+ * part 2 of: fix SAPIs for handover, osmo-bts-sysmo
+ * part 3 of: fix SAPIs for handover, osmo-bts-trx
+ * part 4 of: fix SAPIs for handover, osmo-bts-lc15
+ * part 5 of: fix SAPIs for handover, osmo-bts-oc2g
+ * log: rsl_rx_chan_activ: show chan type as human readable string
+ * chan activ: activate DL SACCH only when TA is known
+ * GSMTAP: make remote host for Um logging configurable via VTY
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 16:35:17 +0100
+
+osmo-bts (1.2.0) unstable; urgency=medium
+
+ [ Oliver Smith ]
+ * Cosmetic: virtual: l1sap.c: fix typos
+ * virtual: set link quality for GSMTAP_CHANNEL_RACH
+ * pcu_sock: fix endian-swapped CellID
+ * gitignore: add oc2g generated files
+ * log: set L1 SAPI log context
+ * vty: add "logging filter l1-sapi"
+ * vty.c: don't ignore get_string_value() errors
+ * vty.c: avoid coverity BAD_SHIFT issues
+ * osmo-bts-virtual.cfg: ms-power-control dsp -> osmo
+
+ [ Harald Welte ]
+ * ETWS Primary Notification via P1 Rest Octets
+ * pcu_interface: Forward ETWS Primary Notification to PCU
+ * doc: Update Abis manual RSL section with ETWS related infomration
+ * osmo-bts-trx/scheduler: prevent uninitialized memory access
+ * osmo-bts-trx: migrate to new generic ECU abstraction
+ * rach_pass_filter(): Add information about channel type
+
+ [ Vadim Yanitskiy ]
+ * common/rsl.c: fix possible NULL-pointer dereference
+ * osmo-bts-trx/scheduler: fix tx_tch_common(): do not send AMR BFI twice
+ * osmo-bts-trx/scheduler: add FIXME note about FACCH/H and BFI
+ * osmo-bts-trx/scheduler: fix: check rc of osmo_ecu_frame_out()
+ * scheduler: fix handling of PTCCH/U and PTCCH/D logical channels
+ * osmo-bts-trx/scheduler: also detect TSC for Access Bursts on PDCH
+ * common/l1sap: increase ToA precision for packet Access Bursts
+ * L1SAP: use RSL_CHAN_* definitions from libosmogsm
+ * L1SAP: also consider RSL_CHAN_OSMO_CBCH8 as CBCH
+ * L1SAP: clarify debug messages in rach_pass_filter()
+ * L1SAP: do not pass unused parameter to l1sap_handover_rach()
+ * L1SAP: refactor handling of Access Bursts on PDCH
+ * L1SAP: properly handle 11-bit encoded RACH.ind in gsmtap_ph_rach()
+ * L1SAP: use the actual ARFCN for outgoing PCUIF messages
+ * L1SAP: fix gsmtap_pdch(): there can be no DATA.ind on PTCCH/U
+ * L1SAP: use GSMTAP_CHANNEL_PDTCH for PDTCH blocks by default
+ * L1SAP: there can be no DATA.ind primitives on PTCCH/U, reject them
+ * README.md: update osmo-bts-trx specific limitations
+ * osmo-bts-trx/scheduler: fix: print the last frame number in rx_data_fn()
+ * osmo-bts-trx: general handling of NOPE / IDLE indications
+ * osmo-bts-trx/trx_if.c: fix: always initialize bi->burst_len for NOPE.ind
+ * osmo-bts-trx/trx_if.c: also print both RSSI and ToA256 for NOPE.ind
+ * osmo-bts-trx/trx_if.c: fix: NOPE.ind also contains C/I field
+ * pcuif_proto.h: extend RACH.ind with TRX and timeslot number fields
+ * common/vty.c: fix: properly assert() the result of get_string_value()
+ * common/abis.c: pass gsm_bts_trx to e1inp_sign_link_create()
+ * common/abis.c: use tall_bts_ctx as talloc-context for libosmo_abis_init()
+ * osmo-bts-trx/vty: ensure backwards compatibility with older config files
+
+ [ Pau Espin Pedrol ]
+ * bts-trx: Log case where no SETFORMAT is sent
+ * bts-trx: Change super verbose IDLE ind not-supported line to DEBUG
+ * doc: bts-models.adoc: Fix typos in rts-advance section
+ * bts-trx: vty: Use API to get poweron state
+ * bts.h: Remove non-existent function definitions
+ * scheduler.c: Move some message log level to DEBUG
+ * scheduler: Use OSMO_ASSERT instead of abort
+ * l1sap: Log conn dropped due to radio link counter timeout
+ * struct gsm_bts: Add model_priv pointer handing bts_model specific data
+ * bts-trx: Allocate struct osmo_trx_clock_state as part of bts-trx private data
+ * bts-trx: vty: Print phy link state in cmd 'show transceiver'
+ * bts-trx: trx_set_bts(): Avoid double loop by checking current trx
+ * bts-trx: Rework code handling poweron state
+ * bts-trx: Don't reset transceiver_available in scheduler_trx.c
+ * bts-trx: Get rid of messy transceiver_available state handler
+ * bts-trx: Drop unused func check_transceiver_availability()
+ * bts-trx: Log TRXC and TRXD socket recv()/send() failures
+ * bts-trx: Time out if no clock ind recvd after RSP POWERON
+ * cosmetic: bts-trx: document variable power level
+ * bts-trx: loops.c: Take into account RSL CHAN ACT ms power level limits
+ * loops.h: Fix missing include for struct l1sched_trx
+ * power_control.c: Take into account RSL CHAN ACT ms power level limits
+ * cosmetic: l1sap.c: Fix typo
+ * rsl: Assign recv pwr to lchan's max ms power
+ * bts-trx: Implement MS Power control loop calculations using dBm instead of ctl levels
+ * rsl: Fix logged value in rx MS Power Control
+ * cosmetic: Fix trailing whitespace
+ * Change gsm_bts_trx field to bool and rename it
+ * Change gsm_lchan field fixed to bool
+ * rsl: Remove unneeded duplicate reset on some lchan fields
+ * Move and rename gsm_lchan.ms_power field
+ * bts-trx: loops.c: Avoid always clamping MS power to MS power class 1
+ * power_control.c: Apply latests improvements from loops.c
+ * power_control.c: Log rx current and target signal levels
+ * power_control.c: Fix ms pwr ctrl skipped if MS doesn't support announced MS Power Level
+ * Introduce BTS feature BTS_FEAT_MS_PWR_CTRL_DSP
+ * power_control.c: Don't use announced MS Power level as input for loop calculations
+ * power_control.c: Limit speed of announced MS Power Level value changes
+ * scheduler_trx.c: cast ptrdiff value to fix printf format
+ * bts-trx: Drop low layer MS Power Control Loop algo
+ * rsl_rx_chan_act: Apply bitmask when parsing IE MS_POWER
+ * rsl: Clarify when autnonoums MS Power Ctrl Loop is used
+ * power_control.c: Log maximum allowed MS Power Level
+ * power_control.c: Clarify loop algo vars and use correct ones during log
+ * l1sap: is_fille_frame(): verify len of data compared
+
+ [ Martin Hauke ]
+ * Fix common misspellings and typos
+ * Rename variable: CALIB_SUCESS -> CALIB_SUCCESS
+
+ [ Philipp Maier ]
+ * scheduler_trx: use gsm0502_fn_remap() to calculate frame number
+ * scheduler_trx: initalize n_errors, n_bursts_bits, n_bits_total
+ * scheduler_trx.c: avoid division by zero when calculating BER
+ * rsl: ensure measurement reports are sent
+ * l1sap.c: ensure ms power control loop is running
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 17:18:44 +0100
+
osmo-bts (1.1.0) unstable; urgency=medium
[ Daniel Willmann ]
diff --git a/debian/compat b/debian/compat
index ec635144..f599e28b 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+10
diff --git a/debian/control b/debian/control
index 2b667164..6a77d56c 100644
--- a/debian/control
+++ b/debian/control
@@ -1,26 +1,42 @@
Source: osmo-bts
-Maintainer: Holger Hans Peter Freyther <holger@moiji-mobile.com>
+Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Section: net
Priority: optional
-Build-Depends: debhelper (>= 9),
+Build-Depends: debhelper (>= 10),
pkg-config,
dh-autoreconf,
- dh-systemd (>= 1.5),
autotools-dev,
pkg-config,
- libosmocore-dev,
- libosmo-abis-dev,
+ libosmocore-dev (>= 1.9.0),
+ libosmo-abis-dev (>= 1.5.0),
+ libosmo-netif-dev (>= 1.4.0),
libgps-dev,
txt2man,
- osmo-gsm-manuals-dev
+ osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.8
-Vcs-Browser: http://git.osmocom.org/osmo-bts/
-Vcs-Git: git://git.osmocom.org/osmo-bts
+Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-bts
+Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-bts
Homepage: https://projects.osmocom.org/projects/osmobts
+Package: osmo-bts
+Architecture: any
+Depends: osmo-bts-trx, osmo-bts-virtual, ${misc:Depends}
+Description: Base Transceiver Station for GSM
+ OsmoBTS is a software implementation of Layer2/3 of a BTS. It implements the
+ following protocols/interfaces:
+ LAPDm (GSM 04.06)
+ RTP
+ A-bis/IP in IPA multiplex
+ OML (GSM TS 12.21)
+ RSL (GSM TS 08.58)
+ .
+ OsmoBTS is modular and has support for multiple back-ends. A back-end talks to
+ a specific L1/PHY implementation of the respective BTS hardware. Based on this
+ architecture, it should be relatively easy to add a new back-end to support
+ so-far unsupported GSM PHY/L1 and associated hardware.
+
Package: osmo-bts-trx
Architecture: any
-Conflicts: osmo-bts
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: osmo-bts-trx GSM BTS with osmo-trx
osmo-bts-trx to be used with the osmo-trx application
@@ -35,7 +51,6 @@ Description: Debug symbols for the osmo-bts-trx
Package: osmo-bts-virtual
Architecture: any
-Conflicts: osmo-bts
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Virtual Osmocom GSM BTS (no RF hardware; GSMTAP/UDP)
This version of OsmoBTS doesn't use actual GSM PHY/Hardware/RF, but
diff --git a/debian/osmo-bts-trx.postinst b/debian/osmo-bts-trx.postinst
new file mode 100755
index 00000000..af5d8218
--- /dev/null
+++ b/debian/osmo-bts-trx.postinst
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+case "$1" in
+ configure)
+ # Create the osmocom group and user (if it doesn't exist yet)
+ if ! getent group osmocom >/dev/null; then
+ groupadd --system osmocom
+ fi
+ if ! getent passwd osmocom >/dev/null; then
+ useradd \
+ --system \
+ --gid osmocom \
+ --home-dir /var/lib/osmocom \
+ --shell /sbin/nologin \
+ --comment "Open Source Mobile Communications" \
+ osmocom
+ fi
+
+ # Fix permissions of previous (root-owned) install (OS#4107)
+ if dpkg --compare-versions "$2" le "1.13.0"; then
+ if [ -e /etc/osmocom/osmo-bts-trx.cfg ]; then
+ chown -v osmocom:osmocom /etc/osmocom/osmo-bts-trx.cfg
+ chmod -v 0660 /etc/osmocom/osmo-bts-trx.cfg
+ fi
+
+ if [ -d /etc/osmocom ]; then
+ chown -v root:osmocom /etc/osmocom
+ chmod -v 2775 /etc/osmocom
+ fi
+
+ mkdir -p /var/lib/osmocom
+ chown -R -v osmocom:osmocom /var/lib/osmocom
+ fi
+ ;;
+esac
+
+# dh_installdeb(1) will replace this with shell code automatically
+# generated by other debhelper scripts.
+#DEBHELPER#
+
diff --git a/debian/osmo-bts-virtual.install b/debian/osmo-bts-virtual.install
index f4d988f4..63cc425d 100644
--- a/debian/osmo-bts-virtual.install
+++ b/debian/osmo-bts-virtual.install
@@ -3,4 +3,3 @@ lib/systemd/system/osmo-bts-virtual.service
usr/bin/osmo-bts-virtual
usr/bin/osmo-bts-omldummy
usr/share/doc/osmo-bts/examples/osmo-bts-virtual/osmo-bts-virtual.cfg
-usr/share/doc/osmo-bts/examples/osmo-bts-virtual/openbsc-virtual.cfg
diff --git a/debian/osmo-bts-virtual.postinst b/debian/osmo-bts-virtual.postinst
new file mode 100755
index 00000000..19ecd83f
--- /dev/null
+++ b/debian/osmo-bts-virtual.postinst
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+case "$1" in
+ configure)
+ # Create the osmocom group and user (if it doesn't exist yet)
+ if ! getent group osmocom >/dev/null; then
+ groupadd --system osmocom
+ fi
+ if ! getent passwd osmocom >/dev/null; then
+ useradd \
+ --system \
+ --gid osmocom \
+ --home-dir /var/lib/osmocom \
+ --shell /sbin/nologin \
+ --comment "Open Source Mobile Communications" \
+ osmocom
+ fi
+
+ # Fix permissions of previous (root-owned) install (OS#4107)
+ if dpkg --compare-versions "$2" le "1.13.0"; then
+ if [ -e /etc/osmocom/osmo-bts-virtual.cfg ]; then
+ chown -v osmocom:osmocom /etc/osmocom/osmo-bts-virtual.cfg
+ chmod -v 0660 /etc/osmocom/osmo-bts-virtual.cfg
+ fi
+
+ if [ -d /etc/osmocom ]; then
+ chown -v root:osmocom /etc/osmocom
+ chmod -v 2775 /etc/osmocom
+ fi
+
+ mkdir -p /var/lib/osmocom
+ chown -R -v osmocom:osmocom /var/lib/osmocom
+ fi
+ ;;
+esac
+
+# dh_installdeb(1) will replace this with shell code automatically
+# generated by other debhelper scripts.
+#DEBHELPER#
+
diff --git a/doc/control_interface.txt b/doc/control_interface.txt
index 5ad97172..dd3dba29 100644
--- a/doc/control_interface.txt
+++ b/doc/control_interface.txt
@@ -4,7 +4,7 @@ h2. generic
h3. trx.0.thermal-attenuation
-The idea of this paramter is to attenuate the system output power as part of
+The idea of this parameter is to attenuate the system output power as part of
thermal management. In some cases the PA might be passing a critical level,
so an external control process can use this attribute to reduce the system
output power.
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am
index 37990692..6a1ae959 100644
--- a/doc/examples/Makefile.am
+++ b/doc/examples/Makefile.am
@@ -1,17 +1,29 @@
-OSMOCONF_FILES = virtual/osmo-bts-virtual.cfg
+# all config examples must be listed here unconditionally, so that
+# all of them end up in the release tarball (see OS#6349)
+EXTRA_DIST = \
+ trx/osmo-bts-trx.cfg \
+ trx/osmo-bts-trx-calypso.cfg \
+ octphy/osmo-bts-trx2dsp1.cfg \
+ octphy/osmo-bts-octphy.cfg \
+ oc2g/osmo-bts-oc2g.cfg \
+ oc2g/oc2gbts-mgr.cfg \
+ sysmo/sysmobts-mgr.cfg \
+ sysmo/osmo-bts-sysmo.cfg \
+ litecell15/osmo-bts-lc15.cfg \
+ litecell15/lc15bts-mgr.cfg \
+ virtual/osmo-bts-virtual.cfg \
+ $(NULL)
doc_virtualdir = $(docdir)/examples/osmo-bts-virtual
doc_virtual_DATA = \
- virtual/osmo-bts-virtual.cfg \
- virtual/openbsc-virtual.cfg
-EXTRA_DIST = $(doc_virtual_DATA)
+ virtual/osmo-bts-virtual.cfg
+OSMOCONF_FILES = virtual/osmo-bts-virtual.cfg
if ENABLE_SYSMOBTS
doc_sysmodir = $(docdir)/examples/osmo-bts-sysmo
doc_sysmo_DATA = \
sysmo/osmo-bts-sysmo.cfg \
sysmo/sysmobts-mgr.cfg
-EXTRA_DIST += $(doc_sysmo_DATA)
OSMOCONF_FILES += sysmo/osmo-bts-sysmo.cfg sysmo/sysmobts-mgr.cfg
endif
@@ -20,7 +32,6 @@ doc_trxdir = $(docdir)/examples/osmo-bts-trx
doc_trx_DATA = \
trx/osmo-bts-trx.cfg \
trx/osmo-bts-trx-calypso.cfg
-EXTRA_DIST += $(doc_trx_DATA)
OSMOCONF_FILES += trx/osmo-bts-trx.cfg
endif
@@ -29,7 +40,6 @@ doc_octphydir = $(docdir)/examples/osmo-bts-octphy
doc_octphy_DATA = \
octphy/osmo-bts-trx2dsp1.cfg \
octphy/osmo-bts-octphy.cfg
-EXTRA_DIST += $(doc_octphy_DATA)
OSMOCONF_FILES += octphy/osmo-bts-octphy.cfg
endif
@@ -38,7 +48,6 @@ doc_lc15dir = $(docdir)/examples/osmo-bts-lc15
doc_lc15_DATA = \
litecell15/osmo-bts-lc15.cfg \
litecell15/lc15bts-mgr.cfg
-EXTRA_DIST += $(doc_lc15_DATA)
OSMOCONF_FILES += litecell15/osmo-bts-lc15.cfg litecell15/lc15bts-mgr.cfg
endif
@@ -47,7 +56,6 @@ doc_oc2gdir = $(docdir)/examples/osmo-bts-oc2g
doc_oc2g_DATA = \
oc2g/osmo-bts-oc2g.cfg \
oc2g/oc2gbts-mgr.cfg
-EXTRA_DIST += $(doc_oc2g_DATA)
OSMOCONF_FILES += oc2g/osmo-bts-oc2g.cfg oc2g/oc2gbts-mgr.cfg
endif
diff --git a/doc/examples/litecell15/lc15bts-mgr.cfg b/doc/examples/litecell15/lc15bts-mgr.cfg
index a92a3fd6..850fb15f 100644
--- a/doc/examples/litecell15/lc15bts-mgr.cfg
+++ b/doc/examples/litecell15/lc15bts-mgr.cfg
@@ -3,10 +3,12 @@
!!
!
log stderr
- logging filter all 1
logging color 1
- logging print category 0
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level temp info
logging level fw info
logging level find info
diff --git a/doc/examples/litecell15/osmo-bts-lc15.cfg b/doc/examples/litecell15/osmo-bts-lc15.cfg
index 907d83a2..16651eb7 100644
--- a/doc/examples/litecell15/osmo-bts-lc15.cfg
+++ b/doc/examples/litecell15/osmo-bts-lc15.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
diff --git a/doc/examples/oc2g/oc2gbts-mgr.cfg b/doc/examples/oc2g/oc2gbts-mgr.cfg
index 8248f60d..ce72e5d3 100644
--- a/doc/examples/oc2g/oc2gbts-mgr.cfg
+++ b/doc/examples/oc2g/oc2gbts-mgr.cfg
@@ -3,10 +3,12 @@
!!
!
log stderr
- logging filter all 1
logging color 1
- logging print category 0
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level temp info
logging level fw info
logging level find info
diff --git a/doc/examples/oc2g/osmo-bts-oc2g.cfg b/doc/examples/oc2g/osmo-bts-oc2g.cfg
index f985f3bc..ddf69f42 100644
--- a/doc/examples/oc2g/osmo-bts-oc2g.cfg
+++ b/doc/examples/oc2g/osmo-bts-oc2g.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
diff --git a/doc/examples/octphy/osmo-bts-octphy.cfg b/doc/examples/octphy/osmo-bts-octphy.cfg
index d6d03b5d..a3a00930 100644
--- a/doc/examples/octphy/osmo-bts-octphy.cfg
+++ b/doc/examples/octphy/osmo-bts-octphy.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
diff --git a/doc/examples/octphy/osmo-bts-trx2dsp1.cfg b/doc/examples/octphy/osmo-bts-trx2dsp1.cfg
index bf590f7d..477bff8a 100644
--- a/doc/examples/octphy/osmo-bts-trx2dsp1.cfg
+++ b/doc/examples/octphy/osmo-bts-trx2dsp1.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
diff --git a/doc/examples/sysmo/osmo-bts-sysmo.cfg b/doc/examples/sysmo/osmo-bts-sysmo.cfg
index 6ff043d8..f44c7189 100644
--- a/doc/examples/sysmo/osmo-bts-sysmo.cfg
+++ b/doc/examples/sysmo/osmo-bts-sysmo.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
diff --git a/doc/examples/sysmo/sysmobts-mgr.cfg b/doc/examples/sysmo/sysmobts-mgr.cfg
index f891ada7..00be2fd0 100644
--- a/doc/examples/sysmo/sysmobts-mgr.cfg
+++ b/doc/examples/sysmo/sysmobts-mgr.cfg
@@ -3,9 +3,12 @@
!!
!
log stderr
- logging filter all 1
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level temp info
logging level fw info
logging level find info
diff --git a/doc/examples/trx/osmo-bts-trx-calypso.cfg b/doc/examples/trx/osmo-bts-trx-calypso.cfg
index 6b52fd2a..018744f8 100644
--- a/doc/examples/trx/osmo-bts-trx-calypso.cfg
+++ b/doc/examples/trx/osmo-bts-trx-calypso.cfg
@@ -1,11 +1,15 @@
!
! OsmoBTS configuration example for CalypsoBTS
-! http://osmocom.org/projects/baseband/wiki/CalypsoBTS
+! https://osmocom.org/projects/baseband/wiki/CalypsoBTS
!!
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl notice
logging level oml notice
logging level rll notice
@@ -22,17 +26,17 @@ line vty
!
phy 0
instance 0
- osmotrx rx-gain 1
osmotrx ip local 127.0.0.1
osmotrx ip remote 127.0.0.1
- osmotrx timing-advance-loop
- osmotrx ms-power-loop -65
osmotrx legacy-setbsic
+ osmotrx fn-advance 20
+ osmotrx rts-advance 5
bts 0
oml remote-ip 127.0.0.1
- ipa unit-id 1801 0
+ ipa unit-id 6969 0
gsmtap-sapi pdtch
gsmtap-sapi ccch
band 900
trx 0
phy 0 instance 0
+ nominal-tx-power 23
diff --git a/doc/examples/trx/osmo-bts-trx.cfg b/doc/examples/trx/osmo-bts-trx.cfg
index 83426979..6b239527 100644
--- a/doc/examples/trx/osmo-bts-trx.cfg
+++ b/doc/examples/trx/osmo-bts-trx.cfg
@@ -4,7 +4,11 @@
!
log stderr
logging color 1
+ logging print category-hex 0
+ logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl notice
logging level oml notice
logging level rll notice
@@ -21,7 +25,6 @@ line vty
!
phy 0
instance 0
- osmotrx rx-gain 1
osmotrx ip local 127.0.0.1
osmotrx ip remote 127.0.0.1
bts 0
diff --git a/doc/examples/virtual/openbsc-virtual.cfg b/doc/examples/virtual/openbsc-virtual.cfg
deleted file mode 100644
index be79d589..00000000
--- a/doc/examples/virtual/openbsc-virtual.cfg
+++ /dev/null
@@ -1,151 +0,0 @@
-!
-! OpenBSC (0.15.0.629-34f0-dirty) configuration saved from vty
-!!
-!
-log stderr
- logging filter all 1
- logging color 0
- logging print category 1
- logging timestamp 1
- logging level all info
- logging level rll notice
- logging level cc notice
- logging level mm debug
- logging level rr notice
- logging level rsl notice
- logging level nm info
- logging level mncc notice
- logging level pag notice
- logging level meas notice
- logging level sccp notice
- logging level msc notice
- logging level mgcp notice
- logging level ho notice
- logging level db notice
- logging level ref notice
- logging level gprs debug
- logging level ns info
- logging level bssgp debug
- logging level llc debug
- logging level sndcp debug
- logging level nat notice
- logging level ctrl notice
- logging level smpp debug
- logging level filter debug
- logging level ranap debug
- logging level sua debug
- logging level lglobal notice
- logging level llapd notice
- logging level linp notice
- logging level lmux notice
- logging level lmi notice
- logging level lmib notice
- logging level lsms notice
- logging level lctrl notice
- logging level lgtp notice
- logging level lstats notice
- logging level lgsup notice
- logging level loap notice
-!
-stats interval 5
-!
-line vty
- no login
-!
-e1_input
- e1_line 0 driver ipa
- e1_line 0 port 0
- no e1_line 0 keepalive
-network
- network country code 262
- mobile network code 42
- short name OpenBSC
- long name OpenBSC
- auth policy accept-all
- authorized-regexp .*
- location updating reject cause 13
- encryption a5 0
- neci 1
- paging any use tch 0
- rrlp mode ms-based
- mm info 1
- handover 0
- handover window rxlev averaging 10
- handover window rxqual averaging 1
- handover window rxlev neighbor averaging 10
- handover power budget interval 6
- handover power budget hysteresis 3
- handover maximum distance 9999
- timer t3101 10
- timer t3103 0
- timer t3105 0
- timer t3107 0
- timer t3109 4
- timer t3111 0
- timer t3113 60
- timer t3115 0
- timer t3117 0
- timer t3119 0
- timer t3122 10
- timer t3141 0
- subscriber-keep-in-ram 0
- bts 0
- type sysmobts
- band DCS1800
- cell_identity 6969
- location_area_code 1
- base_station_id_code 63
- ms max power 0
- cell reselection hysteresis 4
- rxlev access min 0
- periodic location update 30
- radio-link-timeout 32
- channel allocator descending
- rach tx integer 9
- rach max transmission 7
- channel-descrption attach 1
- channel-descrption bs-pa-mfrms 5
- channel-descrption bs-ag-blks-res 1
- ip.access unit_id 6969 0
- oml ip.access stream_id 255 line 0
- neighbor-list mode automatic
- codec-support fr
- gprs mode none
- no force-combined-si
- trx 0
- rf_locked 0
- arfcn 666
- nominal power 0
- max_power_red 0
- rsl e1 tei 0
- timeslot 0
- phys_chan_config CCCH+SDCCH4
- hopping enabled 0
- timeslot 1
- phys_chan_config SDCCH8
- hopping enabled 0
- timeslot 2
- phys_chan_config TCH/F
- hopping enabled 0
- timeslot 3
- phys_chan_config TCH/F
- hopping enabled 0
- timeslot 4
- phys_chan_config TCH/F
- hopping enabled 0
- timeslot 5
- phys_chan_config TCH/F
- hopping enabled 0
- timeslot 6
- phys_chan_config TCH/F
- hopping enabled 0
- timeslot 7
- phys_chan_config TCH/F
- hopping enabled 0
-mncc-int
- default-codec tch-f fr
- default-codec tch-h hr
-nitb
- subscriber-create-on-demand
- subscriber-create-on-demand random 1 24
- assign-tmsi
diff --git a/doc/examples/virtual/osmo-bts-virtual.cfg b/doc/examples/virtual/osmo-bts-virtual.cfg
index dbdc22fa..4663f17f 100644
--- a/doc/examples/virtual/osmo-bts-virtual.cfg
+++ b/doc/examples/virtual/osmo-bts-virtual.cfg
@@ -3,10 +3,12 @@
!!
!
log stderr
- logging filter all 0
- logging color 0
+ logging color 1
+ logging print category-hex 0
logging print category 1
logging timestamp 0
+ logging print file basename last
+ logging print level 1
logging level rsl info
logging level oml info
logging level rll notice
@@ -50,12 +52,11 @@ bts 0
rtp jitter-buffer 100
paging queue-size 200
paging lifetime 0
- uplink-power-target -75
min-qual-rach 50
min-qual-norm -5
trx 0
power-ramp max-initial 23000 mdBm
power-ramp step-size 2000 mdB
power-ramp step-interval 1
- ms-power-control dsp
+ ms-power-control osmo
phy 0 instance 0
diff --git a/doc/manuals/Makefile.am b/doc/manuals/Makefile.am
index e8018d57..1c83c742 100644
--- a/doc/manuals/Makefile.am
+++ b/doc/manuals/Makefile.am
@@ -3,7 +3,6 @@ EXTRA_DIST = dtx.dot \
osmobts-abis-docinfo.xml \
osmobts-usermanual.adoc \
osmobts-usermanual-docinfo.xml \
- osmobts-vty-reference.xml \
rtp-amr.adoc \
rtp-amr-docinfo.xml \
regen_doc.sh \
@@ -18,8 +17,32 @@ if BUILD_MANUALS
osmobts-abis.pdf: $(srcdir)/abis/*.adoc $(srcdir)/abis/*.msc
rtp-amr.pdf: $(srcdir)/dtx.dot
- VTY_REFERENCE = osmobts-vty-reference.xml
- include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
+ # NOTE: osmo-bts-omldummy has no VTY interface
+ VARIANTS = virtual
+
+if ENABLE_SYSMOBTS
+ VARIANTS += sysmo
+endif
+
+if ENABLE_TRX
+ VARIANTS += trx
+endif
+
+if ENABLE_OCTPHY
+ VARIANTS += octphy
+endif
+
+if ENABLE_LC15BTS
+ VARIANTS += lc15
+endif
+
+if ENABLE_OC2GBTS
+ VARIANTS += oc2g
+endif
+
+ # This is a significantly modified, multi-target adopted copy of
+ # $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
+ include $(srcdir)/vty/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-bts
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
diff --git a/doc/manuals/abis/oml.adoc b/doc/manuals/abis/oml.adoc
index 4afcec04..b77894cb 100644
--- a/doc/manuals/abis/oml.adoc
+++ b/doc/manuals/abis/oml.adoc
@@ -3,16 +3,17 @@
=== List of Messages
The following tables list the OML messages used by OsmoBTS, grouped by their
-level of compliance with 3GPP TS 12.21.
+level of compliance with 3GPP TS 52.021 [[3gpp-ts-52-021]] (previously 3GPP TS
+12.21).
-==== Messages Compliant With TS 12.21
+==== Messages Compliant With TS 52.021
Specific limitations apply, see the linked sections.
-.Messages compliant with TS 12.21
+.Messages compliant with TS 52.021
[options="header",cols="10%,10%,20%,35%,5%,20%"]
|===
-| TS 12.21 § | type code (hex) | This document § | Message | <-/-> | Received/Sent by OsmoBTS
+| TS 52.021 § | type code (hex) | This document § | Message | <-/-> | Received/Sent by OsmoBTS
6+<| *SW Download Management Messages:*
| 8.3.7 | 0x10 | <<sw_act_rep>> | SW Activated Report | -> | Sent
6+<| *Air Interface Management Messages:*
@@ -34,12 +35,16 @@ Specific limitations apply, see the linked sections.
.3+.| 8.9.2 | 0x74 .3+.| <<opstart>> | Opstart | <- | Received
| 0x75 | Opstart Ack | -> | Sent
| 0x76 | Opstart Nack | -> | Sent
+6+<| *Other Messages:*
+.3+.| 8.11.1 | 0x81 | <<get_attributes>> | Get Attributes | <- | Received
+ | 8.11.3 | 0x82 | <<get_attr_resp>> | Get Attribute Response | -> | Sent
+ | 8.11.1 | 0x83 | | Get Attributes Nack | -> | Sent
|===
==== Messages Specific to OsmoBTS
-.Messages specific to OsmoBTS, not found in 3GPP TS 12.21
+.Messages specific to OsmoBTS, not found in 3GPP TS 52.021
[options="header"]
[options="header",cols="20%,55%,5%,20%"]
|===
@@ -49,10 +54,10 @@ Specific limitations apply, see the linked sections.
==== Messages Not Implemented by OsmoBTS
-.3GPP TS 12.21 messages not implemented by OsmoBTS
+.3GPP TS 52.021 messages not implemented by OsmoBTS
[options="header",cols="10%,10%,80%"]
|===
-| TS 12.21 § | type code (hex) | Message
+| TS 52.021 § | type code (hex) | Message
3+<| *SW Download Management Messages:*
.3+.| 8.3.1 | 0x01 | Load Data Initiate
| 0x02 | Load Data Initiate Ack
@@ -136,9 +141,6 @@ Specific limitations apply, see the linked sections.
| 8.10.3 | 0x8C | Stop Measurement
| 8.10.4 | 0x8D | Start Measurement
3+<| *Other Messages:*
- | 8.11.1 | 0x81 | Get Attributes
- | 8.11.3 | 0x82 | Get Attribute(s) Response
- | 8.11.1 | 0x83 | Get Attributes Nack
.3+.| 8.11.2 | 0x84 | Set Alarm Threshold
| 0x85 | Set Alarm Threshold Ack
| 0x86 | Set Alarm Threshold Nack
@@ -151,7 +153,7 @@ Specific limitations apply, see the linked sections.
==== SW Activated Report
OsmoBTS will send an _SW Activated Report_ when RF has been activated
-successfully. The message is compliant with 3GPP TS 12.21 § 8.3.7.
+successfully. The message is compliant with 3GPP TS 52.021 § 8.3.7.
Upon RF activation, two _SW Activated Report_ messages will be sent, for the Object Classes
@@ -163,13 +165,13 @@ Upon RF activation, two _SW Activated Report_ messages will be sent, for the Obj
OsmoBTS will receive a _Set BTS Attributes_ message and reply with a
corresponding ACK message on success. IE handling is fully compliant to TS
-12.21, except that a change of BCCH ARFCN or BSIC while in operation is not
+52.021, except that a change of BCCH ARFCN or BSIC while in operation is not
supported, and hence the _Starting Time_ IE is rejected.
._Set BTS Attributes_ IEs not handled by OsmoBTS
[options="header",cols="10%,30%,60%"]
|===
-| TS 12.21 § | IE Name | Handling
+| TS 52.021 § | IE Name | Handling
| 9.4.52 | Starting Time | not supported (provokes NACK cause 0x10)
|===
@@ -177,13 +179,13 @@ supported, and hence the _Starting Time_ IE is rejected.
[[set_radio_attr]]
==== Set Radio Carrier Attributes
-This message conforms to 3GPP TS 12.21, with the following limitation,
+This message conforms to 3GPP TS 52.021, with the following limitation,
as frequency hopping is not supported by OsmoBTS:
._Set Radio Carrier Attributes_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 12.21 § | IE Name | Handling
+| TS 52.021 § | IE Name | Handling
| 9.4.5 | ARFCN List | ignored
|===
@@ -191,14 +193,14 @@ as frequency hopping is not supported by OsmoBTS:
[[set_chan_attr]]
==== Set Channel Attributes
-This message conforms to 3GPP TS 12.21, with the following limitation: the
-following 3GPP TS 12.21 IEs provoke a NACK response when sent to OsmoBTS, as
+This message conforms to 3GPP TS 52.021, with the following limitation: the
+following 3GPP TS 52.021 IEs provoke a NACK response when sent to OsmoBTS, as
frequency hopping is not supported:
._Set Channel Attributes_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 12.21 § | IE Name | Handling
+| TS 52.021 § | IE Name | Handling
| 9.4.21 | HSN | not supported (provokes NACK cause 0x10)
| 9.4.27 | MAIO | not supported (provokes NACK cause 0x10)
| 9.4.52 | Starting Time | not supported (provokes NACK cause 0x10)
@@ -207,34 +209,54 @@ frequency hopping is not supported:
[[state_changed_rep]]
==== State Changed Event Report
-This message is compliant with 3GPP TS 12.21. Exactly these IEs are sent by
+This message is compliant with 3GPP TS 52.021. Exactly these IEs are sent by
OsmoBTS:
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message Type (0xf5) | 3GPP TS 12.21 9.1 | M | V | 1
-| Object Class | 3GPP TS 12.21 9.2 | M | V | 1
-| Object Instance | 3GPP TS 12.21 9.3 | M | V | 3
-| Operational State | 3GPP TS 12.21 9.4.38 | O | TV | 2
-| Availability Status | 3GPP TS 12.21 9.4.7 | O | TL16V (with length of 1) | 3
+| Message Type (0xf5) | 3GPP TS 52.021 9.1 | M | V | 1
+| Object Class | 3GPP TS 52.021 9.2 | M | V | 1
+| Object Instance | 3GPP TS 52.021 9.3 | M | V | 3
+| Operational State | 3GPP TS 52.021 9.4.38 | O | TV | 2
+| Availability Status | 3GPP TS 52.021 9.4.7 | O | TL16V (with length of 1) | 3
|===
[[chg_adm_state]]
==== Change Administrative State
-This message is compliant with 3GPP TS 12.21 § 8.8.5. It applies to all of the
-Object Classes defined in 3GPP TS 12.21 § 9.2 as well as
+This message is compliant with 3GPP TS 52.021 § 8.8.5. It applies to all of the
+Object Classes defined in 3GPP TS 52.021 § 9.2 as well as
<<addnl_obj_classes>>.
[[opstart]]
==== Opstart
-This message is compliant with 3GPP TS 12.21 § 8.9.2. It applies to all of the
-Object Classes defined in 3GPP TS 12.21 § 9.2 as well as
+This message is compliant with 3GPP TS 52.021 § 8.9.2. It applies to all of the
+Object Classes defined in 3GPP TS 52.021 § 9.2 as well as
<<addnl_obj_classes>>.
+[[get_attributes]]
+==== Get Attributes
+
+This message is compliant with 3GPP TS 52.021 § 8.11.1.
+
+For a list of supported attributes, see <<get_attr_resp>>.
+
+[[get_attr_resp]]
+==== Get Attribute Response
+
+This message is compliant with 3GPP TS 52.021 § 8.11.3.
+
+The following attributes are provided by OsmoBTS:
+
+[options="header"]
+|===
+| 3GPP TS 52.021 chapter | description | see
+| 9.4.61 | SW Configuration | <<NM_ATT_SW_CONFIG>>
+| 9.4.30 | Manufacturer Id | <<NM_ATT_MANUF_ID>>
+|===
=== Details on OsmoBTS Specific Messages
@@ -252,9 +274,9 @@ The message specifics depend on the Object Class and are detailed in
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message Type (0xf5) | 3GPP TS 12.21 9.1 | M | V | 1
-| Object Class | 3GPP TS 12.21 9.2 | M | V | 1
-| Object Instance | 3GPP TS 12.21 9.3 | M | V | 3
+| Message Type (0xf5) | 3GPP TS 52.021 9.1 | M | V | 1
+| Object Class | 3GPP TS 52.021 9.2 | M | V | 1
+| Object Instance | 3GPP TS 52.021 9.3 | M | V | 3
5+<| _Object Class specific IEs follow, see <<addnl_obj_classes>>..._
|===
@@ -262,7 +284,7 @@ The message specifics depend on the Object Class and are detailed in
[[addnl_obj_classes]]
=== Additional Object Classes
-In addition to 3GPP TS 12.21 Chapter 9.2, the following managed objects
+In addition to 3GPP TS 52.021 Chapter 9.2, the following managed objects
are supported:
.Additional Managed Object Classes
@@ -284,9 +306,9 @@ with the following Information Elements:
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message Type | 3GPP TS 12.21 9.1 | M | V | 1
-| Object Class | 3GPP TS 12.21 9.2 | M | V | 1
-| Object Instance | 3GPP TS 12.21 9.3 | M | V | 3
+| Message Type | 3GPP TS 52.021 9.1 | M | V | 1
+| Object Class | 3GPP TS 52.021 9.2 | M | V | 1
+| Object Instance | 3GPP TS 52.021 9.3 | M | V | 3
| GPRS NSEI | <<NM_ATT_IPACC_NSEI>> | O | TL16V | >= 5
| GPRS NS Configuration | <<NM_ATT_IPACC_NS_LINK_CFG>> | O | TL16V | >= 10
| GPRS BSSGP Configuration | <<NM_ATT_IPACC_BSSGP_CFG>> | O | TL16V | >= 14
@@ -301,9 +323,9 @@ message with the following Information Elements:
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message Type | 3GPP TS 12.21 9.1 | M | V | 1
-| Object Class | 3GPP TS 12.21 9.2 | M | V | 1
-| Object Instance | 3GPP TS 12.21 9.3 | M | V | 3
+| Message Type | 3GPP TS 52.021 9.1 | M | V | 1
+| Object Class | 3GPP TS 52.021 9.2 | M | V | 1
+| Object Instance | 3GPP TS 52.021 9.3 | M | V | 3
| GPRS Routing Area Code | <<NM_ATT_IPACC_RAC>> | O | TL16V | >= 4
| GPRS Paging Configuration | <<NM_ATT_IPACC_GPRS_PAGING_CFG>> | O | TL16V | >= 5
| GPRS RLC Configuration | <<NM_ATT_IPACC_RLC_CFG>> | O | TL16V | >= 12
@@ -321,9 +343,9 @@ Attribute* message with the following Information Elements:
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message Type | 3GPP TS 12.21 9.1 | M | V | 1
-| Object Class | 3GPP TS 12.21 9.2 | M | V | 1
-| Object Instance | 3GPP TS 12.21 9.3 | M | V | 3
+| Message Type | 3GPP TS 52.021 9.1 | M | V | 1
+| Object Class | 3GPP TS 52.021 9.2 | M | V | 1
+| Object Instance | 3GPP TS 52.021 9.3 | M | V | 3
| GPRS NSVCI | <<NM_ATT_IPACC_NSVCI>> | O | TL16V | >= 5
| GPRS NS Link Configuration | <<NM_ATT_IPACC_NS_LINK_CFG>> | O | TL16V | >= 11
|===
@@ -332,9 +354,9 @@ Attribute* message with the following Information Elements:
=== Information Elements Overview
All of the IEs handled by OsmoBTS are listed below, with limitations and
-additions to TS 12.21 specified in more detail.
+additions to TS 52.021 specified in more detail.
-==== IEs Conforming to TS 12.21
+==== IEs Conforming to TS 52.021
The following Information Elements are accepted by OsmoBTS.
@@ -346,10 +368,10 @@ IEs marked __ignored__ and additionally marked as being received by OsmoBTS
(<-) are in fact parsed and their values are stored by OsmoBTS, but these
stored items are currently not used in the OsmoBTS code base.
-.IEs conforming to TS 12.21
+.IEs conforming to TS 52.021
[options="header",cols="5%,10%,40%,5%,40%"]
|===
-| tag (hex) | TS 12.21 § | IE name | <-/-> | Received/Sent by OsmoBTS
+| tag (hex) | TS 52.021 § | IE name | <-/-> | Received/Sent by OsmoBTS
| 0x00 | 9.4.1 | Abis Channel | | _ignored_
| 0x01 | 9.4.2 | Additional Info | | _ignored_
| 0x02 | 9.4.3 | Additional Text | | _ignored_
@@ -372,8 +394,8 @@ stored items are currently not used in the OsmoBTS code base.
| 0x13 | 9.4.19 | File Version | | _ignored_
| 0x14 | 9.4.20 | GSM Time | | _ignored_
| 0x16 | 9.4.22 | HW Configuration | | _ignored_
-| 0x18 | 9.4.24 | Intave Parameter | <- | _ignored_
-| 0x19 | 9.4.25 | Interference level Boundaries | <- | _ignored_
+| 0x18 | 9.4.24 | Intave Parameter | <- |
+| 0x19 | 9.4.25 | Interference level Boundaries | <- |
| 0x1a | 9.4.26 | List of Required Attributes | | _ignored_
| 0x1c | 9.4.28 | Manufacturer Dependent State | | _ignored_
| 0x1d | 9.4.29 | Manufacturer Dependent Thresholds | | _ignored_
@@ -405,20 +427,20 @@ stored items are currently not used in the OsmoBTS code base.
| 0x38 | 9.4.58 | VSWR Thresholds | | _ignored_
| 0x39 | 9.4.59 | Window Size | | _ignored_
| 0x40 | 9.4.60 | TSC | <- | Received, with limitations: see <<NM_ATT_TSC>>
-| 0x41 | 9.4.61 | SW Configuration | | _ignored_
+| 0x41 | 9.4.61 | SW Configuration | -> | Sent, see <<NM_ATT_SW_CONFIG>>
| 0x43 | 9.4.63 | Perceived Severity | | _ignored_
-| 0x44 | 9.4.64 | Get Attribute Response Info | | _ignored_
+| 0x44 | 9.4.64 | Get Attribute Response Info | -> | Sent, see <<NM_ATT_MANUF_ID>>
| 0x45 | 9.4.65 | Outstanding Alarm Sequence | | _ignored_
| 0x46 | 9.4.66 | HW Conf Change Info | | _ignored_
| 0x47 | 9.4.32 | Measurement Result | | _ignored_
|===
-==== IEs Not Conforming to TS 12.21
+==== IEs Not Conforming to TS 52.021
-.IEs not conforming to TS 12.21
+.IEs not conforming to TS 52.021
[options="header",cols="5%,10%,30%,55%"]
|===
-| tag (hex) | TS 12.21 § | IE name | Description
+| tag (hex) | TS 52.021 § | IE name | Description
| 0x15 | 9.4.21 | HSN | presence causes NACK response
| 0x17 | 9.4.23 | HW Description | _ignored_ by OsmoBTS, but coding may differ, see <<ie_hw_desc>>
| 0x1b | 9.4.27 | MAIO | presence causes NACK response
@@ -431,14 +453,14 @@ stored items are currently not used in the OsmoBTS code base.
==== Additional Attributes and Parameters
The following Information Elements are defined in addition to those
-specified in 3GPP TS 12.21 Chapter 9.4.
+specified in 3GPP TS 52.021 Chapter 9.4.
All of these additional IEs are _received_ by OsmoBTS.
These attributes are not used by OsmoBTS, but
simply passed to OsmoPCU connected to the PCU socket.
-.Additional IEs handled by OsmoBTS but not defined in TS 12.21
+.Additional IEs handled by OsmoBTS but not defined in TS 52.021
[options="header",cols="5%,50%,45%"]
|===
| tag (hex) | IE name | Description
@@ -465,7 +487,7 @@ simply passed to OsmoPCU connected to the PCU socket.
[[ie_hw_desc]]
==== HW Description
-TS 12.21 suggests a series of 5 length-value pairs for the _HW Description_ IE.
+TS 52.021 suggests a series of 5 length-value pairs for the _HW Description_ IE.
Instead, OsmoBTS interprets it as a single TL16V. The value of this IE is
ignored by OsmoBTS, yet the coding may affect message parsing.
@@ -487,7 +509,7 @@ exactly one ARFCN.
[[ie_chan_comb]]
==== Additional Channel Combinations
-In addition to 3GPP TS 12.21 Chapter 9.4.13, the following channel
+In addition to 3GPP TS 52.021 Chapter 9.4.13, the following channel
combinations are supported:
.Additional Channel Combinations
@@ -513,7 +535,7 @@ work, please see the <<rsl-dynamic-channels>>.
[[ie_conn_fail_crit]]
==== Connection Failure Criterion
-3GPP TS 12.21 Chapter 9.4.14 specifies two different options for the
+3GPP TS 52.021 Chapter 9.4.14 specifies two different options for the
_Connection Failure Criterion_. OsmoBTS only implements the option
coded as 0x01, i.e. based upon uplink SACCH error rate
(RADIO_LINK_TIMEOUT).
@@ -523,7 +545,7 @@ coded as 0x01, i.e. based upon uplink SACCH error rate
Due to limitations in the currently supported PHY implementations,
OsmoBTS supports only one global TSC for all channels on one TRX, rather
-than a separate TSC for each timeslot, as expected by 3GPP TS 12.21.
+than a separate TSC for each timeslot, as expected by 3GPP TS 52.021.
[[NM_ATT_IPACC_DST_IP]]
@@ -783,10 +805,91 @@ It is encoded as follows:
This attribute is not used by OsmoBTS, but
simply passed to OsmoPCU connected to the PCU socket.
+[[NM_ATT_SW_CONFIG]]
+==== SW Configuration
+
+The SW Configuration IE is compliant with 3GPP TS 52.021 9.4.61: it contains a
+number of SW Description IEs (9.4.62).
+
+
+.Coding of SW Configuration IE
+[options="header",cols="20%,80%"]
+|===
+| octet | value
+| 1 | NM_ATT_SW_CONFIG IEI (0x41)
+| 2-3 | length of value part
+| 4 | NM_ATT_SW_DESCR IEI (0x42)
+| 5 | NM_ATT_FILE_ID IEI (0x12)
+| 6-7 | length of file name
+| 8-N | ASCII coded file name (without terminating nul)
+| N+1 | NM_ATT_FILE_VERSION IEI (0x13)
+| N+2 - N+3 | length of file content
+| N+4 - M | file content
+| M+1 | NM_ATT_SW_DESCR IEI (0x42)
+| M+2 | NM_ATT_FILE_ID IEI (0x12)
+2+| ...
+|===
+
+.File names and content sent in the SW Configuration IE
+[options="header",cols="20%,80%"]
+|===
+| file name | content
+| 'osmobts' | ASCII coded OsmoBTS version number like "1.2.3" or "1.2.3.4-abcd"
+| 'BTS_TYPE_VARIANT' | one of "osmo-bts-lc15", "osmo-bts-oc2g", "osmo-bts-octphy",
+ "osmo-bts-omldummy", "osmo-bts-sysmo", "osmo-bts-trx", "osmo-bts-virtual"
+| 'BTS_SUB_MODEL' | This file may be omitted; if present, may contain an ASCII
+ coded model number like "sysmoBTS 1002"
+|===
+
+
+[[NM_ATT_MANUF_ID]]
+==== Manufacturer Id
+
+The coding of the Manufacturer Id attribute is a sequence of bit flags (a bit
+vector), where a zero flag indicates absence and a set flag indicates presence
+of a specific BTS feature.
+
+The number of flags transmitted depends on the software version of OsmoBTS and
+the BTS backend in use. More flags may be added in the future. The flag bits
+transmitted are followed by zero bits up to the next full octet boundary.
+
+These features are currently defined:
+
+.coding of BTS feature flags sent in the Manufacturer Id attribute
+[options="header",cols="5%,5%,30%,60%"]
+|===
+| octet | bit | feature name | description
+.8+.| 0 | 7 | HSCSD | High-Speed Circuit-Switched Data
+ | 6 | GPRS | General Packet Radio Service
+ | 5 | EGPRS | Enhanced GPRS (EDGE)
+ | 4 | ECSD | Enhanced Circuit-Switched Data
+ | 3 | HOPPING | Frequency Hopping
+ | 2 | MULTI_TSC | Multi-TSC
+ | 1 | OML_ALERTS | OML Alerts
+ | 0 | AGCH_PCH_PROP | AGCH/PCH proportional allocation
+.8+.| 1 | 7 | CBCH | Cell Broadcast Channel
+ | 6 | SPEECH_F_V1 | Fullrate speech V1
+ | 5 | SPEECH_H_V1 | Halfrate speech V1
+ | 4 | SPEECH_F_EFR | Fullrate speech EFR
+ | 3 | SPEECH_F_AMR | Fullrate speech AMR
+ | 2 | SPEECH_H_AMR | Halfrate speech AMR
+ | 1 | ETWS_PN | ETWS Primary Notification via PCH
+ | 0 | PAGING_COORDINATION | BSS Paging Coordination
+.8+.| 2 | 7 | IPV6_NSVC | NSVC IPv6
+ | 6 | ACCH_REP | FACCH/SACCH Repetition
+ | 5 | CCN | Cell Change Notification
+ | 4 | VAMOS | Voice services over Adaptive Multi-user channels on One Slot
+ | 3 2.4+.| reserved for future use, sent as zero
+ | 2
+ | 1
+ | 0
+|===
+
+
=== A-bis OML Initialization / BTS bring-up
At the time an Abis/IP BTS connects to via OML to the BSC, it is
-initialized according to the procedures described in 3GPP TS 12.21 as
+initialized according to the procedures described in 3GPP TS 52.021 as
amended by this document.
Each Managed Object (MO) is separately initialized. The initialization
diff --git a/doc/manuals/abis/rsl.adoc b/doc/manuals/abis/rsl.adoc
index 86beaa2a..6e8746a6 100644
--- a/doc/manuals/abis/rsl.adoc
+++ b/doc/manuals/abis/rsl.adoc
@@ -3,16 +3,16 @@
=== List of Messages
The following tables list the RSL messages used by OsmoBTS A-bis/IP,
-grouped by their level of compliance with 3GPP TS 08.58.
+grouped by their level of compliance with 3GPP TS 48.058.
-==== Messages Compliant With TS 08.58
+==== Messages Compliant With TS 48.058
Specific additions and limitations apply, see the linked sections.
-.Messages compliant with TS 08.58
+.Messages compliant with TS 48.058
[options="header",cols="10%,20%,45%,5%,20%"]
|===
-| TS 08.58 § | This document § | Message | <-/-> | Received/Sent by OsmoBTS
+| TS 48.058 § | This document § | Message | <-/-> | Received/Sent by OsmoBTS
5+<| *Radio link layer management messages*
| 8.3.1 | - | DATA REQUEST | <- | Received
| 8.3.2 | - | DATA INDICATION | -> | Sent
@@ -59,7 +59,7 @@ Specific additions and limitations apply, see the linked sections.
==== Messages Specific to OsmoBTS
-.Messages specific to OsmoBTS, not found in 3GPP TS 08.58
+.Messages specific to OsmoBTS, not found in 3GPP TS 48.058
[options="header",cols="15%,15%,45%,5%,20%"]
|===
2+| This document § | Message | <-/-> | Received/Sent by OsmoBTS
@@ -87,10 +87,10 @@ Specific additions and limitations apply, see the linked sections.
==== Messages Not Implemented by OsmoBTS
-.3GPP TS 08.58 messages not implemented by OsmoBTS
+.3GPP TS 48.058 messages not implemented by OsmoBTS
[options="header",cols="10%,90%"]
|===
-| TS 08.58 § | Message
+| TS 48.058 § | Message
2+<| *DEDICATED CHANNEL MANAGEMENT MESSAGES*
| 8.4.12 | PHYSICAL CONTEXT REQUEST
| 8.4.13 | PHYSICAL CONTEXT CONFIRM
@@ -123,7 +123,7 @@ Specific additions and limitations apply, see the linked sections.
==== Channel Activation
When used on a timeslot using the non-standard channel combination
-'NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH' as configured by OML, the regular
+'NM_CHANC_OSMO_DYN' as configured by OML, the regular
RSL channel activation procedures can not only be used for activation
of circuit-switched channels, but also for activation of a PDCH.
@@ -135,24 +135,24 @@ dynamic PDCH protocol employed by nanoBTS devices (<<ipa_style_pdch_mgmt>>).
[[MEASUREMENT_RESULT]]
==== Measurement Result
-Conforms to 3GPP TS 08.58 § 8.4.8 with this limitation:
+Conforms to 3GPP TS 48.058 § 8.4.8 with this limitation:
._Measurement Result_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.37 | MS Timing Offset | never sent by OsmoBTS
|===
[[MODE_MODIFY]]
==== Mode Modify
-Conforms to 3GPP TS 08.58 § 8.4.9 with these limitations:
+Conforms to 3GPP TS 48.058 § 8.4.9 with these limitations:
._Mode Modify_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.45 | Main channel reference | _ignored_
| 9.3.53 | MultiRate Control | _ignored_
| 9.3.54 | Supported Codec Types | _ignored_
@@ -161,12 +161,12 @@ Conforms to 3GPP TS 08.58 § 8.4.9 with these limitations:
[[MS_POWER_CONTROL]]
==== MS Power Control
-Conforms to 3GPP TS 08.58 § 8.4.15 with these limitations:
+Conforms to 3GPP TS 48.058 § 8.4.15 with these limitations:
._MS Power Control_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.31 | MS Power Parameters | _ignored_
|===
@@ -174,12 +174,12 @@ Conforms to 3GPP TS 08.58 § 8.4.15 with these limitations:
[[SACCH_INFO_MODIFY]]
==== SACCH Info Modify
-Conforms to 3GPP TS 08.58 § 8.4.20, with these exceptions:
+Conforms to 3GPP TS 48.058 § 8.4.20, with these exceptions:
._SACCH Info Modify_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.30 | System Info Type | See below for available types
| 9.3.23 | Starting Time | not supported, provokes an _Error Report_ response
|===
@@ -192,6 +192,7 @@ Conforms to 3GPP TS 08.58 § 8.4.20, with these exceptions:
| 0x06 | RSL_SYSTEM_INFO_6
| 0x0d | RSL_SYSTEM_INFO_5bis
| 0x0e | RSL_SYSTEM_INFO_5ter
+| 0x0f | RSL_SYSTEM_INFO_10
| 0x47 | RSL_EXT_MEAS_ORDER
| 0x48 | RSL_MEAS_INFO
|===
@@ -199,12 +200,12 @@ Conforms to 3GPP TS 08.58 § 8.4.20, with these exceptions:
[[BCCH_INFORMATION]]
==== BCCH Information
-Conforms to 3GPP TS 08.58 § 8.5.1, with these limitations and extensions:
+Conforms to 3GPP TS 48.058 § 8.5.1, with these limitations and extensions:
._BCCH Information_ IE details
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.30 | System Info Type | See <<SACCH_INFO_MODIFY>> for available types
| 9.3.11 | L3 Info | This IE may be included instead of a 9.3.39 _Full BCCH Info_ IE.
The _Full BCCH Info_ takes precedence over _L3 Info_.
@@ -215,12 +216,12 @@ Conforms to 3GPP TS 08.58 § 8.5.1, with these limitations and extensions:
[[CHANNEL_REQUIRED]]
==== Channel Required
-Conforms to 3GPP TS 08.58 § 8.5.3, with these limitations:
+Conforms to 3GPP TS 48.058 § 8.5.3, with these limitations:
._Channel Required_ message IE details
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.16 | Physical Context | never sent by OsmoBTS
|===
@@ -228,12 +229,12 @@ Conforms to 3GPP TS 08.58 § 8.5.3, with these limitations:
[[PAGING_COMMAND]]
==== Paging Command
-Conforms to 3GPP TS 08.58 § 8.5.5, with these limitations:
+Conforms to 3GPP TS 48.058 § 8.5.5, with these limitations:
._Paging Command_ message IE details
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.49 | eMLPP Priority | _ignored_
|===
@@ -244,28 +245,28 @@ in any way.
[[RF_RESOURCE_INDICATION]]
==== RF Resource Indication
-This message does not conform to 3GPP TS 08.58 § 8.6.1, in that it omits the
-_Resource Information_ IE that would contain the actual payload data, which
-renders this message void.
+For all osmo-bts variants, except osmo-bts-trx, this message does not conform
+to 3GPP TS 48.058 § 8.6.1, in that it omits the _Resource Information_ IE that
+would contain the actual payload data, which renders this message void.
._RF Resource Indication_ message IE exceptions
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
-| 9.3.21 | Resource Information | OsmoBTS omits this IE, though TS 08.58
- specifies it as mandatory.
+| TS 48.058 § | IE Name | Handling
+| 9.3.21 | Resource Information | DSP based osmo-bts variants omit this IE, though
+ TS 48.058 specifies it as mandatory.
|===
[[SACCH_FILLING]]
==== SACCH Filling
-Conforms to 3GPP TS 08.58 § 8.6.2, with these limitations:
+Conforms to 3GPP TS 48.058 § 8.6.2, with these limitations:
._SACCH Filling_ message IE limitations
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.3.30 | System Info Type | See <<SACCH_INFO_MODIFY>> for available types
| 9.3.23 | Starting Time | _ignored_
|===
@@ -275,7 +276,7 @@ Conforms to 3GPP TS 08.58 § 8.6.2, with these limitations:
=== User Plane Transport Management
This chapter defines the A-bis/IP specific RSL procedures that are
-introduced in addition to the 3GPP TS 08.58 standard procedures.
+introduced in addition to the 3GPP TS 48.058 standard procedures.
In classic A-bis over E1, user plane traffic is carried over 16kBps
sub-slots of 64kBps E1 time-slots according to ETSI/3GPP TS 08.60. As
@@ -346,7 +347,7 @@ See <<rsl_dlcx_ind_msg>>
In the classic data model established by ETSI/3GPP for A-bis, each
timeslot (channel) is configured using a static channel combination by
means of A-bis OML. Particularly in presence of GPRS services, this
-is very unflexible and leads to inefficient use of air interface
+is very inflexible and leads to inefficient use of air interface
resources.
As such, several methods have been implemented to overcome this
@@ -417,16 +418,16 @@ include::dyn_ts_ipa_style2.msc[]
==== Osmocom Style Dynamic Channels
This method is in use when OML uses
-'NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH' (0x90) for the given time-slot.
+'NM_CHANC_OSMO_DYN' (0x90) for the given time-slot.
The activation of PDCH is performed by using the regular 'RSL CHANNEL ACTIVATE'
procedure according to <<CHANNEL_ACTIVATION>>, with these modifications:
* The 'C-bits' part of the 'Channel Number' IE take the non-standard binary
- value 11000 (C5 thru C1 as seen in 3GPP TS 08.58 § 9.3.1).
+ value 11000 (C5 through C1 as seen in 3GPP TS 48.058 § 9.3.1).
* The 'A-bits' part of the 'Activation Type' IE take the non-standard binary
- value 1111, with an additional fourth bit (add A4 to A3 thru A1 as seen in
- 3GPP TS 08.58 § 9.3.3; all remaining reserved bits as well as the 'R' bit are
+ value 1111, with an additional fourth bit (add A4 to A3 through A1 as seen in
+ 3GPP TS 48.058 § 9.3.3; all remaining reserved bits as well as the 'R' bit are
coded as zero).
* The normally mandatory 'Channel Mode' IE is omitted; none of the optional IEs
are included.
@@ -436,7 +437,7 @@ Hence the message consists of exactly these IEs:
.PDCH type _Channel Activation_ message IEs
[options="header",cols="10%,30%,60%"]
|===
-| TS 08.58 § | IE Name | Handling
+| TS 48.058 § | IE Name | Handling
| 9.1 | Message discriminator | Dedicated Channel Management
| 9.2 | Message type | CHANnel ACTIVation
| 9.3.1 | Channel number | 'C-bits' 11000, plus TS bits as usual
@@ -476,6 +477,26 @@ signaling for it.
See <<OSMO_ETWS_CMD>> for the Osmocom implementation.
+=== BCCH carrier power reduction operation
+
+According to 3GPP TS 45.008, section 7.1, the BCCH carrier (sometimes called C0) of
+a BTS shall maintain discontinuous Downlink transmission at full power in order to
+stay "visible" to the mobile stations. Because of that, early versions of this 3GPP
+document prohibited BS power reduction on C0. However, a new feature was introduced
+version 13.0.0 (2015-11) - "BCCH carrier power reduction operation".
+
+This is a special mode of operation, in which the variation of RF power level for
+some timeslots is relaxed for the purpose of energy saving. In other words, the
+output power on some timeslots, except the timeslot(s) carrying BCCH/CCCH, can be
+lower than the full power. In this case the maximum allowed difference is 6 dB.
+
+Unfortunately, 3GPP did not specify in which way the BTS is instructed to activate
+and deactivate the BCCH carrier power reduction mode. Osmocom had to invent their
+own non-standard approach: the BSC needs to send _BS POWER CONTROL_ message with
+the _Channel Number_ IE set to 0x80 (BCCH) and the _Message Discriminator_ set to
+0x06 (Common Channel Management messages).
+
+
=== Message Formats and Contents
[[rsl_crcx_msg]]
@@ -488,14 +509,15 @@ number*.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Destination IP Address | <<RSL_IE_IPAC_REMOTE_IP>> | O | TV | 5
| Destination IP Port | <<RSL_IE_IPAC_REMOTE_PORT>> | O | TV | 3
| IP Speech Mode | <<RSL_IE_IPAC_SPEECH_MODE>> | O | TV | 2
| RTP Payload Type 2 | <<RSL_IE_IPAC_RTP_PAYLOAD2>> | O | TV | 2
+| RTP CSD Format | <<RSL_IE_IPAC_RTP_CSD_FORMAT>> | O | TV | 2
|===
[[rsl_crcx_msg_ack]]
@@ -508,10 +530,10 @@ in response to the *Create Connection (CRCX)*.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | M | TV | 3
| Source IP Address | <<RSL_IE_IPAC_LOCAL_IP>> | O | TV | 5
| Source IP Port | <<RSL_IE_IPAC_LOCAL_PORT>> | O | TV | 3
@@ -528,13 +550,13 @@ sent in response to the *Create Connection (CRCX)*.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Destination IP Address | <<RSL_IE_IPAC_REMOTE_IP>> | O | TV | 5
| Destination IP Port | <<RSL_IE_IPAC_REMOTE_PORT>> | O | TV | 3
-| Cause | 08.58 9.3.26 | O | TLV | >= 3
+| Cause | 48.058 9.3.26 | O | TLV | >= 3
|===
@@ -547,15 +569,16 @@ properties of a user-plane RTP connection.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | O | TV | 3
| Destination IP Address | <<RSL_IE_IPAC_REMOTE_IP>> | O | TV | 5
| Destination IP Port | <<RSL_IE_IPAC_REMOTE_PORT>> | O | TV | 3
| IP Speech Mode | <<RSL_IE_IPAC_SPEECH_MODE>> | O | TV | 2
| RTP Payload Type 2 | <<RSL_IE_IPAC_RTP_PAYLOAD2>> | O | TV | 2
+| RTP CSD Format | <<RSL_IE_IPAC_RTP_CSD_FORMAT>> | O | TV | 2
|===
[[rsl_mdcx_msg_ack]]
@@ -568,10 +591,10 @@ response to a *Modify Connection (MDCX)*
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | O | TV | 3
| Source IP Address | <<RSL_IE_IPAC_LOCAL_IP>> | C | TV | 5
| Source IP Port | <<RSL_IE_IPAC_LOCAL_PORT>> | C | TV | 3
@@ -589,11 +612,11 @@ Connection (MDCX)*.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
-| Cause | 08.58 9.3.26 | M | TLV | >= 3
+| Channel number | 48.058 9.3.1 | M | TV | 2
+| Cause | 48.058 9.3.26 | M | TLV | >= 3
|===
[[rsl_dlcx_ind_msg]]
@@ -606,13 +629,13 @@ time of RF Channel release.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | M | TV | 3
| Connection Id | <<RSL_IE_IPAC_CONN_STAT>> | M | TV | 3
-| Cause | 08.58 9.3.26 | M | TLV | >= 3
+| Cause | 48.058 9.3.26 | M | TLV | >= 3
|===
[[rsl_dlcx_msg]]
@@ -625,10 +648,10 @@ number.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | O | TV | 3
|===
@@ -643,10 +666,10 @@ Channel number. It is sent in response to the *Delete Connection
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | O | TV | 3
| Connection Statistics | <<RSL_IE_IPAC_CONN_STAT>> | C | TV | 29
|===
@@ -662,12 +685,12 @@ Channel number. It is sent in response to the *Delete Connection
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
| Connection Id | <<RSL_IE_IPAC_CONN_ID>> | O | TV | 3
-| Cause | 08.58 9.3.26 | M | TLV | >= 3
+| Cause | 48.058 9.3.26 | M | TLV | >= 3
|===
[[rsl_pdch_act]]
@@ -679,10 +702,10 @@ a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -696,11 +719,11 @@ of a PDCH on a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
-| Frame Number | 08.58 9.3.8 | O | TV | 3
+| Channel number | 48.058 9.3.1 | M | TV | 2
+| Frame Number | 48.058 9.3.8 | O | TV | 3
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -714,11 +737,11 @@ of a PDCH on a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
-| Cause | 08.58 9.3.26 | M | TLV | >= 3
+| Channel number | 48.058 9.3.1 | M | TV | 2
+| Cause | 48.058 9.3.26 | M | TLV | >= 3
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -732,10 +755,10 @@ on a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -749,10 +772,10 @@ of a PDCH on a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
+| Channel number | 48.058 9.3.1 | M | TV | 2
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -766,11 +789,11 @@ on a IPA style dynamic TCH/F+PDCH channel.
[options="header"]
[cols="30%,25%,15%,15%,15%"]
|===
-| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
-| Cause | 08.58 9.3.26 | M | TLV | >= 3
+| Channel number | 48.058 9.3.1 | M | TV | 2
+| Cause | 48.058 9.3.26 | M | TLV | >= 3
|===
NOTE:: This message is *not* used by Osmocom style dynamic channels
@@ -794,10 +817,10 @@ The Channel Number IE is set to the Downlink CCCH (PCH).
[cols="30%,25%,15%,15%,15%"]
|===
| INFORMATION ELEMENT | REFERENCE | PRESENCE | FORMAT | LENGTH
-| Message discriminator | 08.58 9.1 | M | V | 1
+| Message discriminator | 48.058 9.1 | M | V | 1
| Message type | <<own_msg_types>> | M | V | 1
-| Channel number | 08.58 9.3.1 | M | TV | 2
-| SMSCB Message | 08.58 9.3.42 | M | TLV | 2-58
+| Channel number | 48.058 9.3.1 | M | TV | 2
+| SMSCB Message | 48.058 9.3.42 | M | TLV | 2-58
|===
@@ -807,7 +830,7 @@ The Channel Number IE is set to the Downlink CCCH (PCH).
==== A-bis/IP specific RSL Message discriminators
The following message discriminators are used in addition to those
-indicated in 3GPP TS 08.58 Section 9.1:
+indicated in 3GPP TS 48.058 Section 9.1:
.OsmoBTS specific new message discriminators
[options="header",cols="10%,50%,40%"]
@@ -835,37 +858,54 @@ indicated in 3GPP TS 08.58 Section 9.1:
==== A-bis/IP specific RSL IEIs
The following Information Element Identifiers (IEIs) are used in
-addition to those indicated in 3GPP TS 08.58 Section 9.3:
+addition to those indicated in 3GPP TS 48.058 Section 9.3:
.A-bis/IP specific information elements
[options="header",cols="10%,50%,40%"]
|===
| IEI | Name | This document §
| 0x01 | RSL_IE_CHAN_NR | <<RSL_IE_CHAN_NR>>
-| 0xf0 | RSL_IE_IPAC_REMOTE_IP | <<RSL_IE_IPAC_REMOTE_IP>>
+| 0x60 | RSL_IE_OSMO_REP_ACCH_CAP | <<RSL_IE_OSMO_REP_ACCH_CAP>>
+| 0x61 | RSL_IE_OSMO_TRAINING_SEQUENCE | <<RSL_IE_OSMO_TRAINING_SEQUENCE>>
+| 0x62 | RSL_IE_OSMO_TEMP_OVP_ACCH_CAP | <<RSL_IE_OSMO_TEMP_OVP_ACCH_CAP>>
+| 0x63 | RSL_IE_OSMO_OSMUX_CID | <<RSL_IE_OSMO_OSMUX_CID>>
+| 0xf0 | RSL_IE_IPAC_REMOTE_IP | <<RSL_IE_IPAC_REMOTE_IP>>
| 0xf1 | RSL_IE_IPAC_REMOTE_PORT | <<RSL_IE_IPAC_REMOTE_PORT>>
| 0xf3 | RSL_IE_IPAC_LOCAL_PORT | <<RSL_IE_IPAC_LOCAL_PORT>>
| 0xf4 | RSL_IE_IPAC_SPEECH_MODE | <<RSL_IE_IPAC_SPEECH_MODE>>
| 0xf5 | RSL_IE_IPAC_LOCAL_IP | <<RSL_IE_IPAC_LOCAL_IP>>
| 0xf6 | RSL_IE_IPAC_CONN_STAT | <<RSL_IE_IPAC_CONN_STAT>>
| 0xf8 | RSL_IE_IPAC_CONN_ID | <<RSL_IE_IPAC_CONN_ID>>
+| 0xf9 | RSL_IE_IPAC_RTP_CSD_FORMAT | <<RSL_IE_IPAC_RTP_CSD_FORMAT>>
| 0xfc | RSL_IE_IPAC_RTP_PAYLOAD2 | <<RSL_IE_IPAC_RTP_PAYLOAD2>>
|===
[[RSL_IE_CHAN_NR]]
==== RSL_IE_CHAN_NR
-This information element is coded like 3GPP TS 08.58 Section 9.3.1,
-but in addition supports the following extended coding:
+This information element is coded as described in 3GPP TS 48.058 Section 9.3.1,
+but in addition supports the following vendor specific values:
-* C5..C1 bits 0b11000 for PDCH type channels
+.RSL Channel Number extensions
+[options="header",cols="5%,5%,5%,5%,5%,75%"]
+|===
+| C5 | C4 | C3 | C2 | C1 | Description
+| 1 | 1 | 0 | 0 | 0 | PDCH `<1>`
+| 1 | 1 | 0 | 0 | 1 | CBCH on SDCCH4
+| 1 | 1 | 0 | 1 | 0 | CBCH on SDCCH8
+| 1 | 1 | 1 | 0 | 1 | VAMOS TCH/F `<2>`
+| 1 | 1 | 1 | 1 | T | VAMOS TCH/H `<2>`
+|===
+
+`<1>` This extension is only valid on an Osmocom-style dynamic channel, having
+configured the 'NM_CHANC_IPAC_TCHFull_PDCH' channel combination by OML.
+`<2>` These Osmocom specific values are used by osmo-bsc to address logical
+channels on the shadow timeslots in VAMOS mode, iff the BTS is an osmo-bts
+and VAMOS capable.
The TN-Bits are not re-defined in this case but use the same encoding
-as specified in TS 08.58 Section 9.3.1.
+as specified in TS 48.058 Section 9.3.1.
-NOTE:: The above extension is only valid on an Osmocom-style dynamic
-channel, having configured the 'NM_CHANC_IPAC_TCHFull_PDCH' channel
-combination by OML.
[[RSL_IE_IPAC_REMOTE_IP]]
==== RSL_IE_IPAC_REMOTE_IP
@@ -919,8 +959,8 @@ IEI followed by four bytes IPv4 address.
This information element contains statistics about the RTP connection.
-It is encoded as 29 bytes, with the first byte as IEI and 28 bytes
-fixed-length payload encoded as follows:
+It is encoded as 30 bytes, with the first byte as IEI, the second byte as length
+(=28), and 28 bytes fixed-length payload encoded as follows:
.A-bis/IP Connection Statistics
[options="header",width="60%",cols="15%,15%,70%"]
@@ -953,6 +993,147 @@ This information element contains the RTP payload identifier, which is
used in the PT (Payload Type) field of the RTP header in subsequent
transmissions of the RTP flow.
+[[RSL_IE_OSMO_REP_ACCH_CAP]]
+==== RSL_IE_OSMO_REP_ACCH_CAP
+
+This is a one byte length TLV IE that is used to enable or disable repeated ACCH
+capabilities on the BTS side during Channel Activation and Mode Modify.
+
+The IE contains a bitfield in the lower nibble in order to set the ACCH repetition
+policy for each of the two channel types individually. Depending on the state of the
+bits (see table below) the ACCH repetition mode is either enabled or disabled completely.
+
+The lower 3 bit of the higher nibble are used to signal an RXQUAL threshold to set the
+BER on which UL-SACCH or DL-FACCH repetition shall be turned on. If the field is set
+to 0, then UL-SACCH and DL-FACCH will be always on. DL-FACCH will also be turned on
+automatically as soon as the MS requests a DL-SACCH repetition.
+
+If the IE is not present, then ACCH repetition completely is disabled.
+
+[options="header"]
+|===
+| *bit* | 7 | 6 - 4 | 3 | 2 | 1 | 0
+| byte at offset 0 | 0 | RXQUAL | UL-SACCH | DL-SACCH | DL-FACCH/ALL | DL-FACCH/CMD
+|===
+
+(Bits 7 is reserved for future use and must be set to zero.)
+
+[[RSL_IE_OSMO_TRAINING_SEQUENCE]]
+==== RSL_IE_OSMO_TRAINING_SEQUENCE
+
+This TLV IE instructs the BTS to use a specific training sequence set and
+training sequence code for a given lchan. It is sent by OsmoBSC in RSL CHANNEL
+ACTIVATION and MODE MODIFY messages to the BTS, iff the BTS is VAMOS-capable,
+i.e. if an Abis-over-IP connected BTS indicated BTS_FEAT_VAMOS in the OML BTS
+features (Manufacturer Id information element, see <<NM_ATT_MANUF_ID>>).
+
+If this information element is present, the receiver shall ignore any other
+training sequence set and training sequence code bits from other information
+elements of the same RSL message.
+
+This is an Osmocom-specific extension of the RSL layer, which was added to
+express more than two TSC sets. For VAMOS operation, OsmoBSC selects from one
+of four separate training sequence codings per modulation scheme, while usual
+RSL IEs are only able to express a single-bit TSC set number. For clarity, this
+IE contains both the TSC set and the TSC in one IE, and is defined as
+overruling any other IEs containing TSC or TSC set numbers.
+
+The first value octet indicates the training sequence set, and the second octet
+indicates the training sequence code to be used. Receiving values from a
+reserved value range should be considered an error condition.
+
+.RSL_IE_OSMO_TRAINING_SEQUENCE
+[options="header",width="80%",cols="20%,80%"]
+|===
+| IE octet | value
+| octet 1 | RSL_IE_OSMO_TRAINING_SEQUENCE IEI (0x61)
+| octet 2 | length of the value part (2)
+| octet 3 | TSC set
+| octet 4 | TSC
+|===
+
+The training sequence set (TSC set) is coded like the 'CS Domain TSC Set' bits,
+as defined in the 'Extended TSC Set' IE in 3GPP TS 44.018 10.5.2.82
+<<3gpp-ts-44-018>>, and corresponds to the 'TSC Set' as defined in 3GPP TS
+45.002 <<3gpp-ts-45-002>>. The encoded training sequence set number ranges from
+0 to 3, any other values are reserved for future use. The encoded 0 corresponds
+to TSC Set 1, see <<RSL_IE_OSMO_TRAINING_SEQUENCE__TSC_set_coding>>.
+
+[[RSL_IE_OSMO_TRAINING_SEQUENCE__TSC_set_coding]]
+.TSC set (octet 3) coding
+[options="header",width="80%",cols="20%,80%"]
+|===
+| octet 3 value | interpretation
+| 0 | 'TSC Set 1' as in 3GPP TS 45.002
+| 1 | 'TSC Set 2'
+| 2 | 'TSC Set 3'
+| 3 | 'TSC Set 4'
+| 4..255 | reserved values
+|===
+
+The training sequence code (TSC) corresponds to the 'TSC' bits as defined in
+the 'Channel Description 2' IE in 3GPP TS 44.018 10.5.2.5a <<3gpp-ts-44-018>>.
+The training sequence code ranges from 0 to 7, any other values are reserved
+for future use.
+
+.TSC (octet 4) coding
+[options="header",width="80%",cols="20%,80%"]
+|===
+| octet 4 value | interpretation
+| 0 | 'Training Sequence Code (TSC) 0' as in 3GPP TS 45.002
+| 1 | 'Training Sequence Code (TSC) 1'
+| 2 | 'Training Sequence Code (TSC) 2'
+| 3 | 'Training Sequence Code (TSC) 3'
+| 4 | 'Training Sequence Code (TSC) 4'
+| 5 | 'Training Sequence Code (TSC) 5'
+| 6 | 'Training Sequence Code (TSC) 6'
+| 7 | 'Training Sequence Code (TSC) 7'
+| 8..255 | reserved values
+|===
+
+[[RSL_IE_OSMO_TEMP_OVP_ACCH_CAP]]
+==== RSL_IE_OSMO_TEMP_OVP_ACCH_CAP
+
+FIXME: this IE has been defined, but remains to be documented.
+
+[[RSL_IE_OSMO_OSMUX_CID]]
+==== RSL_IE_OSMO_OSMUX_CID
+
+FIXME: this IE has been defined, but remains to be documented.
+
+[[RSL_IE_IPAC_RTP_CSD_FORMAT]]
+==== RSL_IE_IPAC_RTP_CSD_FORMAT
+
+This information element contains the RTP Circuit Switched Data format.
+
+.A-bis/IP RTP CSD Format
+[options="header",width="60%",cols="15%,15%,70%"]
+|===
+| Offset | Size | Description
+| 0 | 4 | RTP CSD Format D
+| 4 | 4 | RTP CSD Format IR
+|===
+
+.A-bis/IP RTP CSD Format D Values
+[options="header",width="40%",cols="20%,80%"]
+|===
+| Value | Description
+| 0 | External TRAU format
+| 1 | Non-TRAU Packed format
+| 2 | TRAU within the BTS
+| 3 | IWF-Free BTS-BTS Data
+|===
+
+.A-bis/IP RTP CSD Format IR Values
+[options="header",width="40%",cols="20%,80%"]
+|===
+| Value | Description
+| 0 | 8 kb/s
+| 1 | 16 kb/s
+| 2 | 32 kb/s
+| 3 | 48 kb/s
+|===
+
=== A-bis RSL Initialization / BTS bring-up
Upon receiving the 'IPA RSL CONNECT' OML message by the respective
@@ -977,4 +1158,3 @@ The initialization of the primary and secondary TRX slightly differ, as
illustrated by the differences of <<rsl-msc-pri>> and <<rsl-msc-sec>>.
Since the secondary TRX has no BCCH, it does not (need to) receive any 'RSL
BCCH INFORMATION' messages from the BSC.
-
diff --git a/doc/manuals/chapters/architecture.adoc b/doc/manuals/chapters/architecture.adoc
index a0e66cd0..ca3a1e33 100644
--- a/doc/manuals/chapters/architecture.adoc
+++ b/doc/manuals/chapters/architecture.adoc
@@ -82,13 +82,13 @@ order to specify which PHY instance is allocated to this specific TRX.
| 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() | Install model-specific control interface commands
-| common | telnet_init() | Initialization of telnet interface
+| common | telnet_init_default() | Initialization of telnet interface
| common | pcu_sock_init() | Initialization 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
+| bts-specific | bts_model_phy_link_close() | Close each of the configured PHY links
| common | osmo_daemonize() | Fork as daemon in background (if configured)
| common | bts_main() | Run main loop until global variable quit >= 2
|===
diff --git a/doc/manuals/chapters/bts-models.adoc b/doc/manuals/chapters/bts-models.adoc
index e1f8d9a1..5cb04616 100644
--- a/doc/manuals/chapters/bts-models.adoc
+++ b/doc/manuals/chapters/bts-models.adoc
@@ -248,7 +248,7 @@ current GSM frame number.
GSM is a TDMA (time division multiple access) system on the radio
interface. OsmoTRX is the "clock master" of that in the Osmocom
implementation. It informs OsmoBTS of the current GSM frame
-number. However, as there is non-zero delays (UDP packet trnsmission
+number. However, as there is non-zero delays (UDP packet transmission
delay, operating system scheduler delay on both OsmoTRX and OsmoBTS
side, ...), OsmoBTS must compensate for that delay by "advancing"
the clock a certain amount of time.
@@ -266,12 +266,11 @@ underruns on the OsmoTRX side.
The detailed value will depend on your underlying computer systems,
operating system and related tuning parameters. Running OsmoTRX
-on a remote host will inevitably require a higher fn-advance then
-running it on the same machine, where the UDP packetes are just passed
+on a remote host will inevitably require a higher fn-advance than
+running it on the same machine, where the UDP packets are just passed
over the loopback device.
-The default value for `fn-advance` is 20 (corresponding to 92
-milliseconds).
+The default value for `fn-advance` is 2 (corresponding to 9.2 milliseconds).
===== `osmotrx rts-advance <0-30>`
@@ -282,15 +281,15 @@ The value specified as `rts-advance` is added to the current GSM frame
number as reported by OsmoTRX *and* the `osmotrx fn-advance` in order
to generate the PH-RTS.ind (ready to send indications) across the L1SAP
interface inside osmo-bts. This will trigger the Layer 2 (LAPDm for
-the ocntrol plane, RTP for the voice plane, and OsmoPCU for GPRS) to
+the control plane, RTP for the voice plane, and OsmoPCU for GPRS) to
generate a MAC block and input it into the osmo-bts-trx TDMA scheduler.
If OsmoTRX reported N as the current frame number, the actual frame number
-reported on L1SAP to higher layes will be computed as follows:
+reported on L1SAP to higher layers will be computed as follows:
N + fn-advance + rts-advance
-The default value of `rts-advance` is 5 (corresponding to 23 milliseconds).
+The default value of `rts-advance` is 3 (corresponding to 14 milliseconds).
Do not change this unless you have a good reason!
===== `osmotrx rx-gain <0-50>`
@@ -443,7 +442,7 @@ configuration at the BTS configuration file is (as always) very minimal,
as in the GSM network architecture provides almost all relevant
configuration to the BTS from the BSC.
-An example configuratin file is provided as part of the osmo-bts source
+An example configuration file is provided as part of the osmo-bts source
code: `doc/examples/virtual/osmobts-virtual.cfg`
For more information see
diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc
index 558bd4ba..f6ca75e1 100644
--- a/doc/manuals/chapters/configuration.adoc
+++ b/doc/manuals/chapters/configuration.adoc
@@ -14,12 +14,12 @@ OsmoBTS software.
=== Command Line Options
-Ths OsmoBTS executables (`osmo-bts-sysmo`, `osmo-bts-trx`,
+The OsmoBTS executables (`osmo-bts-sysmo`, `osmo-bts-trx`,
`osmo-bts-octphy`, `osmo-bts-litecell15`, ...) share the following
generic command line options:
==== SYNOPSIS
-*osmo-bts-sysmo* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE' ] [-s] [-T] [-e 'LOGLEVEL'] [-r 'PRIO'] [-i 'GSMTAP-IP'] [-t <1-255>]
+*osmo-bts-sysmo* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE' ] [-s] [-T] [-e 'LOGLEVEL']
==== OPTIONS
*-h, --help*::
@@ -48,16 +48,6 @@ generic command line options:
Set the global log level for logging to stderr. This has mostly
been deprecated by VTY based logging configuration, see
<<logging>> for further information.
-*-r, --realtime 'PRIO'*::
- Enable use of the Linux kernel realtime priority scheduler with
- the specified priority.
- It is recommended you use this option on low-performance
- embedded systems or systems that encounter high non-GSM/GPRS
- load.
-*-i, --gsmtap-ip 'GSMTAP-IP'*::
- Specify the destination IP address for GSMTAP messages.
-*-t, --trx-num <1-255>*::
- Specify the number of TRX supported by this BTS.
There may be additional, hardware specific command line options by the
different bts_model implementations.
@@ -118,11 +108,22 @@ them via UDP/IP. At that point, they can be captured with utilities like
*tcpdump* or *tshark* for further analysis by the *wireshark* protocol
analyzer.
-In order to activate this feature, you first need to make sure to start
-OsmoBTS using the `-i` or `--gsmtap-ip` command line option, specifying
-the destination IP address for the GSMTAP messages. In most cases,
-using 127.0.0.1 for passing the messages over the loopback (`lo`) device
-will be sufficient.
+In order to activate this feature, you first need to make sure to specify
+the remote address of _GSMTAP_ host in the configuration file. In most
+cases, using 127.0.0.1 for passing the messages over the loopback (`lo`)
+device will be sufficient:
+
+.Example: Enabling GSMTAP Um-frame logging to localhost
+----
+bts 0
+ gsmtap-remote-host 127.0.0.1 <1>
+----
+<1> Destination address for _GSMTAP_ Um-frames
+
+NOTE: Changing this parameter at run-time will not affect the existing
+_GSMTAP_ connection, full program restart is required.
+
+NOTE: Command line parameters `-i` and `--gsmtap-ip` have been deprecated.
OsmoBTS can selectively trace such messages by their L1 SAPI, for both
Rx and Tx. For a complete list of L1 SAPI values, please refer to the
@@ -137,8 +138,7 @@ node of the OsmoBTS VTY.
OsmoBTS> enable
OsmoBTS# configure terminal
OsmoBTS(config)# bts 0
-OsmoBTS(bts)# trx 0
-OsmoBTS(trx)# gsmtap-sapi sdcch
+OsmoBTS(bts)# gsmtap-sapi sdcch
OsmoBTS(trx)# write <1>
----
<1> the `write` command will make the configuration persistent in the
@@ -146,18 +146,37 @@ configuration file. This is not required if you wish to enable GSMTAP
only in the current session of OsmoBTS.
De-activation can be performed similarly by using the `no gsmtap-sapi
-sdcch` command at the `trx` node of the OsmoBTS VTY.
+sdcch` command at the `bts` node of the OsmoBTS VTY.
+
+It may be useful to enable all SAPIs with a few exceptions, or vice versa
+disable everything using one command. For this purpose, the VTY provides
+`gsmtap-sapi enable-all` and `gsmtap-sapi disable-all` commands.
+
+.Example: Enabling all SAPIs except PDTCH and PTCCH
+----
+bts 0
+ gsmtap-sapi enable-all <1>
+ no gsmtap-sapi pdtch <2>
+ no gsmtap-sapi ptcch <2>
+----
+<1> Enable all available SAPIs
+<2> Exclude PDTCH and PTCCH SAPIs
From the moment they are enabled via VTY, GSMTAP messages will be
generated and sent in UDP encapsulation to the IANA-registered UDP port
-for GSMTAP (4729) at the IP address specified in the command line
-argument.
+for GSMTAP (4729) of the specified remote address.
==== Configuring power ramping
OsmoBTS can ramp up the power of its trx over time. This helps reduce
cell congestion in busy environments.
+Some models of OsmoBTS (such as osmo-bts-trx) also support ramping down the
+transmit power over time until finally ceasing broadcast, for instance due to a
+trx becoming administratively locked or due to the whole BTS being gracefully
+shut down. This allows for mobile stations camping on the cell to gradually move
+to other cells in the area once the signal drop is detected.
+
In this example, the trx starts with 5dBm output power which increases by 1dB
every two seconds until it reaches nominal power.
Power ramping can use the power-ramp commands at the CONFIG TRX node of the
diff --git a/doc/manuals/chapters/interfaces.adoc b/doc/manuals/chapters/interfaces.adoc
index 9fefa729..24cfdb51 100644
--- a/doc/manuals/chapters/interfaces.adoc
+++ b/doc/manuals/chapters/interfaces.adoc
@@ -43,7 +43,7 @@ See <<vty>> for further information.
=== OsmoBTS Control Interface
-The general structure of the Omsocom control interface is described in
+The general structure of the Osmocom control interface is described in
<<common-control-if>>.
The number of control interface commands/attributes is currently quite
diff --git a/doc/manuals/chapters/osmux_bts.adoc b/doc/manuals/chapters/osmux_bts.adoc
new file mode 100644
index 00000000..8afc3c37
--- /dev/null
+++ b/doc/manuals/chapters/osmux_bts.adoc
@@ -0,0 +1,39 @@
+include::{commondir}/chapters/osmux/osmux.adoc[]
+
+=== Osmux Support in {program-name}
+
+Osmux usage in {program-name} in managed through the VTY commands in node
+`osmux`. Command `use (on|off|only)` is used to configure use policy of Osmux
+within {program-name}. Once enabled (`on` or `only`), {program-name} will
+announce the _OSMUX_ BTS feature towards the BSC over OML. This way, the BSC
+becomes aware that this BTS supports using Osmux to transfer voice call user
+data when the AMR codec is selected.
+
+It is then up to the BSC to decide whether to use Osmux or not when establishing
+a new call. If the BSC decides to use Osmux for a given call, then the _IPACC
+CRCX/MDCX_ messages sent by the BSC will contain an extra _Osmux CID_ IE
+appended, which contains the Osmux CID to be used by the BTS to send Osmux
+frames to the co-located BSC MGW (aka the BSC MGW' local CID, or {program-name}'
+remote CID). The IP address and port provided in the same messages refer to the
+address and port where Osmux frames with the provided CID are expected to be
+received. Similarly, {program-name} appends an _Osmux CID_ IE to the _IPACC
+CRCX/MDCX ACK_ message it generates, this time with its own local Osmux CID.
+Same goes for the BTS' local IP address and port where Osmux frames are expected
+to be received.
+
+{program-name} will behave differently during call set up based on the VTY
+command `use (on|off|only)` presented above:
+
+* `off`: If _IPACC CRCX_ from BSC contains _Osmux CID_ IE, meaning
+ BSC wants to use Osmux for this call, then {program-name} will reject the
+ request and the call set up will fail.
+* `on`: {program-name} will support and accept both Osmux and non-Osmux (RTP)
+ upon call set up. If _IPACC CRCX_ from BSC contains the _Osmux CID_ IE on a
+ AMR call (`Channel Mode GSM3`), it will set up an Osmux stream on its end and
+ provide the BSC with the BTS-local CID. If the BSC provides no _Osmux CID_ IE,
+ then {program-name} will set up a regular RTP based call.
+* `only`: Same as per `on`, except that {program-name} will accept only Osmux
+ calls on the CN-side, this is, if _IPACC CRCX_ from BSC doesn't
+ contain an _Osmux CID_ IE, it will reject the assignment and the call set up
+ will fail. This means also that only AMR calls (`Channel Mode GSM3`) are
+ allowed.
diff --git a/doc/manuals/chapters/overview.adoc b/doc/manuals/chapters/overview.adoc
index 6b6b8284..0dff16a1 100644
--- a/doc/manuals/chapters/overview.adoc
+++ b/doc/manuals/chapters/overview.adoc
@@ -38,7 +38,7 @@ Typical configurations either use OsmoBTS with OsmoBSC, or with
OsmoNITB, as can be seen in the following figures.
[[fig-gsm-classic]]
-.Classic GSM archtiecture using OsmoBTS with OsmoBTS components
+.Classic GSM architecture using OsmoBTS with OsmoBTS components
[graphviz]
----
digraph G {
diff --git a/doc/manuals/chapters/qos-example.adoc b/doc/manuals/chapters/qos-example.adoc
new file mode 100644
index 00000000..c31e2eb5
--- /dev/null
+++ b/doc/manuals/chapters/qos-example.adoc
@@ -0,0 +1,50 @@
+==== Full example of QoS for osmo-bts uplink QoS
+
+In the below example we will show the full set of configuration required
+for both DSCP and PCP differentiation of uplink Abis traffic by osmo-bts.
+
+What we want to achieve in this example is the following configuration:
+
+.DSCP and PCP assignments for osmo-bts uplink traffic in this example
+[options="header",width="30%",cols="2,1,1"]
+|===
+|Traffic |DSCP|PCP
+|A-bis RSL | 56| 7
+|A-bis RTP | 46| 6
+|A-bis OML | 34| 5
+|===
+
+. configure the osmocom program to set the DSCP value
+. configure an egrees QoS map to map from priority to PCP
+
+.Example Step 1: add related VTY configuration to `osmo-bts.cfg`
+----
+...
+e1_input
+ ipa ip-dscp oml 34
+ ipa socket-priority oml 5
+ ipa ip-dscp rsl 56
+ ipa socket-priority rsl 7
+...
+bts 0
+ rtp ip-dscp 46
+ rtp socket-priority 6
+ ...
+----
+
+.Example Step 2: egress QoS map to map from socket priority to PCP values
+----
+$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 1:1 5:5 6:6 7:7 <2>
+----
+<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
+<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also include the
+ mapping 1:1 from the osmo-pcu example (see <<userman-osmopcu>>) here.
+
+NOTE:: The settings of the `ip` command are volatile and only active until
+the next reboot (or the network device or VLAN is removed). Please refer to
+the documentation of your specific Linux distribution in order to find out how
+to make such settings persistent by means of an `ifup` hook whenever the interface
+comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
+script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu,
+this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
+script.
diff --git a/doc/manuals/osmobts-abis-docinfo.xml b/doc/manuals/osmobts-abis-docinfo.xml
index 4e233943..3bbbe7f1 100644
--- a/doc/manuals/osmobts-abis-docinfo.xml
+++ b/doc/manuals/osmobts-abis-docinfo.xml
@@ -1,39 +1,3 @@
-<revhistory>
- <revision>
- <revnumber>1</revnumber>
- <date>December 2015</date>
- <authorinitials>NJH, HW</authorinitials>
- <revremark>
- Initial version, reflecting OsmoBTS master branch as on 2015-Dec-7
- (commit e28a20a2d9d049cd6312e218a7646593bbc43431).
- </revremark>
- </revision>
- <revision>
- <revnumber>2</revnumber>
- <date>February 2016</date>
- <authorinitials>HW</authorinitials>
- <revremark>
- Updated version with Message Sequence Chart of OML and RSL bring-up.
- </revremark>
- </revision>
- <revision>
- <revnumber>2.1</revnumber>
- <date>February 2016</date>
- <authorinitials>HW</authorinitials>
- <revremark>
- Fix A-bis OML/RSL port number swap in message seqeuence charts.
- </revremark>
- </revision>
- <revision>
- <revnumber>2.2</revnumber>
- <date>July 2016</date>
- <authorinitials>NJH, HW</authorinitials>
- <revremark>
- Add description on Dynamic Channel Configuration in OML and activation in RSL.
- </revremark>
- </revision>
-
-</revhistory>
<authorgroup>
<author>
@@ -61,7 +25,7 @@
</authorgroup>
<copyright>
- <year>2015-2016</year>
+ <year>2015-2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
diff --git a/doc/manuals/osmobts-abis.adoc b/doc/manuals/osmobts-abis.adoc
index 857b4bfb..26e57e92 100644
--- a/doc/manuals/osmobts-abis.adoc
+++ b/doc/manuals/osmobts-abis.adoc
@@ -87,6 +87,8 @@ include::{srcdir}/abis/rtp.adoc[]
include::./common/chapters/port_numbers.adoc[]
+include::./common/chapters/bibliography.adoc[]
+
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]
diff --git a/doc/manuals/osmobts-usermanual-docinfo.xml b/doc/manuals/osmobts-usermanual-docinfo.xml
index aa3285f1..1704f899 100644
--- a/doc/manuals/osmobts-usermanual-docinfo.xml
+++ b/doc/manuals/osmobts-usermanual-docinfo.xml
@@ -1,14 +1,3 @@
-<revhistory>
- <revision>
- <revnumber>1</revnumber>
- <date>January 2016</date>
- <authorinitials>HW</authorinitials>
- <revremark>
- Initial version, reflecting OsmoBTS master branch as on FIXME
- (commit FIXME).
- </revremark>
- </revision>
-</revhistory>
<authorgroup>
<author>
@@ -25,7 +14,7 @@
</authorgroup>
<copyright>
- <year>2016</year>
+ <year>2016-2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
diff --git a/doc/manuals/osmobts-usermanual.adoc b/doc/manuals/osmobts-usermanual.adoc
index 55087b23..fc7a5bd1 100644
--- a/doc/manuals/osmobts-usermanual.adoc
+++ b/doc/manuals/osmobts-usermanual.adoc
@@ -1,4 +1,5 @@
:gfdl-enabled:
+:program-name: OsmoBTS
OsmoBTS User Manual
===================
@@ -30,6 +31,12 @@ include::{srcdir}/chapters/bts-models.adoc[]
include::{srcdir}/chapters/architecture.adoc[]
+include::{srcdir}/chapters/osmux_bts.adoc[]
+
+include::./common/chapters/qos-dscp-pcp.adoc[]
+
+include::./common/chapters/vty_cpu_sched.adoc[]
+
include::./common/chapters/trx_if.adoc[]
include::./common/chapters/control_if.adoc[]
diff --git a/doc/manuals/rtp-amr-docinfo.xml b/doc/manuals/rtp-amr-docinfo.xml
index 3f4de8d9..84d5558f 100644
--- a/doc/manuals/rtp-amr-docinfo.xml
+++ b/doc/manuals/rtp-amr-docinfo.xml
@@ -1,29 +1,3 @@
-<revhistory>
- <revision>
- <revnumber>1</revnumber>
- <date>October 2016</date>
- <authorinitials>HW</authorinitials>
- <revremark>
- Initial version
- </revremark>
- </revision>
- <revision>
- <revnumber>2</revnumber>
- <date>November 2016</date>
- <authorinitials>MS</authorinitials>
- <revremark>
- FSM added
- </revremark>
- </revision>
- <revision>
- <revnumber>3</revnumber>
- <date>July 2017</date>
- <authorinitials>PE</authorinitials>
- <revremark>
- Add section and update sequence charts to describe requirement to receive all PH-DATA.ind events
- </revremark>
- </revision>
-</revhistory>
<authorgroup>
<author>
@@ -51,7 +25,7 @@
</authorgroup>
<copyright>
- <year>2016</year>
+ <year>2016-2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
diff --git a/doc/manuals/rtp-amr.adoc b/doc/manuals/rtp-amr.adoc
index 5a36aeab..75f0e014 100644
--- a/doc/manuals/rtp-amr.adoc
+++ b/doc/manuals/rtp-amr.adoc
@@ -95,10 +95,10 @@ msc {
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_FIRST)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -110,10 +110,10 @@ msc {
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
}
@@ -123,7 +123,7 @@ ULSF2:: As per 3GPP TS 05.03 section 3.9.2.4 The last 4 bursts shall not be tran
the SID_FIRST frame is immediately followed by a speech frame. It has been observed that some phone
does not transmit the last 4 bursts even if it is not followed by a speech frame.
-ULSU2:: There must be exactly two supressed voice frames between the
+ULSU2:: There must be exactly two suppressed voice frames between the
SID_FIRST and the SID_UPDATE, i.e. there's 60ms between SID_FIRST and
SID_UPDATE.
@@ -152,52 +152,52 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -208,10 +208,10 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
}
@@ -254,10 +254,10 @@ msc {
...;
--- [label="Once voice is active again"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -345,10 +345,10 @@ msc {
...;
--- [label="FACCH/F Frame During DTX"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -368,10 +368,10 @@ msc {
phy => bts [label="PH-DATA.ind FACCH/F"];
bts => mgw [label="FACCH/F"];
- ms -x phy [label="Supressed L1 burst", id="ULSF2"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst", id="ULSF2"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_FIRST)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
...;
@@ -382,7 +382,7 @@ ULSF2:: The sub-blocks 5-8 of SID_FIRST are not transmitted, as all
information bits are contained in sub-blocks 1-4 only
Note:: It has been observed with some phones that the SID_FIRST is not sent following the FACCH/F
-frame. If this case occures the No Data Frame and SID_UPDATE order resumes.
+frame. If this case occurs the No Data Frame and SID_UPDATE order resumes.
=== TCH/AFS Downlink (Network to MS)
@@ -660,10 +660,10 @@ msc {
phy => bts [label="PH-RTS.ind (TCH)"];
phy <= bts [label="PH-EMPTY-FRAME.req (FACCH/F)"];
phy <= bts [label="PH-EMPTY-FRAME.req (TCH/F)"];
- ms x- phy [label="Supressed burst"];
- ms x- phy [label="Supressed burst"];
- ms x- phy [label="Supressed burst"];
- ms x- phy [label="Supressed burst"];
+ ms x- phy [label="Suppressed burst"];
+ ms x- phy [label="Suppressed burst"];
+ ms x- phy [label="Suppressed burst"];
+ ms x- phy [label="Suppressed burst"];
}
----
@@ -738,8 +738,8 @@ msc {
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (N)"];
bts => mgw [label="RTP (AMR FT=0..7,Q=1)"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr_SidFirstP1", id="ULSF1"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
@@ -753,8 +753,8 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
}
@@ -764,7 +764,7 @@ ULSF1:: Only SID_FIRST_P1 contains information so it must be the only one transm
NOTE:: It has been observed that not all phones transmit SID_FIRST_P2 so the PH-DATA.ind GsmL1_TchPlType_Amr_SidFirstP2 is not guaranteed to be sent to the BTS.
-ULSU1:: There must be exactly two supressed voice frames between the
+ULSU1:: There must be exactly two suppressed voice frames between the
SID_FIRST and the SID_UPDATE, i.e. there's 60ms between SID_FIRST and
SID_UPDATE.
@@ -795,33 +795,33 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -834,8 +834,8 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr (SID_UPDATE)"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
}
@@ -999,8 +999,8 @@ msc {
...;
ms .. mgw [label="FACCH/H during DTX operation"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
@@ -1026,8 +1026,8 @@ msc {
phy => bts [label="PH-DATA.ind with empty payload"];
bts -x mgw [label="Suppressed RTP frame"];
- ms -x phy [label="Supressed L1 burst"];
- ms -x phy [label="Supressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
+ ms -x phy [label="Suppressed L1 burst"];
phy => bts [label="PH-DATA.ind GsmL1_TchPlType_Amr_SidFirstP1"];
bts => mgw [label="RTP (AMR FT=SID,Q=1)"];
}
diff --git a/doc/manuals/vty/Makefile.vty-reference.inc b/doc/manuals/vty/Makefile.vty-reference.inc
new file mode 100644
index 00000000..4598aa5a
--- /dev/null
+++ b/doc/manuals/vty/Makefile.vty-reference.inc
@@ -0,0 +1,37 @@
+DOCBOOKS = $(foreach v,$(VARIANTS),vty/osmobts-$(v)-vty-reference.xml)
+DOCBOOKS_DEPS = $(DOCBOOKS) $(addsuffix .inc,$(DOCBOOKS))
+INC_DIR = $(abspath $(builddir)/vty)
+
+include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.docbook.inc
+
+CLEAN_FILES += $(DOCBOOKS_DEPS)
+CLEAN_FILES += $(addsuffix .inc.gen,$(DOCBOOKS))
+CLEAN_FILES += $(addsuffix .inc.merged,$(DOCBOOKS))
+
+$(INC_DIR):
+ mkdir -p $@
+
+vty/osmobts-%-vty-reference.xml: $(top_srcdir)/src/osmo-bts-% $(INC_DIR)
+ sed -e "s|@@GENERATED@@|$@.inc|" \
+ -e "s|@@VARIANT@@|$(notdir $<)|" \
+ -e "s|@@REV_NUMBER@@|$(VERSION)|" \
+ -e "s|@@REV_DATE@@|$(shell date +"%dth %B %Y")|" \
+ -e "s|@@CR_YEAR@@|$(shell date +"%Y")|" \
+ $(srcdir)/vty/osmobts-vty-reference.xml > $@
+
+vty/osmobts-%-vty-reference.xml.inc: $(top_builddir)/src/osmo-bts-*/osmo-bts-% \
+ $(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
+ $(OSMO_GSM_MANUALS_DIR)/common/chapters/vty.xml \
+ $(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl \
+ $(srcdir)/vty/*.xml $(INC_DIR)
+ # a) Invoke osmo-bts-% to generate the list of commands first
+ $< --vty-ref-mode default --vty-ref-xml > "$@.gen"
+ # ... filter garbage potentially printed by libraries to stdout
+ sed -i '/^<vtydoc/,$$!d' "$@.gen"
+ # b) Merge the result of a) with global and local additions
+ $(OSMO_GSM_MANUALS_DIR)/build/vty_reference_combine.sh \
+ $(realpath $(OSMO_GSM_MANUALS_DIR)/merge_doc.xsl) "$@.gen" \
+ $(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
+ $(srcdir)/vty/*additions*.xml > "$@.merged"
+ # c) Convert the result of b) into a valid docbook
+ xsltproc $(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl "$@.merged" > $@
diff --git a/doc/manuals/vty/bts_vty_additions.xml b/doc/manuals/vty/bts_vty_additions.xml
index 519c4b48..2d22b41d 100644
--- a/doc/manuals/vty/bts_vty_additions.xml
+++ b/doc/manuals/vty/bts_vty_additions.xml
@@ -1 +1,26 @@
-<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'/>
+<!-- ex:ts=2:sw=2:et -->
+<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
+ <node id='phy-inst'>
+ <!-- FIXME: This command appears twice for some reason. -->
+ <command id='osmotrx maxdly &lt;0-63&gt;'>
+ <description>
+ Access Burst is the first burst a mobile transmits in order to establish a connection and it
+ is used to estimate Timing Advance (TA) which is then applied to Normal Bursts to compensate
+ for signal delay due to distance. So changing this setting effectively changes maximum range
+ of the cell, because Access Bursts with a delay higher than this value will be ignored.
+ </description>
+ </command>
+ <!-- FIXME: This command appears unconditionally, despite being hidden. -->
+ <command id='osmotrx maxdlynb &lt;0-63&gt;'>
+ <description>
+ USE FOR TESTING ONLY, DO NOT CHANGE IN PRODUCTION USE!
+ During the normal operation, delay of Normal Bursts is controlled by the Timing Advance loop
+ and thus Normal Bursts arrive to a BTS with no more than a couple GSM symbols, which is
+ already taken into account in osmo-trx. Changing this setting will have no effect in
+ production installations except increasing osmo-trx CPU load. This setting is only useful
+ when testing with a transmitter which cannot precisely synchronize to the BTS downlink
+ signal, like R&amp;S CMD57.
+ </description>
+ </command>
+ </node>
+</vtydoc>
diff --git a/doc/manuals/vty/bts_vty_reference.xml b/doc/manuals/vty/bts_vty_reference.xml
deleted file mode 100644
index d5621c8d..00000000
--- a/doc/manuals/vty/bts_vty_reference.xml
+++ /dev/null
@@ -1,1742 +0,0 @@
-<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
- <node id='_common_cmds_'>
- <name>Common Commands</name>
- <description>These commands are available on all VTY nodes. They are listed here only once, to unclutter the VTY reference.</description>
- <command id='help'>
- <params>
- <param name='help' doc='Description of the interactive help system' />
- </params>
- </command>
- <command id='list'>
- <params>
- <param name='list' doc='Print command list' />
- </params>
- </command>
- <command id='write terminal'>
- <params>
- <param name='write' doc='Write running configuration to memory, network, or terminal' />
- <param name='terminal' doc='Write to terminal' />
- </params>
- </command>
- <command id='write file'>
- <params>
- <param name='write' doc='Write running configuration to memory, network, or terminal' />
- <param name='file' doc='Write to configuration file' />
- </params>
- </command>
- <command id='write memory'>
- <params>
- <param name='write' doc='Write running configuration to memory, network, or terminal' />
- <param name='memory' doc='Write configuration to the file (same as write file)' />
- </params>
- </command>
- <command id='write'>
- <params>
- <param name='write' doc='Write running configuration to memory, network, or terminal' />
- </params>
- </command>
- <command id='show running-config'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='running-config' doc='running configuration' />
- </params>
- </command>
- <command id='exit'>
- <params>
- <param name='exit' doc='Exit current mode and down to previous mode' />
- </params>
- </command>
- <command id='end'>
- <params>
- <param name='end' doc='End current mode and change to enable mode.' />
- </params>
- </command>
- </node>
- <node id='view'>
- <name>view</name>
- <command id='show version'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='version' doc='Displays program version' />
- </params>
- </command>
- <command id='show online-help'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='online-help' doc='Online help' />
- </params>
- </command>
- <command id='enable'>
- <params>
- <param name='enable' doc='Turn on privileged mode command' />
- </params>
- </command>
- <command id='terminal length &lt;0-512&gt;'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='length' doc='Set number of lines on a screen' />
- <param name='&lt;0-512&gt;' doc='Number of lines on screen (0 for no pausing)' />
- </params>
- </command>
- <command id='terminal no length'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='length' doc='Set number of lines on a screen' />
- </params>
- </command>
- <command id='who'>
- <params>
- <param name='who' doc='Display who is on vty' />
- </params>
- </command>
- <command id='show history'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='history' doc='Display the session command history' />
- </params>
- </command>
- <command id='show e1_driver'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_driver' doc='Display information about available E1 drivers' />
- </params>
- </command>
- <command id='show e1_line [line_nr] [stats]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_line' doc='Display information about a E1 line' />
- <param name='[line_nr]' doc='E1 Line Number' />
- <param name='[stats]' doc='Include statistics' />
- </params>
- </command>
- <command id='show e1_timeslot [line_nr] [ts_nr]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_timeslot' doc='Display information about a E1 timeslot' />
- <param name='[line_nr]' doc='E1 Line Number' />
- <param name='[ts_nr]' doc='E1 Timeslot Number' />
- </params>
- </command>
- <command id='show bts &lt;0-255&gt;'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='bts' doc='Display information about a BTS' />
- <param name='&lt;0-255&gt;' doc='BTS Number' />
- </params>
- </command>
- <command id='show trx [&lt;0-255&gt;] [&lt;0-255&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='trx' doc='Display information about a TRX' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- </params>
- </command>
- <command id='show timeslot [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='timeslot' doc='Display information about a TS' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- </params>
- </command>
- <command id='show lchan [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='lchan' doc='Display information about a logical channel' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- <param name='[&lt;0-7&gt;]' doc='Logical Channel Number' />
- </params>
- </command>
- <command id='show lchan summary [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='lchan' doc='Display information about a logical channel' />
- <param name='summary' doc='Short summary' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- <param name='[&lt;0-7&gt;]' doc='Logical Channel Number' />
- </params>
- </command>
- <command id='logging enable'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='enable' doc='Enables logging to this vty' />
- </params>
- </command>
- <command id='logging disable'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='disable' doc='Disables logging to this vty' />
- </params>
- </command>
- <command id='logging filter all (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='filter' doc='Filter log messages' />
- <param name='all' doc='Do you want to log all messages?' />
- <param name='0' doc='Only print messages matched by other filters' />
- <param name='1' doc='Bypass filter and print all messages' />
- </params>
- </command>
- <command id='logging color (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='color' doc='Configure color-printing for log messages' />
- <param name='0' doc='Don&apos;t use color for printing messages' />
- <param name='1' doc='Use color for printing messages' />
- </params>
- </command>
- <command id='logging timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp' />
- </params>
- </command>
- <command id='logging print extended-timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='extended-timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp with YYYYMMDDhhmmssnnn' />
- </params>
- </command>
- <command id='logging print category (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem name' />
- </params>
- </command>
- <command id='logging print category-hex (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category-hex' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem nr in hex (&apos;&lt;000b&gt;&apos;)' />
- </params>
- </command>
- <command id='logging print level (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='level' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the log level name' />
- </params>
- </command>
- <command id='logging print file (0|1|basename) [last]'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='file' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the source file and line' />
- <param name='basename' doc='Prefix each log message with the source file&apos;s basename (strip leading paths) and line' />
- <param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
- </params>
- </command>
- <command id='logging set-log-mask MASK'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='set-log-mask' doc='Set the logmask of this logging target' />
- <param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
- </params>
- </command>
- <command id='logging level (rsl|oml|rll|rr|meas|pag|l1c|l1p|dsp|pcu|ho|trx|loop|abis|rtp|sum|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='rsl' doc='A-bis Radio Siganlling Link (RSL)' />
- <param name='oml' doc='A-bis Network Management / O&amp;M (NM/OML)' />
- <param name='rll' doc='A-bis Radio Link Layer (RLL)' />
- <param name='rr' doc='Layer3 Radio Resource (RR)' />
- <param name='meas' doc='Radio Measurement Processing' />
- <param name='pag' doc='Paging Subsystem' />
- <param name='l1c' doc='Layer 1 Control (MPH)' />
- <param name='l1p' doc='Layer 1 Primitives (PH)' />
- <param name='dsp' doc='DSP Trace Messages' />
- <param name='pcu' doc='PCU interface' />
- <param name='ho' doc='Handover' />
- <param name='trx' doc='TRX interface' />
- <param name='loop' doc='Control loops' />
- <param name='abis' doc='A-bis Intput Subsystem' />
- <param name='rtp' doc='Realtime Transfer Protocol' />
- <param name='sum' doc='DSUM' />
- <param name='lglobal' doc='Library-internal global log family' />
- <param name='llapd' doc='LAPD in libosmogsm' />
- <param name='linp' doc='A-bis Intput Subsystem' />
- <param name='lmux' doc='A-bis B-Subchannel TRAU Frame Multiplex' />
- <param name='lmi' doc='A-bis Input Driver for Signalling' />
- <param name='lmib' doc='A-bis Input Driver for B-Channels (voice)' />
- <param name='lsms' doc='Layer3 Short Message Service (SMS)' />
- <param name='lctrl' doc='Control Interface' />
- <param name='lgtp' doc='GPRS GTP library' />
- <param name='lstats' doc='Statistics messages and logging' />
- <param name='lgsup' doc='Generic Subscriber Update Protocol' />
- <param name='loap' doc='Osmocom Authentication Protocol' />
- <param name='lss7' doc='libosmo-sigtran Signalling System 7' />
- <param name='lsccp' doc='libosmo-sigtran SCCP Implementation' />
- <param name='lsua' doc='libosmo-sigtran SCCP User Adaptation' />
- <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
- <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
- <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
- <param name='lrspro' doc='Remote SIM protocol' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level set-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='set-all' doc='Once-off set all categories to the given log level. There is no single command to take back these changes -- each category is set to the given level, period.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level force-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Globally force all logging categories to a specific level. This is released by the &apos;no logging level force-all&apos; command. Note: any &apos;logging level &lt;category&gt; &lt;level&gt;&apos; commands will have no visible effect after this, until the forced level is released.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='no logging level force-all'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Release any globally forced log level set with &apos;logging level force-all &lt;level&gt;&apos;' />
- </params>
- </command>
- <command id='show logging vty'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='logging' doc='Show current logging configuration' />
- <param name='vty' doc='Show current logging configuration for this vty' />
- </params>
- </command>
- <command id='show alarms'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='alarms' doc='Show current logging configuration' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH)'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- <param name='tree' doc='Display only a specific memory chunk' />
- <param name='ADDRESS' doc='Chunk address (e.g. 0xdeadbeef)' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- <param name='filter' doc='Filter chunks using regular expression' />
- <param name='REGEXP' doc='Regular expression' />
- </params>
- </command>
- <command id='show stats'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='stats' doc='Show statistical values' />
- </params>
- </command>
- <command id='show stats level (global|peer|subscriber)'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='stats' doc='Show statistical values' />
- <param name='level' doc='Set the maximum group level' />
- <param name='global' doc='Show global groups only' />
- <param name='peer' doc='Show global and network peer related groups' />
- <param name='subscriber' doc='Show global, peer, and subscriber groups' />
- </params>
- </command>
- <command id='show asciidoc counters'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='asciidoc' doc='Asciidoc generation' />
- <param name='counters' doc='Generate table of all registered counters' />
- </params>
- </command>
- <command id='show rate-counters'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='rate-counters' doc='Show all rate counters' />
- </params>
- </command>
- </node>
- <node id='enable'>
- <name>enable</name>
- <command id='disable'>
- <params>
- <param name='disable' doc='Turn off privileged mode command' />
- </params>
- </command>
- <command id='configure terminal'>
- <params>
- <param name='configure' doc='Configuration from vty interface' />
- <param name='terminal' doc='Configuration terminal' />
- </params>
- </command>
- <command id='copy running-config startup-config'>
- <params>
- <param name='copy' doc='Copy configuration' />
- <param name='running-config' doc='Copy running config to... ' />
- <param name='startup-config' doc='Copy running config to startup config (same as write file)' />
- </params>
- </command>
- <command id='show startup-config'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='startup-config' doc='Contentes of startup configuration' />
- </params>
- </command>
- <command id='show version'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='version' doc='Displays program version' />
- </params>
- </command>
- <command id='show online-help'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='online-help' doc='Online help' />
- </params>
- </command>
- <command id='terminal length &lt;0-512&gt;'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='length' doc='Set number of lines on a screen' />
- <param name='&lt;0-512&gt;' doc='Number of lines on screen (0 for no pausing)' />
- </params>
- </command>
- <command id='terminal no length'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='length' doc='Set number of lines on a screen' />
- </params>
- </command>
- <command id='who'>
- <params>
- <param name='who' doc='Display who is on vty' />
- </params>
- </command>
- <command id='show history'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='history' doc='Display the session command history' />
- </params>
- </command>
- <command id='terminal monitor'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='monitor' doc='Copy debug output to the current terminal line' />
- </params>
- </command>
- <command id='terminal no monitor'>
- <params>
- <param name='terminal' doc='Set terminal line parameters' />
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='monitor' doc='Copy debug output to the current terminal line' />
- </params>
- </command>
- <command id='show e1_driver'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_driver' doc='Display information about available E1 drivers' />
- </params>
- </command>
- <command id='show e1_line [line_nr] [stats]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_line' doc='Display information about a E1 line' />
- <param name='[line_nr]' doc='E1 Line Number' />
- <param name='[stats]' doc='Include statistics' />
- </params>
- </command>
- <command id='show e1_timeslot [line_nr] [ts_nr]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='e1_timeslot' doc='Display information about a E1 timeslot' />
- <param name='[line_nr]' doc='E1 Line Number' />
- <param name='[ts_nr]' doc='E1 Timeslot Number' />
- </params>
- </command>
- <command id='show bts &lt;0-255&gt;'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='bts' doc='Display information about a BTS' />
- <param name='&lt;0-255&gt;' doc='BTS Number' />
- </params>
- </command>
- <command id='show trx [&lt;0-255&gt;] [&lt;0-255&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='trx' doc='Display information about a TRX' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- </params>
- </command>
- <command id='show timeslot [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='timeslot' doc='Display information about a TS' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- </params>
- </command>
- <command id='show lchan [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='lchan' doc='Display information about a logical channel' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- <param name='[&lt;0-7&gt;]' doc='Logical Channel Number' />
- </params>
- </command>
- <command id='show lchan summary [&lt;0-255&gt;] [&lt;0-255&gt;] [&lt;0-7&gt;] [&lt;0-7&gt;]'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='lchan' doc='Display information about a logical channel' />
- <param name='summary' doc='Short summary' />
- <param name='[&lt;0-255&gt;]' doc='BTS Number' />
- <param name='[&lt;0-255&gt;]' doc='TRX Number' />
- <param name='[&lt;0-7&gt;]' doc='Timeslot Number' />
- <param name='[&lt;0-7&gt;]' doc='Logical Channel Number' />
- </params>
- </command>
- <command id='logging enable'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='enable' doc='Enables logging to this vty' />
- </params>
- </command>
- <command id='logging disable'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='disable' doc='Disables logging to this vty' />
- </params>
- </command>
- <command id='logging filter all (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='filter' doc='Filter log messages' />
- <param name='all' doc='Do you want to log all messages?' />
- <param name='0' doc='Only print messages matched by other filters' />
- <param name='1' doc='Bypass filter and print all messages' />
- </params>
- </command>
- <command id='logging color (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='color' doc='Configure color-printing for log messages' />
- <param name='0' doc='Don&apos;t use color for printing messages' />
- <param name='1' doc='Use color for printing messages' />
- </params>
- </command>
- <command id='logging timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp' />
- </params>
- </command>
- <command id='logging print extended-timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='extended-timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp with YYYYMMDDhhmmssnnn' />
- </params>
- </command>
- <command id='logging print category (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem name' />
- </params>
- </command>
- <command id='logging print category-hex (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category-hex' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem nr in hex (&apos;&lt;000b&gt;&apos;)' />
- </params>
- </command>
- <command id='logging print level (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='level' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the log level name' />
- </params>
- </command>
- <command id='logging print file (0|1|basename) [last]'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='file' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the source file and line' />
- <param name='basename' doc='Prefix each log message with the source file&apos;s basename (strip leading paths) and line' />
- <param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
- </params>
- </command>
- <command id='logging set-log-mask MASK'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='set-log-mask' doc='Set the logmask of this logging target' />
- <param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
- </params>
- </command>
- <command id='logging level (rsl|oml|rll|rr|meas|pag|l1c|l1p|dsp|pcu|ho|trx|loop|abis|rtp|sum|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='rsl' doc='A-bis Radio Siganlling Link (RSL)' />
- <param name='oml' doc='A-bis Network Management / O&amp;M (NM/OML)' />
- <param name='rll' doc='A-bis Radio Link Layer (RLL)' />
- <param name='rr' doc='Layer3 Radio Resource (RR)' />
- <param name='meas' doc='Radio Measurement Processing' />
- <param name='pag' doc='Paging Subsystem' />
- <param name='l1c' doc='Layer 1 Control (MPH)' />
- <param name='l1p' doc='Layer 1 Primitives (PH)' />
- <param name='dsp' doc='DSP Trace Messages' />
- <param name='pcu' doc='PCU interface' />
- <param name='ho' doc='Handover' />
- <param name='trx' doc='TRX interface' />
- <param name='loop' doc='Control loops' />
- <param name='abis' doc='A-bis Intput Subsystem' />
- <param name='rtp' doc='Realtime Transfer Protocol' />
- <param name='sum' doc='DSUM' />
- <param name='lglobal' doc='Library-internal global log family' />
- <param name='llapd' doc='LAPD in libosmogsm' />
- <param name='linp' doc='A-bis Intput Subsystem' />
- <param name='lmux' doc='A-bis B-Subchannel TRAU Frame Multiplex' />
- <param name='lmi' doc='A-bis Input Driver for Signalling' />
- <param name='lmib' doc='A-bis Input Driver for B-Channels (voice)' />
- <param name='lsms' doc='Layer3 Short Message Service (SMS)' />
- <param name='lctrl' doc='Control Interface' />
- <param name='lgtp' doc='GPRS GTP library' />
- <param name='lstats' doc='Statistics messages and logging' />
- <param name='lgsup' doc='Generic Subscriber Update Protocol' />
- <param name='loap' doc='Osmocom Authentication Protocol' />
- <param name='lss7' doc='libosmo-sigtran Signalling System 7' />
- <param name='lsccp' doc='libosmo-sigtran SCCP Implementation' />
- <param name='lsua' doc='libosmo-sigtran SCCP User Adaptation' />
- <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
- <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
- <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
- <param name='lrspro' doc='Remote SIM protocol' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level set-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='set-all' doc='Once-off set all categories to the given log level. There is no single command to take back these changes -- each category is set to the given level, period.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level force-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Globally force all logging categories to a specific level. This is released by the &apos;no logging level force-all&apos; command. Note: any &apos;logging level &lt;category&gt; &lt;level&gt;&apos; commands will have no visible effect after this, until the forced level is released.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='no logging level force-all'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Release any globally forced log level set with &apos;logging level force-all &lt;level&gt;&apos;' />
- </params>
- </command>
- <command id='show logging vty'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='logging' doc='Show current logging configuration' />
- <param name='vty' doc='Show current logging configuration for this vty' />
- </params>
- </command>
- <command id='show alarms'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='alarms' doc='Show current logging configuration' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH)'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- <param name='tree' doc='Display only a specific memory chunk' />
- <param name='ADDRESS' doc='Chunk address (e.g. 0xdeadbeef)' />
- </params>
- </command>
- <command id='show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='talloc-context' doc='Show talloc memory hierarchy' />
- <param name='application' doc='Application&apos;s context' />
- <param name='all' doc='All contexts, if NULL-context tracking is enabled' />
- <param name='full' doc='Display a full talloc memory hierarchy' />
- <param name='brief' doc='Display a brief talloc memory hierarchy' />
- <param name='DEPTH' doc='Specify required maximal depth value' />
- <param name='filter' doc='Filter chunks using regular expression' />
- <param name='REGEXP' doc='Regular expression' />
- </params>
- </command>
- <command id='show stats'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='stats' doc='Show statistical values' />
- </params>
- </command>
- <command id='show stats level (global|peer|subscriber)'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='stats' doc='Show statistical values' />
- <param name='level' doc='Set the maximum group level' />
- <param name='global' doc='Show global groups only' />
- <param name='peer' doc='Show global and network peer related groups' />
- <param name='subscriber' doc='Show global, peer, and subscriber groups' />
- </params>
- </command>
- <command id='show asciidoc counters'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='asciidoc' doc='Asciidoc generation' />
- <param name='counters' doc='Generate table of all registered counters' />
- </params>
- </command>
- <command id='show rate-counters'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='rate-counters' doc='Show all rate counters' />
- </params>
- </command>
- <command id='bts &lt;0-0&gt; trx &lt;0-0&gt; ts &lt;0-7&gt; lchan &lt;0-1&gt; rtp jitter-buffer &lt;0-10000&gt;'>
- <params>
- <param name='bts' doc='BTS related commands' />
- <param name='&lt;0-0&gt;' doc='BTS number' />
- <param name='trx' doc='TRX related commands' />
- <param name='&lt;0-0&gt;' doc='TRX number' />
- <param name='ts' doc='timeslot related commands' />
- <param name='&lt;0-7&gt;' doc='timeslot number' />
- <param name='lchan' doc='logical channel commands' />
- <param name='&lt;0-1&gt;' doc='logical channel number' />
- <param name='rtp' doc='RTP settings' />
- <param name='jitter-buffer' doc='Jitter buffer' />
- <param name='&lt;0-10000&gt;' doc='Size of jitter buffer in (ms)' />
- </params>
- </command>
- <command id='bts &lt;0-0&gt; trx &lt;0-0&gt; ts &lt;0-7&gt; lchan &lt;0-1&gt; loopback'>
- <params>
- <param name='bts' doc='BTS related commands' />
- <param name='&lt;0-0&gt;' doc='BTS number' />
- <param name='trx' doc='TRX related commands' />
- <param name='&lt;0-0&gt;' doc='TRX number' />
- <param name='ts' doc='timeslot related commands' />
- <param name='&lt;0-7&gt;' doc='timeslot number' />
- <param name='lchan' doc='logical channel commands' />
- <param name='&lt;0-1&gt;' doc='logical channel number' />
- <param name='loopback' doc='Set loopback' />
- </params>
- </command>
- <command id='no bts &lt;0-0&gt; trx &lt;0-0&gt; ts &lt;0-7&gt; lchan &lt;0-1&gt; loopback'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='bts' doc='BTS related commands' />
- <param name='&lt;0-0&gt;' doc='BTS number' />
- <param name='trx' doc='TRX related commands' />
- <param name='&lt;0-0&gt;' doc='TRX number' />
- <param name='ts' doc='timeslot related commands' />
- <param name='&lt;0-7&gt;' doc='timeslot number' />
- <param name='lchan' doc='logical channel commands' />
- <param name='&lt;0-1&gt;' doc='logical channel number' />
- <param name='loopback' doc='Set loopback' />
- </params>
- </command>
- </node>
- <node id='config'>
- <name>config</name>
- <command id='hostname WORD'>
- <params>
- <param name='hostname' doc='Set system&apos;s network name' />
- <param name='WORD' doc='This system&apos;s network name' />
- </params>
- </command>
- <command id='no hostname [HOSTNAME]'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='hostname' doc='Reset system&apos;s network name' />
- <param name='[HOSTNAME]' doc='Host name of this router' />
- </params>
- </command>
- <command id='password (8|) WORD'>
- <params>
- <param name='password' doc='Assign the terminal connection password' />
- <param name='8' doc='Specifies a HIDDEN password will follow' />
- <param name='' doc='dummy string ' />
- <param name='WORD' doc='The HIDDEN line password string' />
- </params>
- </command>
- <command id='password LINE'>
- <params>
- <param name='password' doc='Assign the terminal connection password' />
- <param name='LINE' doc='The UNENCRYPTED (cleartext) line password' />
- </params>
- </command>
- <command id='enable password (8|) WORD'>
- <params>
- <param name='enable' doc='Modify enable password parameters' />
- <param name='password' doc='Assign the privileged level password' />
- <param name='8' doc='Specifies a HIDDEN password will follow' />
- <param name='' doc='dummy string ' />
- <param name='WORD' doc='The HIDDEN &apos;enable&apos; password string' />
- </params>
- </command>
- <command id='enable password LINE'>
- <params>
- <param name='enable' doc='Modify enable password parameters' />
- <param name='password' doc='Assign the privileged level password' />
- <param name='LINE' doc='The UNENCRYPTED (cleartext) &apos;enable&apos; password' />
- </params>
- </command>
- <command id='no enable password'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='enable' doc='Modify enable password parameters' />
- <param name='password' doc='Assign the privileged level password' />
- </params>
- </command>
- <command id='banner motd default'>
- <params>
- <param name='banner' doc='Set banner string' />
- <param name='motd' doc='Strings for motd' />
- <param name='default' doc='Default string' />
- </params>
- </command>
- <command id='banner motd file [FILE]'>
- <params>
- <param name='banner' doc='Set banner' />
- <param name='motd' doc='Banner for motd' />
- <param name='file' doc='Banner from a file' />
- <param name='[FILE]' doc='Filename' />
- </params>
- </command>
- <command id='no banner motd'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='banner' doc='Set banner string' />
- <param name='motd' doc='Strings for motd' />
- </params>
- </command>
- <command id='service terminal-length &lt;0-512&gt;'>
- <params>
- <param name='service' doc='Set up miscellaneous service' />
- <param name='terminal-length' doc='System wide terminal length configuration' />
- <param name='&lt;0-512&gt;' doc='Number of lines of VTY (0 means no line control)' />
- </params>
- </command>
- <command id='no service terminal-length [&lt;0-512&gt;]'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='service' doc='Set up miscellaneous service' />
- <param name='terminal-length' doc='System wide terminal length configuration' />
- <param name='[&lt;0-512&gt;]' doc='Number of lines of VTY (0 means no line control)' />
- </params>
- </command>
- <command id='line vty'>
- <params>
- <param name='line' doc='Configure a terminal line' />
- <param name='vty' doc='Virtual terminal' />
- </params>
- </command>
- <command id='service advanced-vty'>
- <params>
- <param name='service' doc='Set up miscellaneous service' />
- <param name='advanced-vty' doc='Enable advanced mode vty interface' />
- </params>
- </command>
- <command id='no service advanced-vty'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='service' doc='Set up miscellaneous service' />
- <param name='advanced-vty' doc='Enable advanced mode vty interface' />
- </params>
- </command>
- <command id='show history'>
- <params>
- <param name='show' doc='Show running system information' />
- <param name='history' doc='Display the session command history' />
- </params>
- </command>
- <command id='ctrl'>
- <params>
- <param name='ctrl' doc='Configure the Control Interface' />
- </params>
- </command>
- <command id='e1_input'>
- <params>
- <param name='e1_input' doc='Configure E1/T1/J1 TDM input' />
- </params>
- </command>
- <command id='log stderr'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='stderr' doc='Logging via STDERR of the process' />
- </params>
- </command>
- <command id='no log stderr'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='log' doc='Configure logging sub-system' />
- <param name='stderr' doc='Logging via STDERR of the process' />
- </params>
- </command>
- <command id='log file .FILENAME'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='file' doc='Logging to text file' />
- <param name='.FILENAME' doc='Filename' />
- </params>
- </command>
- <command id='no log file .FILENAME'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='log' doc='Configure logging sub-system' />
- <param name='file' doc='Logging to text file' />
- <param name='.FILENAME' doc='Filename' />
- </params>
- </command>
- <command id='log alarms &lt;2-32700&gt;'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='alarms' doc='Logging alarms to osmo_strrb' />
- <param name='&lt;2-32700&gt;' doc='Maximum number of messages to log' />
- </params>
- </command>
- <command id='no log alarms'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='log' doc='Configure logging sub-system' />
- <param name='alarms' doc='Logging alarms to osmo_strrb' />
- </params>
- </command>
- <command id='log syslog (authpriv|cron|daemon|ftp|lpr|mail|news|user|uucp)'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='syslog' doc='Logging via syslog' />
- <param name='authpriv' doc='Security/authorization messages facility' />
- <param name='cron' doc='Clock daemon (cron/at) facility' />
- <param name='daemon' doc='General system daemon facility' />
- <param name='ftp' doc='Ftp daemon facility' />
- <param name='lpr' doc='Line printer facility' />
- <param name='mail' doc='Mail facility' />
- <param name='news' doc='News facility' />
- <param name='user' doc='Generic facility' />
- <param name='uucp' doc='UUCP facility' />
- </params>
- </command>
- <command id='log syslog local &lt;0-7&gt;'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='syslog' doc='Logging via syslog' />
- <param name='local' doc='Syslog LOCAL facility' />
- <param name='&lt;0-7&gt;' doc='Local facility number' />
- </params>
- </command>
- <command id='no log syslog'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='log' doc='Configure logging sub-system' />
- <param name='syslog' doc='Logging via syslog' />
- </params>
- </command>
- <command id='log gsmtap [HOSTNAME]'>
- <params>
- <param name='log' doc='Configure logging sub-system' />
- <param name='gsmtap' doc='Logging via GSMTAP' />
- <param name='[HOSTNAME]' doc='Host name to send the GSMTAP logging to (UDP port 4729)' />
- </params>
- </command>
- <command id='stats reporter statsd'>
- <params>
- <param name='stats' doc='Configure stats sub-system' />
- <param name='reporter' doc='Configure a stats reporter' />
- <param name='statsd' doc='Report to a STATSD server' />
- </params>
- </command>
- <command id='no stats reporter statsd'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='stats' doc='Configure stats sub-system' />
- <param name='reporter' doc='Configure a stats reporter' />
- <param name='statsd' doc='Report to a STATSD server' />
- </params>
- </command>
- <command id='stats reporter log'>
- <params>
- <param name='stats' doc='Configure stats sub-system' />
- <param name='reporter' doc='Configure a stats reporter' />
- <param name='log' doc='Report to the logger' />
- </params>
- </command>
- <command id='no stats reporter log'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='stats' doc='Configure stats sub-system' />
- <param name='reporter' doc='Configure a stats reporter' />
- <param name='log' doc='Report to the logger' />
- </params>
- </command>
- <command id='stats interval &lt;1-65535&gt;'>
- <params>
- <param name='stats' doc='Configure stats sub-system' />
- <param name='interval' doc='Set the reporting interval' />
- <param name='&lt;1-65535&gt;' doc='Interval in seconds' />
- </params>
- </command>
- <command id='bts BTS_NR'>
- <params>
- <param name='bts' doc='Select a BTS to configure' />
- <param name='BTS_NR' doc='BTS Number' />
- </params>
- </command>
- <command id='vty telnet-port &lt;0-65535&gt;'>
- <params>
- <param name='vty' doc='Configure the VTY' />
- <param name='telnet-port' doc='Set the VTY telnet port' />
- <param name='&lt;0-65535&gt;' doc='TCP Port number' />
- </params>
- </command>
- <command id='phy &lt;0-255&gt;'>
- <params>
- <param name='phy' doc='Select a PHY to configure' />
- <param name='&lt;0-255&gt;' doc='PHY number' />
- </params>
- </command>
- </node>
- <node id='config-log'>
- <name>config-log</name>
- <command id='logging filter all (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='filter' doc='Filter log messages' />
- <param name='all' doc='Do you want to log all messages?' />
- <param name='0' doc='Only print messages matched by other filters' />
- <param name='1' doc='Bypass filter and print all messages' />
- </params>
- </command>
- <command id='logging color (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='color' doc='Configure color-printing for log messages' />
- <param name='0' doc='Don&apos;t use color for printing messages' />
- <param name='1' doc='Use color for printing messages' />
- </params>
- </command>
- <command id='logging timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp' />
- </params>
- </command>
- <command id='logging print extended-timestamp (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='extended-timestamp' doc='Configure log message timestamping' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with current timestamp with YYYYMMDDhhmmssnnn' />
- </params>
- </command>
- <command id='logging print category (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem name' />
- </params>
- </command>
- <command id='logging print category-hex (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='category-hex' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with category/subsystem nr in hex (&apos;&lt;000b&gt;&apos;)' />
- </params>
- </command>
- <command id='logging print level (0|1)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='level' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the log level name' />
- </params>
- </command>
- <command id='logging print file (0|1|basename) [last]'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='print' doc='Log output settings' />
- <param name='file' doc='Configure log message' />
- <param name='0' doc='Don&apos;t prefix each log message' />
- <param name='1' doc='Prefix each log message with the source file and line' />
- <param name='basename' doc='Prefix each log message with the source file&apos;s basename (strip leading paths) and line' />
- <param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
- </params>
- </command>
- <command id='logging level (rsl|oml|rll|rr|meas|pag|l1c|l1p|dsp|pcu|ho|trx|loop|abis|rtp|sum|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='rsl' doc='A-bis Radio Siganlling Link (RSL)' />
- <param name='oml' doc='A-bis Network Management / O&amp;M (NM/OML)' />
- <param name='rll' doc='A-bis Radio Link Layer (RLL)' />
- <param name='rr' doc='Layer3 Radio Resource (RR)' />
- <param name='meas' doc='Radio Measurement Processing' />
- <param name='pag' doc='Paging Subsystem' />
- <param name='l1c' doc='Layer 1 Control (MPH)' />
- <param name='l1p' doc='Layer 1 Primitives (PH)' />
- <param name='dsp' doc='DSP Trace Messages' />
- <param name='pcu' doc='PCU interface' />
- <param name='ho' doc='Handover' />
- <param name='trx' doc='TRX interface' />
- <param name='loop' doc='Control loops' />
- <param name='abis' doc='A-bis Intput Subsystem' />
- <param name='rtp' doc='Realtime Transfer Protocol' />
- <param name='sum' doc='DSUM' />
- <param name='lglobal' doc='Library-internal global log family' />
- <param name='llapd' doc='LAPD in libosmogsm' />
- <param name='linp' doc='A-bis Intput Subsystem' />
- <param name='lmux' doc='A-bis B-Subchannel TRAU Frame Multiplex' />
- <param name='lmi' doc='A-bis Input Driver for Signalling' />
- <param name='lmib' doc='A-bis Input Driver for B-Channels (voice)' />
- <param name='lsms' doc='Layer3 Short Message Service (SMS)' />
- <param name='lctrl' doc='Control Interface' />
- <param name='lgtp' doc='GPRS GTP library' />
- <param name='lstats' doc='Statistics messages and logging' />
- <param name='lgsup' doc='Generic Subscriber Update Protocol' />
- <param name='loap' doc='Osmocom Authentication Protocol' />
- <param name='lss7' doc='libosmo-sigtran Signalling System 7' />
- <param name='lsccp' doc='libosmo-sigtran SCCP Implementation' />
- <param name='lsua' doc='libosmo-sigtran SCCP User Adaptation' />
- <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
- <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
- <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
- <param name='lrspro' doc='Remote SIM protocol' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level set-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='set-all' doc='Once-off set all categories to the given log level. There is no single command to take back these changes -- each category is set to the given level, period.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='logging level force-all (debug|info|notice|error|fatal)'>
- <params>
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Globally force all logging categories to a specific level. This is released by the &apos;no logging level force-all&apos; command. Note: any &apos;logging level &lt;category&gt; &lt;level&gt;&apos; commands will have no visible effect after this, until the forced level is released.' />
- <param name='debug' doc='Log debug messages and higher levels' />
- <param name='info' doc='Log informational messages and higher levels' />
- <param name='notice' doc='Log noticeable messages and higher levels' />
- <param name='error' doc='Log error messages and higher levels' />
- <param name='fatal' doc='Log only fatal messages' />
- </params>
- </command>
- <command id='no logging level force-all'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='logging' doc='Configure logging' />
- <param name='level' doc='Set the log level for a specified category' />
- <param name='force-all' doc='Release any globally forced log level set with &apos;logging level force-all &lt;level&gt;&apos;' />
- </params>
- </command>
- </node>
- <node id='config-stats'>
- <name>config-stats</name>
- <command id='local-ip ADDR'>
- <params>
- <param name='local-ip' doc='Set the IP address to which we bind locally' />
- <param name='ADDR' doc='IP Address' />
- </params>
- </command>
- <command id='no local-ip'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='local-ip' doc='Set the IP address to which we bind locally' />
- </params>
- </command>
- <command id='remote-ip ADDR'>
- <params>
- <param name='remote-ip' doc='Set the remote IP address to which we connect' />
- <param name='ADDR' doc='IP Address' />
- </params>
- </command>
- <command id='remote-port &lt;1-65535&gt;'>
- <params>
- <param name='remote-port' doc='Set the remote port to which we connect' />
- <param name='&lt;1-65535&gt;' doc='Remote port number' />
- </params>
- </command>
- <command id='mtu &lt;100-65535&gt;'>
- <params>
- <param name='mtu' doc='Set the maximum packet size' />
- <param name='&lt;100-65535&gt;' doc='Size in byte' />
- </params>
- </command>
- <command id='no mtu'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='mtu' doc='Set the maximum packet size' />
- </params>
- </command>
- <command id='prefix PREFIX'>
- <params>
- <param name='prefix' doc='Set the item name prefix' />
- <param name='PREFIX' doc='The prefix string' />
- </params>
- </command>
- <command id='no prefix'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='prefix' doc='Set the item name prefix' />
- </params>
- </command>
- <command id='level (global|peer|subscriber)'>
- <params>
- <param name='level' doc='Set the maximum group level' />
- <param name='global' doc='Report global groups only' />
- <param name='peer' doc='Report global and network peer related groups' />
- <param name='subscriber' doc='Report global, peer, and subscriber groups' />
- </params>
- </command>
- <command id='enable'>
- <params>
- <param name='enable' doc='Enable the reporter' />
- </params>
- </command>
- <command id='disable'>
- <params>
- <param name='disable' doc='Disable the reporter' />
- </params>
- </command>
- </node>
- <node id='config-line'>
- <name>config-line</name>
- <command id='login'>
- <params>
- <param name='login' doc='Enable password checking' />
- </params>
- </command>
- <command id='no login'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='login' doc='Enable password checking' />
- </params>
- </command>
- <command id='bind A.B.C.D [&lt;0-65535&gt;]'>
- <params>
- <param name='bind' doc='Accept VTY telnet connections on local interface' />
- <param name='A.B.C.D' doc='Local interface IP address (default: 127.0.0.1)' />
- <param name='[&lt;0-65535&gt;]' doc='Local TCP port number' />
- </params>
- </command>
- </node>
- <node id='config-e1_input'>
- <name>config-e1_input</name>
- <command id='e1_line &lt;0-255&gt; driver (misdn|misdn_lapd|dahdi|ipa|unixsocket)'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='driver' doc='Set driver for this line' />
- <param name='misdn' doc='mISDN supported E1 Card (kernel LAPD)' />
- <param name='misdn_lapd' doc='mISDN supported E1 Card (userspace LAPD)' />
- <param name='dahdi' doc='DAHDI supported E1/T1/J1 Card' />
- <param name='ipa' doc='IPA TCP/IP input' />
- <param name='unixsocket' doc='HSL TCP/IP input' />
- </params>
- </command>
- <command id='e1_line &lt;0-255&gt; port &lt;0-255&gt;'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='port' doc='Set physical port/span/card number' />
- <param name='&lt;0-255&gt;' doc='E1/T1 Port/Span/Card number' />
- </params>
- </command>
- <command id='e1_line &lt;0-255&gt; socket .SOCKET'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='socket' doc='Set socket path for unixsocket' />
- <param name='.SOCKET' doc='socket path' />
- </params>
- </command>
- <command id='e1_line &lt;0-255&gt; name .LINE'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='name' doc='Set name for this line' />
- <param name='.LINE' doc='Human readable name' />
- </params>
- </command>
- <command id='e1_line &lt;0-255&gt; keepalive'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='keepalive' doc='Enable keep-alive probing' />
- </params>
- </command>
- <command id='e1_line &lt;0-255&gt; keepalive &lt;1-300&gt; &lt;1-20&gt; &lt;1-300&gt;'>
- <params>
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='keepalive' doc='Enable keep-alive probing' />
- <param name='&lt;1-300&gt;' doc='Idle interval in seconds before probes are sent' />
- <param name='&lt;1-20&gt;' doc='Number of probes to sent' />
- <param name='&lt;1-300&gt;' doc='Delay between probe packets in seconds' />
- </params>
- </command>
- <command id='no e1_line &lt;0-255&gt; keepalive'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='e1_line' doc='Configure E1/T1/J1 Line' />
- <param name='&lt;0-255&gt;' doc='Line Number' />
- <param name='keepalive' doc='Enable keep-alive probing' />
- </params>
- </command>
- <command id='ipa bind A.B.C.D'>
- <params>
- <param name='ipa' doc='ipa driver config' />
- <param name='bind' doc='Set ipa local bind address' />
- <param name='A.B.C.D' doc='Listen on this IP address (default 0.0.0.0)' />
- </params>
- </command>
- </node>
- <node id='config-ctrl'>
- <name>config-ctrl</name>
- <command id='bind A.B.C.D'>
- <params>
- <param name='bind' doc='Set bind address to listen for Control connections' />
- <param name='A.B.C.D' doc='Local IP address (default 127.0.0.1)' />
- </params>
- </command>
- </node>
- <node id='phy'>
- <name>phy</name>
- <command id='instance &lt;0-255&gt;'>
- <params>
- <param name='instance' doc='Select a PHY instance to configure' />
- <param name='&lt;0-255&gt;' doc='PHY Instance number' />
- </params>
- </command>
- <command id='no instance &lt;0-255&gt;'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='instance' doc='Select a PHY instance to remove' />
- <param name='&lt;0-255&gt;' doc='PHY Instance number' />
- </params>
- </command>
- <command id='virtual-um ms-multicast-group GROUP'>
- <params>
- <param name='virtual-um' doc='Virtual Um layer' />
- <param name='ms-multicast-group' doc='Configure the MS multicast group' />
- <param name='GROUP' doc='(null)' />
- </params>
- </command>
- <command id='virtual-um ms-udp-port &lt;0-65535&gt;'>
- <params>
- <param name='virtual-um' doc='Virtual Um layer' />
- <param name='ms-udp-port' doc='Configure the MS UDP port' />
- <param name='&lt;0-65535&gt;' doc='(null)' />
- </params>
- </command>
- <command id='virtual-um bts-multicast-group GROUP'>
- <params>
- <param name='virtual-um' doc='Virtual Um layer' />
- <param name='bts-multicast-group' doc='Configure the BTS multicast group' />
- <param name='GROUP' doc='(null)' />
- </params>
- </command>
- <command id='virtual-um bts-udp-port &lt;0-65535&gt;'>
- <params>
- <param name='virtual-um' doc='Virtual Um layer' />
- <param name='bts-udp-port' doc='Configure the BTS UDP port' />
- <param name='&lt;0-65535&gt;' doc='(null)' />
- </params>
- </command>
- <command id='virtual-um net-device NETDEV'>
- <params>
- <param name='virtual-um' doc='Virtual Um layer' />
- <param name='net-device' doc='Configure the network device' />
- <param name='NETDEV' doc='(null)' />
- </params>
- </command>
- </node>
- <node id='phy-inst'>
- <name>phy-inst</name>
- </node>
- <node id='bts'>
- <name>bts</name>
- <command id='ipa unit-id &lt;0-65534&gt; &lt;0-255&gt;'>
- <params>
- <param name='ipa' doc='ip.access RSL commands' />
- <param name='unit-id' doc='Set the Unit ID of this BTS' />
- <param name='&lt;0-65534&gt;' doc='Site ID' />
- <param name='&lt;0-255&gt;' doc='Unit ID' />
- </params>
- </command>
- <command id='oml remote-ip A.B.C.D'>
- <params>
- <param name='oml' doc='OML Parameters' />
- <param name='remote-ip' doc='OML IP Address' />
- <param name='A.B.C.D' doc='OML IP Address' />
- </params>
- </command>
- <command id='rtp jitter-buffer &lt;0-10000&gt; [adaptive]'>
- <params>
- <param name='rtp' doc='RTP parameters' />
- <param name='jitter-buffer' doc='RTP jitter buffer' />
- <param name='&lt;0-10000&gt;' doc='jitter buffer in ms' />
- <param name='[adaptive]' doc='(null)' />
- </params>
- </command>
- <command id='rtp port-range &lt;1-65534&gt; &lt;1-65534&gt;'>
- <params>
- <param name='rtp' doc='RTP parameters' />
- <param name='port-range' doc='Range of local ports to use for RTP/RTCP traffic' />
- <param name='&lt;1-65534&gt;' doc='(null)' />
- <param name='&lt;1-65534&gt;' doc='(null)' />
- </params>
- </command>
- <command id='band (450|GSM450|480|GSM480|750|GSM750|810|GSM810|850|GSM850|900|GSM900|1800|DCS1800|1900|PCS1900)'>
- <params>
- <param name='band' doc='Set the frequency band of this BTS' />
- <param name='450' doc='Alias for GSM450' />
- <param name='GSM450' doc='450Mhz' />
- <param name='480' doc='Alias for GSM480' />
- <param name='GSM480' doc='480Mhz' />
- <param name='750' doc='Alias for GSM750' />
- <param name='GSM750' doc='750Mhz' />
- <param name='810' doc='Alias for GSM810' />
- <param name='GSM810' doc='810Mhz' />
- <param name='850' doc='Alias for GSM850' />
- <param name='GSM850' doc='850Mhz' />
- <param name='900' doc='Alias for GSM900' />
- <param name='GSM900' doc='900Mhz' />
- <param name='1800' doc='Alias for DCS1800' />
- <param name='DCS1800' doc='1800Mhz' />
- <param name='1900' doc='Alias for PCS1900' />
- <param name='PCS1900' doc='1900Mhz' />
- </params>
- </command>
- <command id='description .TEXT'>
- <params>
- <param name='description' doc='Save human-readable description of the object' />
- <param name='.TEXT' doc='Text until the end of the line' />
- </params>
- </command>
- <command id='no description'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='description' doc='Remove description of the object' />
- </params>
- </command>
- <command id='paging queue-size &lt;1-1024&gt;'>
- <params>
- <param name='paging' doc='Paging related parameters' />
- <param name='queue-size' doc='Maximum length of BTS-internal paging queue' />
- <param name='&lt;1-1024&gt;' doc='Maximum length of BTS-internal paging queue' />
- </params>
- </command>
- <command id='paging lifetime &lt;0-60&gt;'>
- <params>
- <param name='paging' doc='Paging related parameters' />
- <param name='lifetime' doc='Maximum lifetime of a paging record' />
- <param name='&lt;0-60&gt;' doc='Maximum lifetime of a paging record (secods)' />
- </params>
- </command>
- <command id='agch-queue-mgmt default'>
- <params>
- <param name='agch-queue-mgmt' doc='AGCH queue mgmt' />
- <param name='default' doc='Reset clean parameters to default values' />
- </params>
- </command>
- <command id='agch-queue-mgmt threshold &lt;0-100&gt; low &lt;0-100&gt; high &lt;0-100000&gt;'>
- <params>
- <param name='agch-queue-mgmt' doc='AGCH queue mgmt' />
- <param name='threshold' doc='Threshold to start cleanup' />
- <param name='&lt;0-100&gt;' doc='in %% of the maximum queue length' />
- <param name='low' doc='Low water mark for cleanup' />
- <param name='&lt;0-100&gt;' doc='in %% of the maximum queue length' />
- <param name='high' doc='High water mark for cleanup' />
- <param name='&lt;0-100000&gt;' doc='in %% of the maximum queue length' />
- </params>
- </command>
- <command id='uplink-power-target &lt;-110-0&gt;'>
- <params>
- <param name='uplink-power-target' doc='Set the nominal target Rx Level for uplink power control loop' />
- <param name='&lt;-110-0&gt;' doc='Target uplink Rx level in dBm' />
- </params>
- </command>
- <command id='min-qual-rach &lt;-100-100&gt;'>
- <params>
- <param name='min-qual-rach' doc='Set the minimum link quality level of Access Bursts to be accepted' />
- <param name='&lt;-100-100&gt;' doc='C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)' />
- </params>
- </command>
- <command id='min-qual-norm &lt;-100-100&gt;'>
- <params>
- <param name='min-qual-norm' doc='Set the minimum link quality level of Normal Bursts to be accepted' />
- <param name='&lt;-100-100&gt;' doc='C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)' />
- </params>
- </command>
- <command id='max-ber10k-rach &lt;0-10000&gt;'>
- <params>
- <param name='max-ber10k-rach' doc='Set the maximum BER for valid RACH requests' />
- <param name='&lt;0-10000&gt;' doc='BER in 1/10000 units (0=no BER; 100=1% BER)' />
- </params>
- </command>
- <command id='pcu-socket PATH'>
- <params>
- <param name='pcu-socket' doc='Configure the PCU socket file/path name' />
- <param name='PATH' doc='(null)' />
- </params>
- </command>
- <command id='supp-meas-info toa256'>
- <params>
- <param name='supp-meas-info' doc='Configure the RSL Supplementary Measurement Info' />
- <param name='toa256' doc='Report the TOA in 1/256th symbol periods' />
- </params>
- </command>
- <command id='no supp-meas-info toa256'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='supp-meas-info' doc='Configure the RSL Supplementary Measurement Info' />
- <param name='toa256' doc='Report the TOA in 1/256th symbol periods' />
- </params>
- </command>
- <command id='smscb queue-max-length &lt;1-60&gt;'>
- <params>
- <param name='smscb' doc='Maximum queue length for SMSCB (CBCH) queue. In count of messages/pages (Default: 15)' />
- <param name='queue-max-length' doc='(null)' />
- <param name='&lt;1-60&gt;' doc='(null)' />
- </params>
- </command>
- <command id='smscb queue-target-length &lt;1-30&gt;'>
- <params>
- <param name='smscb' doc='Target queue length for SMSCB (CBCH) queue. In count of messages/pages (Default: 2)' />
- <param name='queue-target-length' doc='(null)' />
- <param name='&lt;1-30&gt;' doc='(null)' />
- </params>
- </command>
- <command id='smscb queue-hysteresis &lt;0-30&gt;'>
- <params>
- <param name='smscb' doc='Hysteresis for SMSCB (CBCH) queue. In count of messages/pages (Default: 2)' />
- <param name='queue-hysteresis' doc='(null)' />
- <param name='&lt;0-30&gt;' doc='(null)' />
- </params>
- </command>
- <command id='gsmtap-sapi (bcch|ccch|rach|agch|pch|sdcch|tch/f|tch/h|pacch|pdtch|ptcch|cbch|sacch)'>
- <params>
- <param name='gsmtap-sapi' doc='GSMTAP SAPI' />
- <param name='bcch' doc='BCCH' />
- <param name='ccch' doc='CCCH' />
- <param name='rach' doc='RACH' />
- <param name='agch' doc='AGCH' />
- <param name='pch' doc='PCH' />
- <param name='sdcch' doc='SDCCH' />
- <param name='tch/f' doc='TCH/F' />
- <param name='tch/h' doc='TCH/H' />
- <param name='pacch' doc='PACCH' />
- <param name='pdtch' doc='PDTCH' />
- <param name='ptcch' doc='PTCCH' />
- <param name='cbch' doc='CBCH' />
- <param name='sacch' doc='SACCH' />
- </params>
- </command>
- <command id='no gsmtap-sapi (bcch|ccch|rach|agch|pch|sdcch|tch/f|tch/h|pacch|pdtch|ptcch|cbch|sacch)'>
- <params>
- <param name='no' doc='Negate a command or set its defaults' />
- <param name='gsmtap-sapi' doc='GSMTAP SAPI' />
- <param name='bcch' doc='BCCH' />
- <param name='ccch' doc='CCCH' />
- <param name='rach' doc='RACH' />
- <param name='agch' doc='AGCH' />
- <param name='pch' doc='PCH' />
- <param name='sdcch' doc='SDCCH' />
- <param name='tch/f' doc='TCH/F' />
- <param name='tch/h' doc='TCH/H' />
- <param name='pacch' doc='PACCH' />
- <param name='pdtch' doc='PDTCH' />
- <param name='ptcch' doc='PTCCH' />
- <param name='cbch' doc='CBCH' />
- <param name='sacch' doc='SACCH' />
- </params>
- </command>
- <command id='trx &lt;0-254&gt;'>
- <params>
- <param name='trx' doc='Select a TRX to configure' />
- <param name='&lt;0-254&gt;' doc='TRX number' />
- </params>
- </command>
- </node>
- <node id='trx'>
- <name>trx</name>
- <command id='user-gain &lt;-100000-100000&gt; (dB|mdB)'>
- <params>
- <param name='user-gain' doc='Inform BTS about additional, user-provided gain or attenuation at TRX output' />
- <param name='&lt;-100000-100000&gt;' doc='Value of user-provided external gain(+)/attenuation(-)' />
- <param name='dB' doc='Unit is dB (decibels)' />
- <param name='mdB' doc='Unit is mdB (milli-decibels, or rather 1/10000 bel)' />
- </params>
- </command>
- <command id='power-ramp max-initial &lt;0-100000&gt; (dBm|mdBm)'>
- <params>
- <param name='power-ramp' doc='Power-Ramp settingsMaximum initial power' />
- <param name='max-initial' doc='Value' />
- <param name='&lt;0-100000&gt;' doc='Unit is dB (decibels)' />
- <param name='dBm' doc='Unit is mdB (milli-decibels, or rather 1/10000 bel)' />
- <param name='mdBm' doc='(null)' />
- </params>
- </command>
- <command id='power-ramp step-size &lt;1-100000&gt; (dB|mdB)'>
- <params>
- <param name='power-ramp' doc='Power-Ramp settingsPower increase by step' />
- <param name='step-size' doc='Step size' />
- <param name='&lt;1-100000&gt;' doc='Unit is dB (decibels)' />
- <param name='dB' doc='Unit is mdB (milli-decibels, or rather 1/10000 bel)' />
- <param name='mdB' doc='(null)' />
- </params>
- </command>
- <command id='power-ramp step-interval &lt;1-100&gt;'>
- <params>
- <param name='power-ramp' doc='Power-Ramp settingsPower increase by step' />
- <param name='step-interval' doc='Step time in seconds' />
- <param name='&lt;1-100&gt;' doc='(null)' />
- </params>
- </command>
- <command id='ms-power-control (dsp|osmo)'>
- <params>
- <param name='ms-power-control' doc='Mobile Station Power Level Control (change requires restart)' />
- <param name='dsp' doc='Handled by DSP' />
- <param name='osmo' doc='Handled by OsmoBTS' />
- </params>
- </command>
- <command id='phy &lt;0-255&gt; instance &lt;0-255&gt;'>
- <params>
- <param name='phy' doc='Configure PHY Link+Instance for this TRX' />
- <param name='&lt;0-255&gt;' doc='PHY Link number' />
- <param name='instance' doc='PHY instance' />
- <param name='&lt;0-255&gt;' doc='PHY Instance number' />
- </params>
- </command>
- </node>
-</vtydoc>
diff --git a/doc/manuals/osmobts-vty-reference.xml b/doc/manuals/vty/osmobts-vty-reference.xml
index b7c8a596..b62f1d69 100644
--- a/doc/manuals/osmobts-vty-reference.xml
+++ b/doc/manuals/vty/osmobts-vty-reference.xml
@@ -6,24 +6,25 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
-<!ENTITY sections-vty SYSTEM "generated/docbook_vty.xml" >
+<!ENTITY sections-vty SYSTEM "@@GENERATED@@" >
]>
<book>
<info>
<revhistory>
<revision>
- <revnumber>v1</revnumber>
- <date>13th October 2016</date>
- <authorinitials>hw</authorinitials>
- <revremark>Initial</revremark>
+ <revnumber>v2</revnumber>
+ <date>@@REV_DATE@@</date>
+ <authorinitials>s.f.m.c.</authorinitials>
+ <revremark>Automatic build (@@REV_NUMBER@@)</revremark>
</revision>
</revhistory>
<title>OsmoBTS VTY Reference</title>
+ <subtitle>@@VARIANT@@</subtitle>
<copyright>
- <year>2016</year>
+ <year>@@CR_YEAR@@</year>
</copyright>
<legalnotice>
diff --git a/doc/startup.txt b/doc/startup.txt
index 50766e48..46c526a7 100644
--- a/doc/startup.txt
+++ b/doc/startup.txt
@@ -21,13 +21,12 @@ The start-up procedure of OsmoBTS can be described as follows:
| 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 | telnet_init_default() | Initialization of telnet interface
+| common | pcu_sock_init() | Initialization 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
diff --git a/doc/trx_sched_tch.txt b/doc/trx_sched_tch.txt
new file mode 100644
index 00000000..f8c79ffa
--- /dev/null
+++ b/doc/trx_sched_tch.txt
@@ -0,0 +1,98 @@
+== rx_tchf_fn(): TCH/FS, TCH/EFS, TCH/AFS, TCH/F2.4, and FACCH/F
+
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | | | | | | | | | | | | | a | b | c | d | Rx bid={0,1,2,3}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | Rx bid={0,1,2,3}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
+ |
+ |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
+ | |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
+ @ decoding from here
+
+
+== rx_tchf_fn(): TCH/F14.4, TCH/F9.6, TCH/F4.8
+
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | | | | | | | | | | | | | a | b | c | d | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | Rx bid={0,1,2,3}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
+|
+|<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
+| |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
+@ decoding from here
+
+
+== rx_tchh_fn(): TCH/HS, TCH/AHS
+
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+ |
+ |<~~~~~~~~~~~~~>| frame A
+ | |<~~~~~~~~~~~~~>| frame B
+ @ decoding from here
+
+
+== rx_tchh_fn(): FACCH/H
+
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
+ |
+ |<~~~~~~~~~~~~~~~~~~~~~>| frame A
+ | |<~~~~~~~~~~~~~~~~~~~~~>| frame B
+ @ decoding from here
+
+
+== rx_tchh_fn(): TCH/H4.8, TCH/H2.4
+
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | | | Rx bid={0,1}
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | | | Rx bid={0,1}
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | | | Rx bid={0,1}
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | | | Rx bid={0,1}
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | | | Rx bid={0,1}, decode
+|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
+|
+|<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
+| |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
+@ decoding from here
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index a15ce3d2..cbd0fc37 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -1,5 +1,39 @@
-noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h gsm_data_shared.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 phy_link.h \
- dtx_dl_amr_fsm.h
+noinst_HEADERS = \
+ abis.h \
+ abis_osmo.h \
+ asci.h \
+ bts.h \
+ bts_model.h \
+ bts_shutdown_fsm.h \
+ bts_sm.h \
+ bts_trx.h \
+ gsm_data.h \
+ logging.h \
+ measurement.h \
+ oml.h \
+ paging.h \
+ rsl.h \
+ rtp_input_preen.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 \
+ csd_v110.h \
+ l1sap.h \
+ lchan.h \
+ power_control.h \
+ scheduler.h \
+ scheduler_backend.h \
+ phy_link.h \
+ dtx_dl_amr_fsm.h \
+ ta_control.h \
+ nm_common_fsm.h \
+ notification.h \
+ osmux.h \
+ $(NULL)
diff --git a/include/osmo-bts/abis.h b/include/osmo-bts/abis.h
index 62407ece..40707cd1 100644
--- a/include/osmo-bts/abis.h
+++ b/include/osmo-bts/abis.h
@@ -6,19 +6,15 @@
#include <osmo-bts/gsm_data.h>
-#define OML_RETRY_TIMER 5
-#define OML_PING_TIMER 20
-
-enum {
- LINK_STATE_IDLE = 0,
- LINK_STATE_RETRYING,
- LINK_STATE_CONNECTING,
- LINK_STATE_CONNECT,
+enum abis_link_fsm_event {
+ ABIS_LINK_EV_SIGN_LINK_OML_UP,
+ ABIS_LINK_EV_SIGN_LINK_DOWN,
+ ABIS_LINK_EV_VTY_RM_ADDR, /* data: struct bsc_oml_host* being removed */
};
void abis_init(struct gsm_bts *bts);
-struct e1inp_line *abis_open(struct gsm_bts *bts, char *dst_host,
- char *model_name);
+int abis_open(struct gsm_bts *bts, char *model_name);
+
int abis_oml_sendmsg(struct msgb *msg);
diff --git a/include/osmo-bts/abis_osmo.h b/include/osmo-bts/abis_osmo.h
new file mode 100644
index 00000000..be2817f0
--- /dev/null
+++ b/include/osmo-bts/abis_osmo.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <osmocom/core/msgb.h>
+#include <osmo-bts/pcuif_proto.h>
+
+struct gsm_bts;
+
+int down_osmo(struct gsm_bts *bts, struct msgb *msg);
+
+int abis_osmo_pcu_tx_container(struct gsm_bts *bts, const struct gsm_pcu_if_container *container);
diff --git a/include/osmo-bts/amr.h b/include/osmo-bts/amr.h
index f3132874..3fa4b8f2 100644
--- a/include/osmo-bts/amr.h
+++ b/include/osmo-bts/amr.h
@@ -14,5 +14,6 @@ int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc,
void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc,
uint8_t cmi, uint8_t cmr);
unsigned int amr_get_initial_mode(struct gsm_lchan *lchan);
+void amr_init_mr_conf_def(struct gsm_lchan *lchan);
#endif /* _OSMO_BTS_AMR_H */
diff --git a/include/osmo-bts/asci.h b/include/osmo-bts/asci.h
new file mode 100644
index 00000000..99802962
--- /dev/null
+++ b/include/osmo-bts/asci.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <stdint.h>
+
+#include <osmo-bts/lchan.h>
+
+enum {
+ VGCS_TALKER_NONE = 0,
+ VGCS_TALKER_WAIT_FRAME,
+ VGCS_TALKER_ACTIVE,
+};
+
+void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn);
+
+void vgcs_lchan_activate(struct gsm_lchan *lchan);
+
+void vgcs_lchan_react(struct gsm_lchan *lchan);
+
+void vgcs_talker_frame(struct gsm_lchan *lchan);
+
+void vgcs_talker_reset(struct gsm_lchan *lchan, bool ul_access);
+
+void vgcs_listener_reset(struct gsm_lchan *lchan);
+
+static inline bool vgcs_is_uplink_free(struct gsm_lchan *lchan)
+{
+ return lchan->asci.uplink_free;
+}
+
+static inline void vgcs_uplink_free_get(struct gsm_lchan *lchan, uint8_t *msg)
+{
+ memcpy(msg, lchan->asci.uplink_free_msg, GSM_MACBLOCK_LEN);
+}
+
+static inline void vgcs_uplink_free_set(struct gsm_lchan *lchan, uint8_t *msg)
+{
+ memcpy(lchan->asci.uplink_free_msg, msg, GSM_MACBLOCK_LEN);
+ lchan->asci.uplink_free = true;
+}
+
+static inline void vgcs_uplink_free_reset(struct gsm_lchan *lchan)
+{
+ lchan->asci.uplink_free = false;
+}
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 4d132145..8a5fb820 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -2,7 +2,13 @@
#define _BTS_H
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/socket.h>
#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_trx.h>
+#include <osmo-bts/osmux.h>
+
+
+struct gsm_bts_trx;
enum bts_global_status {
BTS_STATUS_RF_ACTIVE,
@@ -13,59 +19,449 @@ enum bts_global_status {
enum {
BTS_CTR_PAGING_RCVD,
BTS_CTR_PAGING_DROP,
+ BTS_CTR_PAGING_DROP_PS,
BTS_CTR_PAGING_SENT,
+ BTS_CTR_PAGING_CONG,
BTS_CTR_RACH_RCVD,
BTS_CTR_RACH_DROP,
BTS_CTR_RACH_HO,
+ BTS_CTR_RACH_VGCS,
BTS_CTR_RACH_CS,
BTS_CTR_RACH_PS,
BTS_CTR_AGCH_RCVD,
BTS_CTR_AGCH_SENT,
BTS_CTR_AGCH_DELETED,
+
+ BTS_CTR_RTP_RX_TOTAL,
+ BTS_CTR_RTP_RX_MARKER,
+ BTS_CTR_RTP_RX_DROP_PREEN,
+ BTS_CTR_RTP_RX_DROP_LOOPBACK,
+ BTS_CTR_RTP_RX_DROP_OVERFLOW,
+ BTS_CTR_RTP_RX_DROP_V110_DEC,
+ BTS_CTR_RTP_TX_TOTAL,
+ BTS_CTR_RTP_TX_MARKER,
+};
+
+/* Used by OML layer for BTS Attribute reporting */
+enum bts_attribute {
+ BTS_TYPE_VARIANT,
+ BTS_SUB_MODEL,
+ TRX_PHY_VERSION,
+};
+const char *btsatttr2str(enum bts_attribute v);
+
+enum gsm_bts_type_variant {
+ BTS_UNKNOWN,
+ BTS_OSMO_LITECELL15,
+ BTS_OSMO_OC2G,
+ BTS_OSMO_OCTPHY,
+ BTS_OSMO_SYSMO,
+ BTS_OSMO_TRX,
+ BTS_OSMO_VIRTUAL,
+ BTS_OSMO_OMLDUMMY,
+ _NUM_BTS_VARIANT
+};
+const char *btsvariant2str(enum gsm_bts_type_variant v);
+
+enum bts_impl_flag {
+ /* TODO: add a brief description of this flag */
+ BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP,
+ /* When this flag is set then the measurement data is included in
+ * (PRIM_PH_DATA) and struct ph_tch_param (PRIM_TCH). Otherwise the
+ * measurement data is passed using a separate MPH INFO MEAS IND.
+ * (See also ticket: OS#2977) */
+ BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB,
+ /* Whether the BTS model requires RadioCarrier MO to be in Enabled state
+ * (OPSTARTed) before OPSTARTing the RadioChannel MOs. See OS#5157 */
+ BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER,
+ /* Whether the BTS model reports interference measurements to L1SAP. */
+ BTS_INTERNAL_FLAG_INTERF_MEAS,
+
+ _BTS_INTERNAL_FLAG_NUM, /* must be at the end */
+};
+
+/* BTS implementation flags (internal use, not exposed via OML) */
+#define bts_internal_flag_get(bts, flag) \
+ ((bts->flags & (typeof(bts->flags))(1 << flag)) != 0)
+#define bts_internal_flag_set(bts, flag) \
+ bts->flags |= (typeof(bts->flags))(1 << flag)
+
+struct gprs_rlc_cfg {
+ uint16_t parameter[_NUM_RLC_PAR];
+ struct {
+ uint16_t repeat_time; /* ms */
+ uint8_t repeat_count;
+ } paging;
+ uint32_t cs_mask; /* bitmask of gprs_cs */
+ uint8_t initial_cs;
+ uint8_t initial_mcs;
+};
+
+struct bts_smscb_state {
+ struct llist_head queue; /* list of struct smscb_msg */
+ int queue_len;
+ struct rate_ctr_group *ctrs;
+ struct smscb_msg *cur_msg; /* current SMS-CB */
+ struct smscb_msg *default_msg; /* default broadcast message; NULL if none */
+};
+
+/* Tx power filtering algorithm */
+enum bts_pf_algo {
+ BTS_PF_ALGO_NONE = 0,
+ BTS_PF_ALGO_EWMA,
+};
+
+/* UL/DL power control parameters */
+struct bts_power_ctrl_params {
+ /* Target value to strive to */
+ int target_dbm;
+ /* Tolerated deviation from target */
+ int hysteresis_db;
+ /* How many dB do we raise power at maximum */
+ int raise_step_max_db;
+ /* How many dB do we lower power at maximum */
+ int lower_step_max_db;
+ /* RxLev filtering algorithm */
+ enum bts_pf_algo pf_algo;
+ /* (Optional) filtering parameters */
+ union {
+ /* Exponentially Weighted Moving Average */
+ struct {
+ /* Smoothing factor: higher the value - less smoothing */
+ uint8_t alpha; /* 1 .. 99 (in %) */
+ } ewma;
+ } pf;
+};
+
+/* GPRS CELL; ip.access specific NM Object */
+struct gsm_gprs_cell {
+ struct gsm_abis_mo mo;
+ uint16_t bvci;
+ uint8_t timer[11];
+ struct gprs_rlc_cfg rlc_cfg;
+ struct {
+ uint32_t gprs_codings; /* see NM_IPAC_F_GPRS_CODING_* flags */
+ } support;
+};
+
+/* Struct that holds one OML-Address (Address of the BSC) */
+struct bsc_oml_host {
+ struct llist_head list;
+ char *addr;
};
+#define BTS_PCU_SOCK_WQUEUE_LEN_DEFAULT 100
+
+/* One BTS */
+struct gsm_bts {
+ /* list header in g_bts_sm->bts_list */
+ struct llist_head list;
+
+ /* number of the BTS in network */
+ uint8_t nr;
+ /* human readable name / description */
+ char *description;
+ /* Cell Identity */
+ uint16_t cell_identity;
+ /* location area code of this BTS */
+ uint16_t location_area_code;
+ /* Base Station Identification Code (BSIC), lower 3 bits is BCC,
+ * which is used as TSC for the CCCH */
+ uint8_t bsic;
+ bool bsic_configured;
+ /* type of BTS */
+ enum gsm_bts_type_variant variant;
+ enum gsm_band band;
+ char version[MAX_VERSION_LENGTH];
+ char sub_model[MAX_VERSION_LENGTH];
+
+ /* public features of a given BTS (set/reported via OML) */
+ struct bitvec *features;
+ /* implementation flags of a given BTS (not exposed via OML) */
+ uint16_t flags;
+
+ /* Connected PCU version (if any) */
+ char pcu_version[MAX_VERSION_LENGTH];
+
+ /* maximum Tx power that the MS is permitted to use in this cell */
+ int ms_max_power;
+
+ /* how do we talk OML with this TRX? */
+ struct e1inp_sign_link *oml_link;
+ struct timespec oml_conn_established_timestamp;
+ /* OSMO extenion link associated to same line as oml_link: */
+ struct e1inp_sign_link *osmo_link;
+
+ /* Abis network management O&M handle */
+ struct gsm_abis_mo mo;
+
+ /* number of this BTS on given E1 link */
+ uint8_t bts_nr;
+
+ /* DTX features of this BTS */
+ bool dtxd;
+
+ /* CCCH is on C0 */
+ struct gsm_bts_trx *c0;
+
+ struct gsm_bts_sm *site_mgr;
+
+ /* bitmask of all SI that are present/valid in si_buf */
+ uint32_t si_valid;
+ /* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
+ uint8_t si2q_index; /* distinguish individual SI2quater messages */
+ uint8_t si2q_count; /* si2q_index for the last (highest indexed) individual SI2quater message */
+ /* buffers where we put the pre-computed SI */
+ sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
+ /* offsets used while generating SI2quater */
+ size_t e_offset;
+ size_t u_offset;
+ /* decoded SI rest octets - *unmodified* as received from BSC */
+ struct osmo_gsm48_si_ro_info si3_ro_decoded;
+ struct osmo_gsm48_si_ro_info si4_ro_decoded;
+ /* is SI GPRS Indicator currently disabled due to lack of PCU connection? */
+ bool si_gprs_ind_disabled;
+
+ /* ip.access Unit ID's have Site/BTS/TRX layout */
+ union {
+ struct {
+ uint16_t site_id;
+ uint16_t bts_id;
+ uint32_t flags;
+ uint32_t rsl_ip;
+ } ip_access;
+ };
+
+ /* Not entirely sure how ip.access specific this is */
+ struct {
+ struct gsm_gprs_cell cell;
+ uint8_t rac;
+ } gprs;
+
+ /* transceivers */
+ int num_trx;
+ struct llist_head trx_list;
+
+ struct rate_ctr_group *ctrs;
+ bool supp_meas_toa256;
+
+ struct {
+ /* Interference Boundaries for OML */
+ int16_t boundary[6];
+ uint8_t intave;
+ } interference;
+ uint32_t t200_fn[7];
+ unsigned int t3105_ms;
+ unsigned int t3115_ms; /* VGCS UPLINK GRANT repeat timer */
+ struct {
+ uint8_t overload_period;
+ struct {
+ /* Input parameters from OML */
+ uint8_t load_ind_thresh; /* percent */
+ uint8_t load_ind_period; /* seconds */
+ /* Internal data */
+ struct osmo_timer_list timer;
+ unsigned int pch_total;
+ unsigned int pch_used;
+ } ccch;
+ struct {
+ /* Input parameters from OML */
+ int16_t busy_thresh; /* in dBm */
+ uint16_t averaging_slots;
+ /* Internal data */
+ unsigned int total; /* total nr */
+ unsigned int busy; /* above busy_thresh */
+ unsigned int access; /* access bursts */
+ } rach;
+ } load;
+ uint8_t ny1;
+ uint8_t ny2; /* maximum number of repetitions for the VGCS UPLINK GRANT */
+ uint8_t max_ta;
+
+ /* AGCH queuing */
+ struct {
+ struct llist_head queue;
+ int length;
+ int max_length;
+
+ int thresh_level; /* Cleanup threshold in percent of max len */
+ int low_level; /* Low water mark in percent of max len */
+ int high_level; /* High water mark in percent of max len */
+
+ /* TODO: Use a rate counter group instead */
+ uint64_t dropped_msgs;
+ uint64_t merged_msgs;
+ uint64_t rejected_msgs;
+ uint64_t agch_msgs;
+ uint64_t pch_msgs;
+ } agch_queue;
+
+ struct {
+ uint8_t *prim_notif; /* ETWS primary notification (NULL if none) */
+ ssize_t prim_notif_len; /* Length of prim_notif; expected 56 bytes */
+ uint8_t page_size;
+ uint8_t num_pages; /* total number of pages */
+ uint8_t next_page; /* next page number to be sent */
+ bool pni; /* Primary Notification Identifier */
+ } etws;
+
+ /* Advanced Speech Call Items (VBS/VGCS) + NCH related bits */
+ struct {
+ int pos_nch; /* position of the NCH or < 0, if not available */
+ uint8_t nln, nln_status; /* current notification list number and status */
+ struct llist_head notifications;
+ int notification_entries; /* current number of entries in the list */
+ int notification_count; /* counter to count all entries */
+ } asci;
+
+ struct paging_state *paging_state;
+ struct llist_head bsc_oml_hosts;
+ unsigned int rtp_jitter_buf_ms;
+ bool rtp_jitter_adaptive;
+
+ uint16_t rtp_port_range_start;
+ uint16_t rtp_port_range_end;
+ uint16_t rtp_port_range_next;
+ int rtp_ip_dscp;
+ int rtp_priority;
+
+ bool rtp_nogaps_mode; /* emit RTP stream without any gaps */
+ bool use_ul_ecu; /* "rtp internal-uplink-ecu" option */
+ bool emit_hr_rfc5993;
+
+ struct {
+ uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
+ uint8_t max_ta; /* maximum timing advance */
+ } support;
+ struct {
+ uint8_t tc4_ctr;
+ } si;
+ struct gsm_time gsm_time;
+ /* frame number statistics (FN in PH-RTS.ind vs. PH-DATA.ind */
+ struct {
+ int32_t min; /* minimum observed */
+ int32_t max; /* maximum observed */
+ int32_t avg256; /* accumulator */
+ uint32_t avg_count; /* number of samples accumulated in avg256 */
+ uint32_t avg_window; /* number of averages in avg_count */
+ } fn_stats;
+ /* Radio Link Timeout counter. -1 disables timeout for
+ * lab/measurement purpose */
+ struct {
+ int oml; /* value communicated by BSC in OML */
+ int current; /* actual currently applied value */
+ bool vty_override; /* OML value overridden by VTY */
+ } radio_link_timeout;
+
+ /* Default (fall-back) Dynamic Power Control parameters for all transceivers */
+ struct gsm_power_ctrl_params bs_dpc_params; /* BS Dynamic Power Control */
+ struct gsm_power_ctrl_params ms_dpc_params; /* MS Dynamic Power Control */
+
+ /* Maximum BCCH carrier power reduction */
+ uint8_t c0_power_red_db;
+
+ /* used by the sysmoBTS to adjust band */
+ uint8_t auto_band;
+
+ /* State for SMSCB (Cell Broadcast) for BASIC and EXTENDED channel */
+ struct bts_smscb_state smscb_basic;
+ struct bts_smscb_state smscb_extended;
+ int smscb_queue_tgt_len; /* ideal/target queue length */
+ int smscb_queue_max_len; /* maximum queue length */
+ int smscb_queue_hyst; /* hysteresis for CBCH load indications */
+
+ int16_t min_qual_rach; /* minimum link quality (in centiBels) for Access Bursts */
+ int16_t min_qual_norm; /* minimum link quality (in centiBels) for Normal Bursts */
+ uint16_t max_ber10k_rach; /* Maximum permitted RACH BER in 0.01% */
+
+ struct {
+ char *sock_path;
+ unsigned int sock_wqueue_len_max;
+ } pcu;
+
+ /* GSMTAP Um logging (disabled by default) */
+ struct {
+ struct gsmtap_inst *inst;
+ char *remote_host;
+ char *local_host;
+ uint32_t sapi_mask;
+ uint8_t sapi_acch;
+ bool rlp;
+ bool rlp_skip_null;
+ } gsmtap;
+
+ struct osmux_state osmux;
+
+ struct osmo_fsm_inst *shutdown_fi; /* FSM instance to manage shutdown procedure during process exit */
+ bool shutdown_fi_exit_proc; /* exit process when shutdown_fsm is finished? */
+ bool shutdown_fi_skip_power_ramp; /* Skip power ramping and change power in one step? */
+ struct osmo_fsm_inst *abis_link_fi; /* FSM instance to manage abis connection during process startup and link failure */
+ struct osmo_tdef *T_defs; /* Timer defines */
+
+ void *model_priv; /* Allocated by bts_model, contains model specific data pointer */
+};
+
+extern const struct value_string bts_impl_flag_desc[];
extern void *tall_bts_ctx;
+#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
+#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
+#define GSM_BTS_SI(bts, i) (void *)((bts)->si_buf[i][0])
+
+static inline struct gsm_bts *gsm_gprs_cell_get_bts(struct gsm_gprs_cell *cell)
+{
+ return (struct gsm_bts *)container_of(cell, struct gsm_bts, gprs.cell);
+}
+
+struct gsm_bts *gsm_bts_alloc(struct gsm_bts_sm *bts_sm, uint8_t bts_num);
+struct gsm_bts *gsm_bts_num(const struct gsm_bts_sm *bts_sm, int num);
+
int bts_init(struct gsm_bts *bts);
-int bts_trx_init(struct gsm_bts_trx *trx);
void bts_shutdown(struct gsm_bts *bts, const char *reason);
+void bts_shutdown_ext(struct gsm_bts *bts, const char *reason, bool exit_proc, bool skip_power_ramp);
-struct gsm_bts *create_bts(uint8_t num_trx, char *id);
-int create_ms(struct gsm_bts_trx *trx, int maskc, uint8_t *maskv_tx,
- uint8_t *maskv_rx);
-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);
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);
+enum ccch_msgt {
+ CCCH_MSGT_AGCH,
+ CCCH_MSGT_PCH,
+ CCCH_MSGT_NCH,
+};
+
+int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch);
+int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher);
uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time);
void regenerate_si3_restoctets(struct gsm_bts *bts);
-uint8_t *lchan_sacch_get(struct gsm_lchan *lchan);
-int lchan_init_lapdm(struct gsm_lchan *lchan);
+void regenerate_si4_restoctets(struct gsm_bts *bts);
+int get_si4_ro_offset(const uint8_t *si4_buf);
void load_timer_start(struct gsm_bts *bts);
-uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg);
+void load_timer_stop(struct gsm_bts *bts);
+bool load_timer_is_running(const struct gsm_bts *bts);
void bts_update_status(enum bts_global_status which, int on);
-int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx);
-
struct gsm_time *get_time(struct gsm_bts *bts);
int bts_main(int argc, char **argv);
-int bts_supports_cm(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
- enum gsm48_chan_mode cm);
+bool bts_supports_cm(const struct gsm_bts *bts,
+ const struct rsl_ie_chan_mode *cm);
-int32_t bts_get_avg_fn_advance(struct gsm_bts *bts);
+int32_t bts_get_avg_fn_advance(const struct gsm_bts *bts);
-#endif /* _BTS_H */
+/* return the gsm_lchan for the CBCH (if it exists at all) */
+struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
+
+int bts_set_c0_pwr_red(struct gsm_bts *bts, const uint8_t red);
+/* Context information to be put in the control buffer (db) of the AGCH msg
+ * buffer */
+struct bts_agch_msg_cb {
+ uint32_t msg_id;
+ bool confirm;
+} __attribute__ ((packed));
+
+#endif /* _BTS_H */
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index be0480c1..673eb5b1 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -5,6 +5,7 @@
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmo-bts/gsm_data.h>
@@ -20,8 +21,8 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
struct tlv_parsed *old_attr, struct tlv_parsed *new_attr,
void *obj);
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int obj_kind, void *obj);
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj);
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj);
@@ -30,17 +31,20 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj, uint8_t adm_state);
int bts_model_trx_deact_rf(struct gsm_bts_trx *trx);
-int bts_model_trx_close(struct gsm_bts_trx *trx);
-int bts_model_vty_init(struct gsm_bts *bts);
+/* Implementation should call bts_model_trx_close_cb when done */
+void bts_model_trx_close(struct gsm_bts_trx *trx);
-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_vty_init(void *ctx);
+
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts);
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx);
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink);
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst);
int bts_model_oml_estab(struct gsm_bts *bts);
+/* Implementation should call power_trx_change_compl() to confirm power change applied */
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan);
@@ -62,4 +66,10 @@ void bts_model_phy_instance_set_defaults(struct phy_instance *pinst);
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts);
void bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan);
+/* BTS model specific implementations are expected to call these functions as a
+ * response to some of the APIs above:
+ */
+
+void bts_model_trx_close_cb(struct gsm_bts_trx *trx, int rc);
+
#endif
diff --git a/include/osmo-bts/bts_shutdown_fsm.h b/include/osmo-bts/bts_shutdown_fsm.h
new file mode 100644
index 00000000..553267dc
--- /dev/null
+++ b/include/osmo-bts/bts_shutdown_fsm.h
@@ -0,0 +1,43 @@
+/* BTS shutdown FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/fsm.h>
+
+enum bts_shutdown_fsm_states {
+ BTS_SHUTDOWN_ST_NONE,
+ BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL,
+ BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED,
+ BTS_SHUTDOWN_ST_EXIT,
+};
+
+enum bts_shutdown_fsm_events {
+ BTS_SHUTDOWN_EV_START,
+ BTS_SHUTDOWN_EV_TRX_RAMP_COMPL,
+ BTS_SHUTDOWN_EV_TRX_CLOSED,
+};
+
+extern struct osmo_fsm bts_shutdown_fsm;
+
+struct gsm_bts;
+bool bts_shutdown_in_progress(const struct gsm_bts *bts);
diff --git a/include/osmo-bts/bts_sm.h b/include/osmo-bts/bts_sm.h
new file mode 100644
index 00000000..e6610a5e
--- /dev/null
+++ b/include/osmo-bts/bts_sm.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/gsm/gsm23003.h>
+
+#include <osmo-bts/oml.h>
+
+struct pcu_sock_state;
+
+/* GPRS NSVC; ip.access specific NM Object */
+struct gsm_gprs_nse;
+struct gsm_gprs_nsvc {
+ struct gsm_abis_mo mo;
+ struct gsm_gprs_nse *nse;
+ /* data read via VTY config file, to configure the BTS
+ * via OML from BSC */
+ int id;
+ uint16_t nsvci;
+ struct osmo_sockaddr local; /* on the BTS */
+ struct osmo_sockaddr remote; /* on the SGSN */
+};
+
+/* GPRS NSE; ip.access specific NM Object */
+struct gsm_gprs_nse {
+ struct gsm_abis_mo mo;
+ uint16_t nsei;
+ uint8_t timer[7];
+ struct gsm_gprs_nsvc nsvc[2];
+};
+
+struct gsm_bts *gsm_gprs_nse_get_bts(const struct gsm_gprs_nse *nse);
+
+/* BTS Site Manager */
+struct gsm_bts_sm {
+ struct gsm_abis_mo mo;
+ struct llist_head bts_list;
+ unsigned int num_bts;
+ struct osmo_plmn_id plmn;
+ struct {
+ struct pcu_sock_state *pcu_state;
+ struct gsm_gprs_nse nse;
+ } gprs;
+};
+
+extern struct gsm_bts_sm *g_bts_sm;
+
+struct gsm_bts_sm *gsm_bts_sm_alloc(void *talloc_ctx);
diff --git a/include/osmo-bts/bts_trx.h b/include/osmo-bts/bts_trx.h
new file mode 100644
index 00000000..9d3a748e
--- /dev/null
+++ b/include/osmo-bts/bts_trx.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <osmocom/core/sockaddr_str.h>
+#include <osmo-bts/gsm_data.h>
+
+struct gsm_bts_bb_trx {
+ struct gsm_abis_mo mo;
+ /* how do we talk RSL with this TRX? */
+ struct {
+ struct osmo_sockaddr_str rem_addrstr;
+ uint8_t tei;
+ struct e1inp_sign_link *link;
+ } rsl;
+};
+
+/* One TRX in a BTS */
+struct gsm_bts_trx {
+ /* list header in bts->trx_list */
+ struct llist_head list;
+
+ struct gsm_bts *bts;
+ /* number of this TRX in the BTS */
+ uint8_t nr;
+ /* human readable name / description */
+ char *description;
+
+ /* NM Radio Carrier and Baseband Transciever */
+ struct gsm_abis_mo mo;
+ struct gsm_bts_bb_trx bb_transc;
+
+ uint16_t arfcn;
+ int nominal_power; /* in dBm */
+ unsigned int max_power_red; /* in actual dB */
+ uint8_t max_power_backoff_8psk; /* in actual dB OC-2G only */
+ uint8_t c0_idle_power_red; /* in actual dB OC-2G only */
+
+ uint8_t ta_ctrl_interval; /* 1 step is 2 SACCH periods */
+
+ struct trx_power_params power_params;
+ struct gsm_power_ctrl_params *bs_dpc_params; /* BS Dynamic Power Control */
+ struct gsm_power_ctrl_params *ms_dpc_params; /* MS Dynamic Power Control */
+ bool ms_pwr_ctl_soft; /* is power control loop done by osmocom software? */
+
+ /* The associated PHY instance */
+ struct phy_instance *pinst;
+
+ struct {
+ uint32_t freq_bands; /* see NM_IPAC_F_FREQ_BAND_* flags */
+ uint32_t chan_types; /* see NM_IPAC_F_CHANT_* flags */
+ uint32_t chan_modes; /* see NM_IPAC_F_CHANM_* flags */
+ } support;
+
+ struct gsm_bts_trx_ts ts[TRX_NR_TS];
+};
+
+static inline struct gsm_bts_trx *gsm_bts_bb_trx_get_trx(struct gsm_bts_bb_trx *bb_transc) {
+ return (struct gsm_bts_trx *)container_of(bb_transc, struct gsm_bts_trx, bb_transc);
+}
+
+struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
+struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx);
+void gsm_bts_trx_free_shadow_ts(struct gsm_bts_trx *trx);
+char *gsm_trx_name(const struct gsm_bts_trx *trx);
+const char *gsm_trx_unit_id(struct gsm_bts_trx *trx);
+
+int trx_link_estab(struct gsm_bts_trx *trx);
+void trx_operability_update(struct gsm_bts_trx *trx);
+
+uint8_t num_agch(const struct gsm_bts_trx *trx, const char * arg);
+int pos_nch(const struct gsm_bts_trx *trx, const char *arg);
+bool trx_ms_pwr_ctrl_is_osmo(const struct gsm_bts_trx *trx);
+
+#define LOGPTRX(trx, ss, lvl, fmt, args...) LOGP(ss, lvl, "%s " fmt, gsm_trx_name(trx), ## args)
diff --git a/include/osmo-bts/cbch.h b/include/osmo-bts/cbch.h
index 6bba5fa2..d5521f06 100644
--- a/include/osmo-bts/cbch.h
+++ b/include/osmo-bts/cbch.h
@@ -21,3 +21,5 @@ int bts_process_smscb_cmd(struct gsm_bts *bts, struct rsl_ie_cb_cmd_type cmd_typ
/* call-back from bts model specific code when it wants to obtain a CBCH
* block for a given gsm_time. outbuf must have 23 bytes of space. */
int bts_cbch_get(struct gsm_bts *bts, uint8_t *outbuf, struct gsm_time *g_time);
+
+void bts_cbch_reset(struct gsm_bts *bts);
diff --git a/include/osmo-bts/control_if.h b/include/osmo-bts/control_if.h
index 490c87af..f6d877bc 100644
--- a/include/osmo-bts/control_if.h
+++ b/include/osmo-bts/control_if.h
@@ -1,5 +1,4 @@
#pragma once
int bts_ctrl_cmds_install(struct gsm_bts *bts);
-struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
- const char *bind_addr, uint16_t port);
+struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts, uint16_t port);
diff --git a/include/osmo-bts/csd_v110.h b/include/osmo-bts/csd_v110.h
new file mode 100644
index 00000000..f6be0ae2
--- /dev/null
+++ b/include/osmo-bts/csd_v110.h
@@ -0,0 +1,23 @@
+#pragma once
+
+/* RFC4040 "clearmode" RTP payload length */
+#define RFC4040_RTP_PLEN 160
+
+struct gsm_lchan;
+
+struct csd_v110_frame_desc {
+ uint16_t num_blocks;
+ uint16_t num_bits;
+};
+
+struct csd_v110_lchan_desc {
+ struct csd_v110_frame_desc fr;
+ struct csd_v110_frame_desc hr;
+};
+
+extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256];
+
+int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp,
+ const uint8_t *data, size_t data_len);
+int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data,
+ const uint8_t *rtp, size_t rtp_len);
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index 1de5eddd..164c89fd 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -1,13 +1,33 @@
#ifndef _GSM_DATA_H
#define _GSM_DATA_H
+#include <stdbool.h>
+#include <stdint.h>
+
#include <osmocom/core/timer.h>
+#include <osmocom/core/bitvec.h>
+#include <osmocom/core/statistics.h>
+#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
-#include <osmocom/gsm/lapdm.h>
+#include <osmocom/core/tdef.h>
#include <osmocom/gsm/gsm23003.h>
+#include <osmocom/gsm/gsm0502.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/rxlev_stat.h>
+#include <osmocom/gsm/sysinfo.h>
+#include <osmocom/gsm/bts_features.h>
+#include <osmocom/gsm/gsm48_rest_octets.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmocom/abis/e1_input.h>
#include <osmo-bts/paging.h>
#include <osmo-bts/tx_power.h>
+#include <osmo-bts/oml.h>
+#include <osmo-bts/lchan.h>
#define GSM_FR_BITS 260
#define GSM_EFR_BITS 244
@@ -16,45 +36,209 @@
#define GSM_HR_BYTES 14 /* TS 101318 Chapter 5.2: 112 bits, no sig */
#define GSM_EFR_BYTES 31 /* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
-#define GSM_SUPERFRAME (26*51) /* 1326 TDMA frames */
-#define GSM_HYPERFRAME (2048*GSM_SUPERFRAME) /* GSM_HYPERFRAME frames */
-
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT 41
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE 999999
#define GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT 41
#define GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT 91
-#define LOGPLCHAN(lchan, ss, lvl, fmt, args...) LOGP(ss, lvl, "%s " fmt, gsm_lchan_name(lchan), ## args)
-struct gsm_network {
- struct llist_head bts_list;
- unsigned int num_bts;
- struct osmo_plmn_id plmn;
- struct pcu_sock_state *pcu_state;
+/* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1:
+ 4-bit index is used (2#1111 = 10#15) */
+#define SI2Q_MAX_NUM 16
+/* length in bits (for single SI2quater message) */
+#define SI2Q_MAX_LEN 160
+#define SI2Q_MIN_LEN 18
+
+/* lchans 0..3 are SDCCH in combined channel configuration,
+ use 4 as magic number for BCCH hack - see osmo-bts-../oml.c:opstart_compl() */
+#define CCCH_LCHAN 4
+#define CBCH_LCHAN 2
+
+#define TRX_NR_TS 8
+#define TS_MAX_LCHAN 8
+
+#define MAX_VERSION_LENGTH 64
+
+/* NM_IPAC_F_CHANT_* mask for NM_IPAC_EIE_CHAN_TYPES (common) */
+#define NM_IPAC_MASK_CHANT_COMMON \
+ (NM_IPAC_F_CHANT_TCHF | \
+ NM_IPAC_F_CHANT_TCHH | \
+ NM_IPAC_F_CHANT_SDCCH8 | \
+ NM_IPAC_F_CHANT_BCCH | \
+ NM_IPAC_F_CHANT_BCCH_SDCCH4)
+/* NM_IPAC_F_CHANM_SPEECH_* mask for NM_IPAC_EIE_CHAN_MODES */
+#define NM_IPAC_MASK_CHANM_SPEECH \
+ (NM_IPAC_F_CHANM_SPEECH_FS | \
+ NM_IPAC_F_CHANM_SPEECH_EFS | \
+ NM_IPAC_F_CHANM_SPEECH_AFS | \
+ NM_IPAC_F_CHANM_SPEECH_HS | \
+ NM_IPAC_F_CHANM_SPEECH_AHS)
+/* NM_IPAC_F_CHANM_CSD_NT_* mask for NM_IPAC_EIE_CHAN_MODES */
+#define NM_IPAC_MASK_CHANM_CSD_NT \
+ (NM_IPAC_F_CHANM_CSD_NT_4k8 | \
+ NM_IPAC_F_CHANM_CSD_NT_9k6 | \
+ NM_IPAC_F_CHANM_CSD_NT_14k4)
+/* NM_IPAC_F_CHANM_CSD_T_* mask for NM_IPAC_EIE_CHAN_MODES */
+#define NM_IPAC_MASK_CHANM_CSD_T \
+ (NM_IPAC_F_CHANM_CSD_T_1200_75 | \
+ NM_IPAC_F_CHANM_CSD_T_600 | \
+ NM_IPAC_F_CHANM_CSD_T_1k2 | \
+ NM_IPAC_F_CHANM_CSD_T_2k4 | \
+ NM_IPAC_F_CHANM_CSD_T_4k8 | \
+ NM_IPAC_F_CHANM_CSD_T_9k6 | \
+ NM_IPAC_F_CHANM_CSD_T_14k4)
+/* NM_IPAC_F_GPRS_CODING_CS[1-4] mask for NM_IPAC_EIE_GPRS_CODING */
+#define NM_IPAC_MASK_GPRS_CODING_CS \
+ (NM_IPAC_F_GPRS_CODING_CS1 | \
+ NM_IPAC_F_GPRS_CODING_CS2 | \
+ NM_IPAC_F_GPRS_CODING_CS3 | \
+ NM_IPAC_F_GPRS_CODING_CS4)
+/* NM_IPAC_F_GPRS_CODING_MCS[1-9] mask for NM_IPAC_EIE_GPRS_CODING */
+#define NM_IPAC_MASK_GPRS_CODING_MCS \
+ (NM_IPAC_F_GPRS_CODING_MCS1 | \
+ NM_IPAC_F_GPRS_CODING_MCS2 | \
+ NM_IPAC_F_GPRS_CODING_MCS3 | \
+ NM_IPAC_F_GPRS_CODING_MCS4 | \
+ NM_IPAC_F_GPRS_CODING_MCS5 | \
+ NM_IPAC_F_GPRS_CODING_MCS6 | \
+ NM_IPAC_F_GPRS_CODING_MCS7 | \
+ NM_IPAC_F_GPRS_CODING_MCS8 | \
+ NM_IPAC_F_GPRS_CODING_MCS9)
+
+enum gsm_bts_trx_ts_flags {
+ TS_F_PDCH_ACTIVE = 0x1000,
+ TS_F_PDCH_ACT_PENDING = 0x2000,
+ TS_F_PDCH_DEACT_PENDING = 0x4000,
+ TS_F_PDCH_PENDING_MASK = 0x6000 /*<
+ TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING */
+};
+
+/* One Timeslot in a TRX */
+struct gsm_bts_trx_ts {
+ struct gsm_bts_trx *trx;
+ /* number of this timeslot at the TRX */
+ uint8_t nr;
+
+ enum gsm_phys_chan_config pchan;
+
+ struct {
+ enum gsm_phys_chan_config pchan_is;
+ enum gsm_phys_chan_config pchan_want;
+ } dyn;
+
+ unsigned int flags;
+ struct gsm_abis_mo mo;
+
+ /* Training Sequence Code (range 0..7) */
+ uint8_t tsc_oml; /* configured via OML */
+ bool tsc_oml_configured;
+ uint8_t tsc_rsl; /* configured via RSL (Osmo extension) */
+ bool tsc_rsl_configured;
+ uint8_t tsc; /* TSC currently in use. Preference: RSL, OML, BTS-BSIC-OML */
+ /* Training Sequence Set (range 0..3) */
+ uint8_t tsc_set;
+
+ /* Actual BCCH carrier power reduction */
+ uint8_t c0_power_red_db;
+
+ /* Frequency hopping parameters (configured via OML) */
+ struct {
+ bool enabled;
+ uint8_t maio;
+ uint8_t hsn;
+ uint16_t arfcn_list[64];
+ uint8_t arfcn_num;
+ } hopping;
+
+ /* Transceiver "cache" for frequency hopping */
+ const struct gsm_bts_trx *fh_trx_list[64];
+
+ /* Implementation specific structure(s) */
+ void *priv;
+
+ /* VAMOS specific fields */
+ struct {
+ /* NULL if BTS_FEAT_VAMOS is not set */
+ struct gsm_bts_trx_ts *peer;
+ bool is_shadow;
+ } vamos;
+
+ struct gsm_lchan lchan[TS_MAX_LCHAN];
};
-enum lchan_ciph_state {
- LCHAN_CIPH_NONE,
- LCHAN_CIPH_RX_REQ,
- LCHAN_CIPH_RX_CONF,
- LCHAN_CIPH_RXTX_REQ,
- LCHAN_CIPH_RX_CONF_TX_REQ,
- LCHAN_CIPH_RXTX_CONF,
+enum gprs_rlc_par {
+ RLC_T3142,
+ RLC_T3169,
+ RLC_T3191,
+ RLC_T3193,
+ RLC_T3195,
+ RLC_N3101,
+ RLC_N3103,
+ RLC_N3105,
+ CV_COUNTDOWN,
+ T_DL_TBF_EXT, /* ms */
+ T_UL_TBF_EXT, /* ms */
+ _NUM_RLC_PAR
};
-#include <osmo-bts/gsm_data_shared.h>
+enum gprs_cs {
+ GPRS_CS1,
+ GPRS_CS2,
+ GPRS_CS3,
+ GPRS_CS4,
+ GPRS_MCS1,
+ GPRS_MCS2,
+ GPRS_MCS3,
+ GPRS_MCS4,
+ GPRS_MCS5,
+ GPRS_MCS6,
+ GPRS_MCS7,
+ GPRS_MCS8,
+ GPRS_MCS9,
+ _NUM_GRPS_CS
+};
+
+/* The amount of time within which a sudden disconnect of a newly established
+ * OML connection will cause a special warning to be logged. */
+#define OSMO_BTS_OML_CONN_EARLY_DISCONNECT 10 /* in seconds */
+
+extern struct osmo_tdef_group bts_tdef_groups[];
+extern struct osmo_tdef bts_T_defs[];
+extern struct osmo_tdef abis_T_defs[];
+
+extern const struct value_string gsm_pchant_names[13];
+extern const struct value_string gsm_pchant_descs[13];
+const char *gsm_pchan_name(enum gsm_phys_chan_config c);
+const char *gsm_lchant_name(enum gsm_chan_t c);
+char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
+char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
+
+#define GSM_TS_NAME_FMT \
+ "bts=%u,trx=%u,ts=%u" "%s"
+#define GSM_TS_NAME_ARGS(ts) \
+ (ts)->trx->bts->nr, (ts)->trx->nr, (ts)->nr, \
+ (ts)->vamos.is_shadow ? ",shadow" : ""
+
+#define BSIC2BCC(bsic) ((bsic) & 0x07)
+#define BTS_TSC(bts) BSIC2BCC((bts)->bsic)
+
+struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
+ int *rc);
+
+enum gsm_phys_chan_config ts_pchan(const struct gsm_bts_trx_ts *ts);
+uint8_t ts_subslots(const struct gsm_bts_trx_ts *ts);
+bool ts_is_tch(const struct gsm_bts_trx_ts *ts);
-void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state);
int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
enum gsm_phys_chan_config pchan);
/* cipher code */
#define CIPHER_A5(x) (1 << (x-1))
-int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher);
-
bool ts_is_pdch(const struct gsm_bts_trx_ts *ts);
-int bts_model_check_cm_mode(enum gsm_phys_chan_config pchan, enum gsm48_chan_mode cm);
+void gsm_ts_apply_configured_tsc(struct gsm_bts_trx_ts *ts);
+
+void gsm_ts_release(struct gsm_bts_trx_ts *ts);
#endif /* _GSM_DATA_H */
diff --git a/include/osmo-bts/gsm_data_shared.h b/include/osmo-bts/gsm_data_shared.h
deleted file mode 100644
index cf7b7157..00000000
--- a/include/osmo-bts/gsm_data_shared.h
+++ /dev/null
@@ -1,882 +0,0 @@
-#ifndef _GSM_DATA_SHAREDH
-#define _GSM_DATA_SHAREDH
-
-#include <regex.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <osmocom/codec/ecu.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/bitvec.h>
-#include <osmocom/core/statistics.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/rxlev_stat.h>
-#include <osmocom/gsm/sysinfo.h>
-#include <osmocom/gsm/meas_rep.h>
-#include <osmocom/gsm/gsm48_rest_octets.h>
-#include <osmocom/gsm/protocol/gsm_04_08.h>
-#include <osmocom/gsm/protocol/gsm_08_58.h>
-#include <osmocom/gsm/protocol/gsm_12_21.h>
-
-#include <osmocom/abis/e1_input.h>
-#include <osmocom/gsm/lapdm.h>
-
-/* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1:
- 4-bit index is used (2#1111 = 10#15) */
-#define SI2Q_MAX_NUM 16
-/* length in bits (for single SI2quater message) */
-#define SI2Q_MAX_LEN 160
-#define SI2Q_MIN_LEN 18
-
-/* Channel Request reason */
-enum gsm_chreq_reason_t {
- GSM_CHREQ_REASON_EMERG,
- GSM_CHREQ_REASON_PAG,
- GSM_CHREQ_REASON_CALL,
- GSM_CHREQ_REASON_LOCATION_UPD,
- GSM_CHREQ_REASON_OTHER,
- GSM_CHREQ_REASON_PDCH,
-};
-
-/* lchans 0..3 are SDCCH in combined channel configuration,
- use 4 as magic number for BCCH hack - see osmo-bts-../oml.c:opstart_compl() */
-#define CCCH_LCHAN 4
-
-#define TRX_NR_TS 8
-#define TS_MAX_LCHAN 8
-
-#define HARDCODED_ARFCN 123
-#define HARDCODED_BSIC 0x3f /* NCC = 7 / BCC = 7 */
-
-/* for multi-drop config */
-#define HARDCODED_BTS0_TS 1
-#define HARDCODED_BTS1_TS 6
-#define HARDCODED_BTS2_TS 11
-
-#define MAX_VERSION_LENGTH 64
-
-#define MAX_BTS_FEATURES 128
-
-enum gsm_hooks {
- GSM_HOOK_NM_SWLOAD,
- GSM_HOOK_RR_PAGING,
- GSM_HOOK_RR_SECURITY,
-};
-
-enum bts_gprs_mode {
- BTS_GPRS_NONE = 0,
- BTS_GPRS_GPRS = 1,
- BTS_GPRS_EGPRS = 2,
-};
-
-struct gsm_lchan;
-struct osmo_rtp_socket;
-struct pcu_sock_state;
-struct smscb_msg;
-
-/* Network Management State */
-struct gsm_nm_state {
- uint8_t operational;
- uint8_t administrative;
- uint8_t availability;
-};
-
-struct gsm_abis_mo {
- /* A-bis OML Object Class */
- uint8_t obj_class;
- /* is there still some procedure pending? */
- uint8_t procedure_pending;
- /* A-bis OML Object Instance */
- struct abis_om_obj_inst obj_inst;
- /* human-readable name */
- const char *name;
- /* NM State */
- struct gsm_nm_state nm_state;
- /* Attributes configured in this MO */
- struct tlv_parsed *nm_attr;
- /* BTS to which this MO belongs */
- struct gsm_bts *bts;
-};
-
-#define MAX_A5_KEY_LEN (128/8)
-#define A38_XOR_MIN_KEY_LEN 12
-#define A38_XOR_MAX_KEY_LEN 16
-#define A38_COMP128_KEY_LEN 16
-#define RSL_ENC_ALG_A5(x) (x+1)
-#define MAX_EARFCN_LIST 32
-
-/* is the data link established? who established it? */
-#define LCHAN_SAPI_UNUSED 0
-#define LCHAN_SAPI_MS 1
-#define LCHAN_SAPI_NET 2
-#define LCHAN_SAPI_REL 3
-
-/* state of a logical channel */
-enum gsm_lchan_state {
- LCHAN_S_NONE, /* channel is not active */
- LCHAN_S_ACT_REQ, /* channel activation requested */
- LCHAN_S_ACTIVE, /* channel is active and operational */
- LCHAN_S_REL_REQ, /* channel release has been requested */
- LCHAN_S_REL_ERR, /* channel is in an error state */
- LCHAN_S_BROKEN, /* channel is somehow unusable */
- LCHAN_S_INACTIVE, /* channel is set inactive */
-};
-
-/* BTS ONLY */
-#define MAX_NUM_UL_MEAS 104
-#define LC_UL_M_F_L1_VALID (1 << 0)
-#define LC_UL_M_F_RES_VALID (1 << 1)
-#define LC_UL_M_F_OSMO_EXT_VALID (1 << 2)
-
-struct bts_ul_meas {
- /* BER in units of 0.01%: 10.000 == 100% ber, 0 == 0% ber */
- uint16_t ber10k;
- /* timing advance offset (in 1/256 bits) */
- int16_t ta_offs_256bits;
- /* C/I ratio in dB */
- float c_i;
- /* flags */
- uint8_t is_sub:1;
- /* RSSI in dBm * -1 */
- uint8_t inv_rssi;
-};
-
-struct bts_codec_conf {
- uint8_t hr;
- uint8_t efr;
- uint8_t amr;
-};
-
-struct amr_mode {
- uint8_t mode;
- uint8_t threshold;
- uint8_t hysteresis;
-};
-
-struct amr_multirate_conf {
- uint8_t gsm48_ie[2];
- struct amr_mode ms_mode[4];
- struct amr_mode bts_mode[4];
- uint8_t num_modes;
-};
-/* /BTS ONLY */
-
-enum lchan_csd_mode {
- LCHAN_CSD_M_NT,
- LCHAN_CSD_M_T_1200_75,
- LCHAN_CSD_M_T_600,
- LCHAN_CSD_M_T_1200,
- LCHAN_CSD_M_T_2400,
- LCHAN_CSD_M_T_9600,
- LCHAN_CSD_M_T_14400,
- LCHAN_CSD_M_T_29000,
- LCHAN_CSD_M_T_32000,
-};
-
-/* State of the SAPIs in the lchan */
-enum lchan_sapi_state {
- LCHAN_SAPI_S_NONE,
- LCHAN_SAPI_S_REQ,
- LCHAN_SAPI_S_ASSIGNED,
- LCHAN_SAPI_S_REL,
- LCHAN_SAPI_S_ERROR,
-};
-
-struct gsm_lchan {
- /* The TS that we're part of */
- struct gsm_bts_trx_ts *ts;
- /* The logical subslot number in the TS */
- uint8_t nr;
- /* The logical channel type */
- enum gsm_chan_t type;
- /* RSL channel mode */
- enum rsl_cmod_spd rsl_cmode;
- /* If TCH, traffic channel mode */
- enum gsm48_chan_mode tch_mode;
- enum lchan_csd_mode csd_mode;
- /* State */
- enum gsm_lchan_state state;
- const char *broken_reason;
- /* Power levels for MS and BTS */
- uint8_t bs_power;
- uint8_t ms_power;
- /* Encryption information */
- struct {
- uint8_t alg_id;
- uint8_t key_len;
- uint8_t key[MAX_A5_KEY_LEN];
- } encr;
-
- /* AMR bits */
- uint8_t mr_bts_lv[7];
-
- /* Established data link layer services */
- int sacch_deact;
-
- struct {
- uint32_t bound_ip;
- uint32_t connect_ip;
- uint16_t bound_port;
- uint16_t connect_port;
- uint16_t conn_id;
- uint8_t rtp_payload;
- uint8_t rtp_payload2;
- uint8_t speech_mode;
- struct osmo_rtp_socket *rtp_socket;
- } abis_ip;
-
- uint8_t rqd_ta;
-
- char *name;
-
- /* Number of different GsmL1_Sapi_t used in osmo_bts_sysmo is 23.
- * Currently we don't share these headers so this is a magic number. */
- struct llist_head sapi_cmds;
- uint8_t sapis_dl[23];
- uint8_t sapis_ul[23];
- struct lapdm_channel lapdm_ch;
- struct llist_head dl_tch_queue;
- struct {
- /* bitmask of all SI that are present/valid in si_buf */
- uint32_t valid;
- /* bitmask of all SI that do not mirror the BTS-global SI values */
- uint32_t overridden;
- uint32_t last;
- /* buffers where we put the pre-computed SI:
- SI2Q_MAX_NUM is the max number of SI2quater messages (see 3GPP TS 44.018) */
- sysinfo_buf_t buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
- } si;
- struct {
- uint8_t flags;
- /* RSL measurment result number, 0 at lchan_act */
- uint8_t res_nr;
- /* current Tx power level of the BTS */
- uint8_t bts_tx_pwr;
- /* number of measurements stored in array below */
- uint8_t num_ul_meas;
- struct bts_ul_meas uplink[MAX_NUM_UL_MEAS];
- /* last L1 header from the MS */
- uint8_t l1_info[2];
- struct gsm_meas_rep_unidir ul_res;
- int16_t ms_toa256;
- /* Frame number of the last measurement indication receceived */
- uint32_t last_fn;
- /* Osmocom extended measurement results, see LC_UL_M_F_EXTD_VALID */
- struct {
- /* minimum value of toa256 during measurement period */
- int16_t toa256_min;
- /* maximum value of toa256 during measurement period */
- int16_t toa256_max;
- /* standard deviation of toa256 value during measurement period */
- uint16_t toa256_std_dev;
- } ext;
- } meas;
- struct {
- struct amr_multirate_conf amr_mr;
- struct {
- struct osmo_fsm_inst *dl_amr_fsm;
- /* TCH cache */
- uint8_t cache[20];
- /* FACCH cache */
- uint8_t facch[GSM_MACBLOCK_LEN];
- uint8_t len;
- uint32_t fn;
- bool is_update;
- /* set for each SID frame to detect talkspurt for codecs
- without explicit ONSET event */
- bool ul_sid;
- /* indicates if DTXd was active during DL measurement
- period */
- bool dl_active;
- /* last UL SPEECH resume flag */
- bool is_speech_resume;
- } dtx;
- uint8_t last_cmr;
- uint32_t last_fn;
- } tch;
-
- /* 3GPP TS 48.058 § 9.3.37: [0; 255] ok, -1 means invalid*/
- int16_t ms_t_offs;
- /* 3GPP TS 45.010 § 1.2 round trip propagation delay (in symbols) or -1 */
- int16_t p_offs;
-
- /* BTS-side ciphering state (rx only, bi-directional, ...) */
- uint8_t ciph_state;
- uint8_t ciph_ns;
- uint8_t loopback;
- struct {
- uint8_t active;
- uint8_t ref;
- /* T3105: PHYS INF retransmission */
- struct osmo_timer_list t3105;
- /* counts up to Ny1 */
- unsigned int phys_info_count;
- } ho;
- /* S counter for link loss */
- int s;
- /* Kind of the release/activation. E.g. RSL or PCU */
- int rel_act_kind;
- /* RTP header Marker bit to indicate beginning of speech after pause */
- bool rtp_tx_marker;
- /* power handling */
- struct {
- uint8_t current;
- uint8_t fixed;
- } ms_power_ctrl;
-
- struct msgb *pending_rel_ind_msg;
-
- /* ECU (Error Concealment Unit) state */
- struct osmo_ecu_state *ecu_state;
-};
-
-static inline uint8_t lchan_get_ta(const struct gsm_lchan *lchan)
-{
- return lchan->meas.l1_info[1];
-}
-
-extern const struct value_string lchan_ciph_state_names[];
-static inline const char *lchan_ciph_state_name(uint8_t state) {
- return get_value_string(lchan_ciph_state_names, state);
-}
-
-enum {
- TS_F_PDCH_ACTIVE = 0x1000,
- TS_F_PDCH_ACT_PENDING = 0x2000,
- TS_F_PDCH_DEACT_PENDING = 0x4000,
- TS_F_PDCH_PENDING_MASK = 0x6000 /*<
- TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING */
-} gsm_bts_trx_ts_flags;
-
-/* One Timeslot in a TRX */
-struct gsm_bts_trx_ts {
- struct gsm_bts_trx *trx;
- /* number of this timeslot at the TRX */
- uint8_t nr;
-
- enum gsm_phys_chan_config pchan;
-
- struct {
- enum gsm_phys_chan_config pchan_is;
- enum gsm_phys_chan_config pchan_want;
- struct msgb *pending_chan_activ;
- } dyn;
-
- unsigned int flags;
- struct gsm_abis_mo mo;
- struct tlv_parsed nm_attr;
- uint8_t nm_chan_comb;
- int tsc; /* -1 == use BTS TSC */
-
- struct {
- /* Parameters below are configured by VTY */
- int enabled;
- uint8_t maio;
- uint8_t hsn;
- struct bitvec arfcns;
- uint8_t arfcns_data[1024/8];
- /* This is the pre-computed MA for channel assignments */
- struct bitvec ma;
- uint8_t ma_len; /* part of ma_data that is used */
- uint8_t ma_data[8]; /* 10.5.2.21: max 8 bytes value part */
- } hopping;
-
- struct gsm_lchan lchan[TS_MAX_LCHAN];
-};
-
-/* One TRX in a BTS */
-struct gsm_bts_trx {
- /* list header in bts->trx_list */
- struct llist_head list;
-
- struct gsm_bts *bts;
- /* number of this TRX in the BTS */
- uint8_t nr;
- /* human readable name / description */
- char *description;
- /* how do we talk RSL with this TRX? */
- uint8_t rsl_tei;
- struct e1inp_sign_link *rsl_link;
-
- /* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
- struct e1inp_sign_link *oml_link;
-
- struct gsm_abis_mo mo;
- struct tlv_parsed nm_attr;
- struct {
- struct gsm_abis_mo mo;
- } bb_transc;
-
- uint16_t arfcn;
- int nominal_power; /* in dBm */
- unsigned int max_power_red; /* in actual dB */
- uint8_t max_power_backoff_8psk; /* in actual dB OC-2G only */
- uint8_t c0_idle_power_red; /* in actual dB OC-2G only */
-
-
- struct trx_power_params power_params;
- int ms_power_control;
-
- struct {
- void *l1h;
- } role_bts;
-
- union {
- struct {
- unsigned int test_state;
- uint8_t test_nr;
- struct rxlev_stats rxlev_stat;
- } ipaccess;
- };
- struct gsm_bts_trx_ts ts[TRX_NR_TS];
-};
-
-#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
-#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
-#define GSM_BTS_SI(bts, i) (void *)((bts)->si_buf[i][0])
-#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
-
-enum gsm_bts_type_variant {
- BTS_UNKNOWN,
- BTS_OSMO_LITECELL15,
- BTS_OSMO_OC2G,
- BTS_OSMO_OCTPHY,
- BTS_OSMO_SYSMO,
- BTS_OSMO_TRX,
- BTS_OSMO_VIRTUAL,
- BTS_OSMO_OMLDUMMY,
- _NUM_BTS_VARIANT
-};
-
-/* Used by OML layer for BTS Attribute reporting */
-enum bts_attribute {
- BTS_TYPE_VARIANT,
- BTS_SUB_MODEL,
- TRX_PHY_VERSION,
-};
-
-struct vty;
-
-/* N. B: always add new features to the end of the list (right before _NUM_BTS_FEAT) to avoid breaking compatibility
- with BTS compiled against earlier version of this header. Also make sure that the description strings
- gsm_bts_features_descs[] in gsm_data_shared.c are also updated accordingly! */
-enum gsm_bts_features {
- BTS_FEAT_HSCSD,
- BTS_FEAT_GPRS,
- BTS_FEAT_EGPRS,
- BTS_FEAT_ECSD,
- BTS_FEAT_HOPPING,
- BTS_FEAT_MULTI_TSC,
- BTS_FEAT_OML_ALERTS,
- BTS_FEAT_AGCH_PCH_PROP,
- BTS_FEAT_CBCH,
- BTS_FEAT_SPEECH_F_V1,
- BTS_FEAT_SPEECH_H_V1,
- BTS_FEAT_SPEECH_F_EFR,
- BTS_FEAT_SPEECH_F_AMR,
- BTS_FEAT_SPEECH_H_AMR,
- BTS_FEAT_ETWS_PN,
- _NUM_BTS_FEAT
-};
-
-extern const struct value_string gsm_bts_features_descs[];
-
-struct gsm_bts_gprs_nsvc {
- struct gsm_bts *bts;
- /* data read via VTY config file, to configure the BTS
- * via OML from BSC */
- int id;
- uint16_t nsvci;
- uint16_t local_port; /* on the BTS */
- uint16_t remote_port; /* on the SGSN */
- uint32_t remote_ip; /* on the SGSN */
-
- struct gsm_abis_mo mo;
-};
-
-enum gprs_rlc_par {
- RLC_T3142,
- RLC_T3169,
- RLC_T3191,
- RLC_T3193,
- RLC_T3195,
- RLC_N3101,
- RLC_N3103,
- RLC_N3105,
- CV_COUNTDOWN,
- T_DL_TBF_EXT, /* ms */
- T_UL_TBF_EXT, /* ms */
- _NUM_RLC_PAR
-};
-
-enum gprs_cs {
- GPRS_CS1,
- GPRS_CS2,
- GPRS_CS3,
- GPRS_CS4,
- GPRS_MCS1,
- GPRS_MCS2,
- GPRS_MCS3,
- GPRS_MCS4,
- GPRS_MCS5,
- GPRS_MCS6,
- GPRS_MCS7,
- GPRS_MCS8,
- GPRS_MCS9,
- _NUM_GRPS_CS
-};
-
-struct gprs_rlc_cfg {
- uint16_t parameter[_NUM_RLC_PAR];
- struct {
- uint16_t repeat_time; /* ms */
- uint8_t repeat_count;
- } paging;
- uint32_t cs_mask; /* bitmask of gprs_cs */
- uint8_t initial_cs;
- uint8_t initial_mcs;
-};
-
-struct bts_smscb_state {
- struct llist_head queue; /* list of struct smscb_msg */
- int queue_len;
- struct rate_ctr_group *ctrs;
- struct smscb_msg *cur_msg; /* current SMS-CB */
- struct smscb_msg *default_msg; /* default broadcast message; NULL if none */
-};
-
-/* The amount of time within which a sudden disconnect of a newly established
- * OML connection will cause a special warning to be logged. */
-#define OSMO_BTS_OML_CONN_EARLY_DISCONNECT 10 /* in seconds */
-
-/* One BTS */
-struct gsm_bts {
- /* list header in net->bts_list */
- struct llist_head list;
-
- /* number of ths BTS in network */
- uint8_t nr;
- /* human readable name / description */
- char *description;
- /* Cell Identity */
- uint16_t cell_identity;
- /* location area code of this BTS */
- uint16_t location_area_code;
- /* Base Station Identification Code (BSIC), lower 3 bits is BCC,
- * which is used as TSC for the CCCH */
- uint8_t bsic;
- /* type of BTS */
- enum gsm_bts_type_variant variant;
- enum gsm_band band;
- char version[MAX_VERSION_LENGTH];
- char sub_model[MAX_VERSION_LENGTH];
-
- /* features of a given BTS set/reported via OML */
- struct bitvec features;
- uint8_t _features_data[MAX_BTS_FEATURES/8];
-
- /* Connected PCU version (if any) */
- char pcu_version[MAX_VERSION_LENGTH];
-
- /* maximum Tx power that the MS is permitted to use in this cell */
- int ms_max_power;
-
- /* how do we talk OML with this TRX? */
- uint8_t oml_tei;
- struct e1inp_sign_link *oml_link;
- struct timespec oml_conn_established_timestamp;
-
- /* Abis network management O&M handle */
- struct abis_nm_h *nmh;
-
- struct gsm_abis_mo mo;
-
- /* number of this BTS on given E1 link */
- uint8_t bts_nr;
-
- /* DTX features of this BTS */
- enum gsm48_dtx_mode dtxu;
- bool dtxd;
-
- /* CCCH is on C0 */
- struct gsm_bts_trx *c0;
-
- struct {
- struct gsm_abis_mo mo;
- } site_mgr;
-
- /* bitmask of all SI that are present/valid in si_buf */
- uint32_t si_valid;
- /* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
- uint8_t si2q_index; /* distinguish individual SI2quater messages */
- uint8_t si2q_count; /* si2q_index for the last (highest indexed) individual SI2quater message */
- /* buffers where we put the pre-computed SI */
- sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
- /* offsets used while generating SI2quater */
- size_t e_offset;
- size_t u_offset;
- /* decoded SI3 rest octets - *unmodified* as received from BSC */
- struct osmo_gsm48_si_ro_info si3_ro_decoded;
- /* is SI3 GPRS Indicator currently disabled due to lack of PCU connection? */
- bool si3_gprs_ind_disabled;
-
- /* ip.accesss Unit ID's have Site/BTS/TRX layout */
- union {
- struct {
- uint16_t site_id;
- uint16_t bts_id;
- uint32_t flags;
- uint32_t rsl_ip;
- } ip_access;
- };
-
- /* Not entirely sure how ip.access specific this is */
- struct {
- uint8_t supports_egprs_11bit_rach;
- enum bts_gprs_mode mode;
- struct {
- struct gsm_abis_mo mo;
- uint16_t nsei;
- uint8_t timer[7];
- } nse;
- struct {
- struct gsm_abis_mo mo;
- uint16_t bvci;
- uint8_t timer[11];
- struct gprs_rlc_cfg rlc_cfg;
- } cell;
- struct gsm_bts_gprs_nsvc nsvc[2];
- uint8_t rac;
- uint8_t net_ctrl_ord;
- bool ctrl_ack_type_use_block;
- } gprs;
-
- /* RACH NM values */
- int rach_b_thresh;
- int rach_ldavg_slots;
-
- /* transceivers */
- int num_trx;
- struct llist_head trx_list;
-
- /* SI related items */
- int force_combined_si;
- int bcch_change_mark;
-
- struct rate_ctr_group *ctrs;
- bool supp_meas_toa256;
-
- struct {
- /* Interference Boundaries for OML */
- int16_t boundary[6];
- uint8_t intave;
- } interference;
- unsigned int t200_ms[7];
- unsigned int t3105_ms;
- struct {
- uint8_t overload_period;
- struct {
- /* Input parameters from OML */
- uint8_t load_ind_thresh; /* percent */
- uint8_t load_ind_period; /* seconds */
- /* Internal data */
- struct osmo_timer_list timer;
- unsigned int pch_total;
- unsigned int pch_used;
- } ccch;
- struct {
- /* Input parameters from OML */
- int16_t busy_thresh; /* in dBm */
- uint16_t averaging_slots;
- /* Internal data */
- unsigned int total; /* total nr */
- unsigned int busy; /* above busy_thresh */
- unsigned int access; /* access bursts */
- } rach;
- } load;
- uint8_t ny1;
- uint8_t max_ta;
-
- /* AGCH queuing */
- struct {
- struct llist_head queue;
- int length;
- int max_length;
-
- int thresh_level; /* Cleanup threshold in percent of max len */
- int low_level; /* Low water mark in percent of max len */
- int high_level; /* High water mark in percent of max len */
-
- /* TODO: Use a rate counter group instead */
- uint64_t dropped_msgs;
- uint64_t merged_msgs;
- uint64_t rejected_msgs;
- uint64_t agch_msgs;
- uint64_t pch_msgs;
- } agch_queue;
-
- struct {
- uint8_t *prim_notif; /* ETWS primary notification (NULL if none) */
- ssize_t prim_notif_len; /* Length of prim_notif; expected 56 bytes */
- uint8_t page_size;
- uint8_t num_pages; /* total number of pages */
- uint8_t next_page; /* next page number to be sent */
- bool pni; /* Primary Notification Identifier */
- } etws;
-
- struct paging_state *paging_state;
- char *bsc_oml_host;
- struct llist_head oml_queue;
- unsigned int rtp_jitter_buf_ms;
- bool rtp_jitter_adaptive;
-
- uint16_t rtp_port_range_start;
- uint16_t rtp_port_range_end;
- uint16_t rtp_port_range_next;
-
- struct {
- uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
- } support;
- struct {
- uint8_t tc4_ctr;
- } si;
- struct gsm_time gsm_time;
- /* frame number statistics (FN in PH-RTS.ind vs. PH-DATA.ind */
- struct {
- int32_t min; /* minimum observed */
- int32_t max; /* maximum observed */
- int32_t avg256; /* accumulator */
- uint32_t avg_count; /* number of samples accumulated in avg256 */
- uint32_t avg_window; /* number of averages in avg_count */
- } fn_stats;
- /* Radio Link Timeout counter. -1 disables timeout for
- * lab/measurement purpose */
- int radio_link_timeout;
-
- int ul_power_target; /* Uplink Rx power target */
-
- /* used by the sysmoBTS to adjust band */
- uint8_t auto_band;
-
- /* State for SMSCB (Cell Broadcast) for BASIC and EXTENDED channel */
- struct bts_smscb_state smscb_basic;
- struct bts_smscb_state smscb_extended;
- int smscb_queue_tgt_len; /* ideal/target queue length */
- int smscb_queue_max_len; /* maximum queue length */
- int smscb_queue_hyst; /* hysteresis for CBCH laod indications */
-
- int16_t min_qual_rach; /* minimum link quality (in centiBels) for Access Bursts */
- int16_t min_qual_norm; /* minimum link quality (in centiBels) for Normal Bursts */
- uint16_t max_ber10k_rach; /* Maximum permitted RACH BER in 0.01% */
-
- struct {
- char *sock_path;
- } pcu;
-
- struct {
- uint32_t last_fn;
- struct timeval tv_clock;
- struct osmo_timer_list fn_timer;
- } vbts;
-#ifdef ENABLE_OC2GBTS
- /* specific to Open Cellular 2G BTS */
- struct {
- uint8_t led_ctrl_mode; /* 0: control by BTS, 1: not control by BTS */
- struct llist_head ceased_alarm_list; /* ceased alarm list*/
- unsigned int rtp_drift_thres_ms; /* RTP timestamp drift detection threshold */
- } oc2g;
-#endif
-};
-
-
-struct gsm_bts *gsm_bts_alloc(void *talloc_ctx, uint8_t bts_num);
-struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
-
-struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
-struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
-
-enum bts_attribute str2btsattr(const char *s);
-const char *btsatttr2str(enum bts_attribute v);
-
-enum gsm_bts_type_variant str2btsvariant(const char *arg);
-const char *btsvariant2str(enum gsm_bts_type_variant v);
-
-extern const struct value_string gsm_chreq_descs[];
-const struct value_string gsm_pchant_names[13];
-const struct value_string gsm_pchant_descs[13];
-const char *gsm_pchan_name(enum gsm_phys_chan_config c);
-enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
-const char *gsm_lchant_name(enum gsm_chan_t c);
-const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
-char *gsm_trx_name(const struct gsm_bts_trx *trx);
-char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
-char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
-char *gsm_lchan_name_compute(const struct gsm_lchan *lchan);
-const char *gsm_lchans_name(enum gsm_lchan_state s);
-
-static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
-{
- return lchan->name;
-}
-
-static inline int gsm_bts_set_feature(struct gsm_bts *bts, enum gsm_bts_features feat)
-{
- OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES);
- return bitvec_set_bit_pos(&bts->features, feat, 1);
-}
-
-static inline bool gsm_bts_has_feature(const struct gsm_bts *bts, enum gsm_bts_features feat)
-{
- OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES);
- return bitvec_get_bit_pos(&bts->features, feat);
-}
-
-void gsm_abis_mo_reset(struct gsm_abis_mo *mo);
-
-struct gsm_abis_mo *
-gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst);
-
-struct gsm_nm_state *
-gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst);
-void *
-gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst);
-
-uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
-uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
- enum gsm_phys_chan_config as_pchan);
-
-/* return the gsm_lchan for the CBCH (if it exists at all) */
-struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
-
-/*
- * help with parsing regexps
- */
-int gsm_parse_reg(void *ctx, regex_t *reg, char **str,
- int argc, const char **argv) __attribute__ ((warn_unused_result));
-
-#define BSIC2BCC(bsic) ((bsic) & 0x3)
-
-static inline uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts)
-{
- if (ts->tsc != -1)
- return ts->tsc;
- else
- return ts->trx->bts->bsic & 7;
-}
-
-struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
- int *rc);
-
-enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts);
-uint8_t ts_subslots(struct gsm_bts_trx_ts *ts);
-bool ts_is_tch(struct gsm_bts_trx_ts *ts);
-const char *gsm_trx_unit_id(struct gsm_bts_trx *trx);
-
-int lchan2ecu_codec(const struct gsm_lchan *lchan);
-
-#endif
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h
index 70b45647..34259bd3 100644
--- a/include/osmo-bts/l1sap.h
+++ b/include/osmo-bts/l1sap.h
@@ -2,6 +2,9 @@
#define L1SAP_H
#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+
+#define L1SAP_MSGB_HEADROOM 128
/* lchan link ID */
#define LID_SACCH 0x40
@@ -15,16 +18,32 @@
#define L1SAP_CHAN2SS_BCCH(chan_nr) (CCCH_LCHAN)
/* logical channel from chan_nr + link_id */
-#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == LID_SACCH)
-#define L1SAP_IS_CHAN_TCHF(chan_nr) ((chan_nr & 0xf8) == 0x08)
-#define L1SAP_IS_CHAN_TCHH(chan_nr) ((chan_nr & 0xf0) == 0x10)
-#define L1SAP_IS_CHAN_SDCCH4(chan_nr) ((chan_nr & 0xe0) == 0x20)
-#define L1SAP_IS_CHAN_SDCCH8(chan_nr) ((chan_nr & 0xc0) == 0x40)
-#define L1SAP_IS_CHAN_BCCH(chan_nr) ((chan_nr & 0xf8) == 0x80)
-#define L1SAP_IS_CHAN_RACH(chan_nr) ((chan_nr & 0xf8) == 0x88)
-#define L1SAP_IS_CHAN_AGCH_PCH(chan_nr) ((chan_nr & 0xf8) == 0x90)
-#define L1SAP_IS_CHAN_PDCH(chan_nr) ((chan_nr & 0xf8) == 0xc0)
-#define L1SAP_IS_CHAN_CBCH(chan_nr) ((chan_nr & 0xf8) == 0xc8)
+#define L1SAP_IS_LINK_SACCH(link_id) \
+ ((link_id & 0xC0) == LID_SACCH)
+#define L1SAP_IS_CHAN_TCHF(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs || \
+ (chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs)
+#define L1SAP_IS_CHAN_TCHH(chan_nr) \
+ ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs || \
+ (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)
+#define L1SAP_IS_CHAN_SDCCH4(chan_nr) \
+ ((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH)
+#define L1SAP_IS_CHAN_SDCCH8(chan_nr) \
+ ((chan_nr & 0xc0) == RSL_CHAN_SDCCH8_ACCH)
+#define L1SAP_IS_CHAN_BCCH(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_BCCH)
+#define L1SAP_IS_CHAN_RACH(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_RACH)
+#define L1SAP_IS_CHAN_AGCH_PCH(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_PCH_AGCH)
+#define L1SAP_IS_CHAN_PDCH(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_OSMO_PDCH)
+#define L1SAP_IS_CHAN_CBCH(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH4) \
+ || ((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH8)
+#define L1SAP_IS_CHAN_VAMOS(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs || \
+ (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)
/* rach type from ra */
#define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70 && (ra & 0x0f) != 0x0f)
@@ -79,25 +98,55 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
uint32_t timestamp, bool marker);
/* channel control */
-int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp);
+int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr);
int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr);
int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr);
int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr);
+int l1sap_uplink_access(struct gsm_lchan *lchan, bool active);
+
+enum l1sap_common_sapi {
+ L1SAP_COMMON_SAPI_UNKNOWN,
+ /* alphabetic order */
+ L1SAP_COMMON_SAPI_AGCH,
+ L1SAP_COMMON_SAPI_BCCH,
+ L1SAP_COMMON_SAPI_CBCH,
+ L1SAP_COMMON_SAPI_FACCH_F,
+ L1SAP_COMMON_SAPI_FACCH_H,
+ L1SAP_COMMON_SAPI_FCCH,
+ L1SAP_COMMON_SAPI_IDLE,
+ L1SAP_COMMON_SAPI_NCH,
+ L1SAP_COMMON_SAPI_PACCH,
+ L1SAP_COMMON_SAPI_PAGCH,
+ L1SAP_COMMON_SAPI_PBCCH,
+ L1SAP_COMMON_SAPI_PCH,
+ L1SAP_COMMON_SAPI_PDTCH,
+ L1SAP_COMMON_SAPI_PNCH,
+ L1SAP_COMMON_SAPI_PPCH,
+ L1SAP_COMMON_SAPI_PRACH,
+ L1SAP_COMMON_SAPI_PTCCH,
+ L1SAP_COMMON_SAPI_RACH,
+ L1SAP_COMMON_SAPI_SACCH,
+ L1SAP_COMMON_SAPI_SCH,
+ L1SAP_COMMON_SAPI_SDCCH,
+ L1SAP_COMMON_SAPI_TCH_F,
+ L1SAP_COMMON_SAPI_TCH_H,
+};
-extern const struct value_string gsmtap_sapi_names[];
-extern struct gsmtap_inst *gsmtap;
-extern uint32_t gsmtap_sapi_mask;
-extern uint8_t gsmtap_sapi_acch;
+extern uint16_t l1sap_log_ctx_sapi;
+extern const struct value_string l1sap_common_sapi_names[];
int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
struct gsm_lchan *lchan, uint8_t chan_nr, uint32_t fn,
- uint16_t ber10k, int16_t lqual_cb);
+ uint16_t ber10k, int16_t lqual_cb, int8_t rssi,
+ int16_t ta_offs, uint8_t is_sub);
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
+void radio_link_timeout_reset(struct gsm_lchan *lchan);
+
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
uint8_t *data, int len);
-int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn);
+enum ccch_msgt get_ccch_msgt(struct gsm_bts_trx *trx, uint32_t fn);
#endif /* L1SAP_H */
diff --git a/include/osmo-bts/lchan.h b/include/osmo-bts/lchan.h
new file mode 100644
index 00000000..585483bd
--- /dev/null
+++ b/include/osmo-bts/lchan.h
@@ -0,0 +1,428 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/codec/codec.h>
+#include <osmocom/codec/ecu.h>
+#include <osmocom/gsm/lapdm.h>
+#include <osmocom/gsm/sysinfo.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/gsm48_rest_octets.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/meas_rep.h>
+#include <osmocom/netif/osmux.h>
+
+#include <osmo-bts/power_control.h>
+
+#define LOGPLCHAN(lchan, ss, lvl, fmt, args...) LOGP(ss, lvl, "%s " fmt, gsm_lchan_name(lchan), ## args)
+
+enum lchan_ciph_state {
+ LCHAN_CIPH_NONE,
+ LCHAN_CIPH_RX_REQ,
+ LCHAN_CIPH_RX_CONF,
+ LCHAN_CIPH_RXTX_REQ,
+ LCHAN_CIPH_RX_CONF_TX_REQ,
+ LCHAN_CIPH_RXTX_CONF,
+};
+
+/* state of a logical channel */
+enum gsm_lchan_state {
+ LCHAN_S_NONE, /* channel is not active */
+ LCHAN_S_ACT_REQ, /* channel activation requested */
+ LCHAN_S_ACTIVE, /* channel is active and operational */
+ LCHAN_S_REL_REQ, /* channel release has been requested */
+ LCHAN_S_REL_ERR, /* channel is in an error state */
+ LCHAN_S_BROKEN, /* channel is somehow unusable */
+};
+
+#define MAX_NUM_UL_MEAS 104
+#define LC_UL_M_F_L1_VALID (1 << 0)
+#define LC_UL_M_F_RES_VALID (1 << 1)
+#define LC_UL_M_F_OSMO_EXT_VALID (1 << 2)
+
+#define MAX_A5_KEY_LEN (128/8)
+#define RSL_ENC_ALG_A5(x) (x+1)
+
+struct bts_ul_meas {
+ /* BER in units of 0.01%: 10.000 == 100% ber, 0 == 0% ber */
+ uint16_t ber10k;
+ /* timing advance offset (in 1/256 bits) */
+ int16_t ta_offs_256bits;
+ /* C/I ratio in cB */
+ int16_t ci_cb;
+ /* flags */
+ uint8_t is_sub:1;
+ /* RSSI in dBm * -1 */
+ uint8_t inv_rssi;
+};
+
+struct amr_mode {
+ uint8_t mode;
+ uint8_t threshold;
+ uint8_t hysteresis;
+};
+
+struct amr_multirate_conf {
+ uint8_t gsm48_ie[2];
+ struct amr_mode mode[4];
+ uint8_t num_modes;
+};
+
+enum lchan_csd_mode {
+ LCHAN_CSD_M_NT = 0,
+ LCHAN_CSD_M_T_1200_75,
+ LCHAN_CSD_M_T_600,
+ LCHAN_CSD_M_T_1200,
+ LCHAN_CSD_M_T_2400,
+ LCHAN_CSD_M_T_4800,
+ LCHAN_CSD_M_T_9600,
+ LCHAN_CSD_M_T_14400,
+ LCHAN_CSD_M_T_29000,
+ LCHAN_CSD_M_T_32000,
+ _LCHAN_CSD_M_NUM,
+};
+
+/* State of the SAPIs in the lchan */
+enum lchan_sapi_state {
+ LCHAN_SAPI_S_NONE,
+ LCHAN_SAPI_S_REQ,
+ LCHAN_SAPI_S_ASSIGNED,
+ LCHAN_SAPI_S_REL,
+ LCHAN_SAPI_S_ERROR,
+};
+
+/* What kind of release/activation is done? A silent one for
+ * the PDCH or one triggered through RSL? */
+enum lchan_rel_act_kind {
+ LCHAN_REL_ACT_RSL,
+ LCHAN_REL_ACT_PCU,
+ LCHAN_REL_ACT_OML,
+ LCHAN_REL_ACT_REACT, /* FIXME: remove once auto-activation hack is removed from opstart_compl() (OS#1575) */
+};
+
+struct gsm_rep_facch {
+ struct msgb *msg;
+ uint32_t fn;
+};
+
+
+struct lchan_power_ctrl_state {
+ /* Dynamic Power Control parameters (NULL in static mode) */
+ const struct gsm_power_ctrl_params *dpc_params;
+ /* Measurement pre-processing state (for dynamic mode) */
+ struct gsm_power_ctrl_meas_proc_state rxlev_meas_proc;
+ struct gsm_power_ctrl_meas_proc_state rxqual_meas_proc;
+ struct gsm_power_ctrl_meas_proc_state ci_meas_proc;
+ /* Number of SACCH blocks to skip (for dynamic mode) */
+ int skip_block_num;
+
+ /* Depending on the context (MS or BS power control), fields 'current' and 'max'
+ * reflect either the MS power level (magic numbers), or BS Power reduction level
+ * (attenuation, in dB). */
+ uint8_t current;
+ uint8_t max;
+};
+
+struct lchan_ta_ctrl_state {
+ /* Number of SACCH blocks to skip */
+ int skip_block_num;
+ /* Currently requested TA */
+ uint8_t current;
+};
+
+struct gsm_lchan {
+ /* The TS that we're part of */
+ struct gsm_bts_trx_ts *ts;
+ /* The logical subslot number in the TS */
+ uint8_t nr;
+ /* The logical channel type */
+ enum gsm_chan_t type;
+ /* RSL channel rate and type */
+ enum rsl_cmod_crt rsl_chan_rt;
+ /* RSL channel mode */
+ enum rsl_cmod_spd rsl_cmode;
+ /* If TCH, traffic channel mode */
+ enum gsm48_chan_mode tch_mode;
+ enum lchan_csd_mode csd_mode;
+ /* State */
+ enum gsm_lchan_state state;
+ const char *broken_reason;
+ /* Encryption information */
+ struct {
+ uint8_t alg_id;
+ uint8_t key_len;
+ uint8_t key[MAX_A5_KEY_LEN];
+ } encr;
+
+ struct {
+ uint32_t bound_ip;
+ uint32_t connect_ip;
+ uint16_t bound_port;
+ uint16_t connect_port;
+ uint16_t conn_id;
+ uint8_t rtp_payload;
+ uint8_t rtp_payload2;
+ uint8_t speech_mode;
+ struct {
+ bool use;
+ uint8_t local_cid;
+ uint8_t remote_cid;
+ /* Rx Osmux -> RTP, one allocated & owned per lchan */
+ struct osmux_out_handle *out;
+ /* Tx RTP -> Osmux, shared by all lchans sharing a
+ * remote endp (addr+port), see "struct osmux_handle" */
+ struct osmux_in_handle *in;
+ /* Used to build rtp messages we send to osmux */
+ struct osmo_rtp_handle *rtpst;
+ } osmux;
+ struct osmo_rtp_socket *rtp_socket;
+ } abis_ip;
+
+ char *name;
+
+ /* For handover, activation is described in 3GPP TS 48.058 4.1.3 and 4.1.4:
+ *
+ * | | Access || transmit | activate
+ * | MS Power | Delay || on main channel | dl SACCH
+ * ----------------------------------------------------------------------
+ * async ho no * --> yes no
+ * async ho yes * --> yes may be started
+ * sync ho no no --> yes no
+ * sync ho yes no --> yes may be started
+ * sync ho yes yes --> yes shall be started
+ *
+ * Always start the main channel immediately.
+ * want_dl_sacch_active indicates whether dl SACCH should be activated on CHAN ACT.
+ */
+ bool want_dl_sacch_active;
+
+ /* Number of different GsmL1_Sapi_t used in osmo_bts_sysmo is 23.
+ * Currently we don't share these headers so this is a magic number. */
+ struct llist_head sapi_cmds;
+ uint8_t sapis_dl[23];
+ uint8_t sapis_ul[23];
+ struct lapdm_channel lapdm_ch;
+ /* It is required to have L3 info with DL establishment. */
+ bool l3_info_estab;
+ struct llist_head dl_tch_queue;
+ unsigned int dl_tch_queue_len;
+ struct {
+ /* bitmask of all SI that are present/valid in si_buf */
+ uint32_t valid;
+ /* bitmask of all SI that do not mirror the BTS-global SI values */
+ uint32_t overridden;
+ uint32_t last;
+ /* buffers where we put the pre-computed SI:
+ SI2Q_MAX_NUM is the max number of SI2quater messages (see 3GPP TS 44.018) */
+ sysinfo_buf_t buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
+ } si;
+ struct {
+ uint8_t flags;
+ /* RSL measurement result number, 0 at lchan_act */
+ uint8_t res_nr;
+ /* number of measurements stored in array below */
+ uint8_t num_ul_meas;
+ struct bts_ul_meas uplink[MAX_NUM_UL_MEAS];
+ /* last L1 header from the MS */
+ struct rsl_l1_info l1_info;
+ struct gsm_meas_rep_unidir ul_res;
+ int16_t ms_toa256;
+ int16_t ul_ci_cb_full;
+ int16_t ul_ci_cb_sub;
+ /* Frame number of the last measurement indication receceived */
+ uint32_t last_fn;
+ /* Osmocom extended measurement results, see LC_UL_M_F_EXTD_VALID */
+ struct {
+ /* minimum value of toa256 during measurement period */
+ int16_t toa256_min;
+ /* maximum value of toa256 during measurement period */
+ int16_t toa256_max;
+ /* standard deviation of toa256 value during measurement period */
+ uint16_t toa256_std_dev;
+ } ext;
+ /* Interference levels reported by PHY (in dBm) */
+ int16_t interf_meas_avg_dbm; /* Average value */
+ int16_t interf_meas_dbm[31]; /* Intave max is 31 */
+ uint8_t interf_meas_num;
+ uint8_t interf_band;
+ } meas;
+ struct {
+ struct amr_multirate_conf amr_mr;
+ struct {
+ struct osmo_fsm_inst *dl_amr_fsm;
+ /* TCH cache */
+ uint8_t cache[20];
+ /* FACCH cache */
+ uint8_t facch[GSM_MACBLOCK_LEN];
+ uint8_t len;
+ uint32_t fn;
+ bool is_update;
+ /* set for each SID frame to detect talkspurt for codecs
+ without explicit ONSET event */
+ bool ul_sid;
+ /* indicates if DTXd was active during DL measurement
+ period */
+ bool dl_active;
+ /* last UL SPEECH resume flag */
+ bool is_speech_resume;
+ } dtx;
+ struct {
+ bool last_rtp_input_was_sid;
+ uint8_t last_sid[GSM_FR_BYTES];
+ uint8_t last_sid_len;
+ uint8_t last_sid_age;
+ /* A SID was transmitted on the DL in the period
+ * beginning with the last transmitted speech frame
+ * or the last mandatory-Tx position, whichever was
+ * more recent. */
+ bool dl_sid_transmitted;
+ /* The current frame in the DL is taken up by FACCH */
+ bool dl_facch_stealing;
+ } dtx_fr_hr_efr;
+ uint8_t last_cmr;
+ uint32_t last_fn;
+ struct {
+ /* buffers to re-combine RLP frame from multiple Um blocks */
+ uint8_t rlp_buf_ul[576/8]; /* maximum size of RLP frame */
+ uint8_t rlp_buf_dl[576/8]; /* maximum size of RLP frame */
+ } csd;
+ } tch;
+
+ /* 3GPP TS 48.058 § 9.3.37: [0; 255] ok, -1 means invalid*/
+ int16_t ms_t_offs;
+ /* 3GPP TS 45.010 § 1.2 round trip propagation delay (in symbols) or -1 */
+ int16_t p_offs;
+
+ /* BTS-side ciphering state (rx only, bi-directional, ...) */
+ uint8_t ciph_state;
+ uint8_t ciph_ns;
+ uint8_t loopback;
+ struct {
+ uint8_t active;
+ uint8_t ref;
+ /* T3105: PHYS INF retransmission */
+ struct osmo_timer_list t3105;
+ /* counts up to Ny1 */
+ unsigned int phys_info_count;
+ } ho;
+ struct {
+ bool listener_detected;
+ uint8_t talker_active;
+ uint8_t ref;
+ uint32_t fn;
+ /* T3115: VGCS UPLINK GRANT retransmission */
+ struct osmo_timer_list t3115;
+ /* counts up to Ny2 */
+ unsigned int vgcs_ul_grant_count;
+ /* uplink free message */
+ bool uplink_free;
+ uint8_t uplink_free_msg[GSM_MACBLOCK_LEN];
+ } asci;
+ /* S counter for link loss */
+ int s;
+ /* Kind of the release/activation. E.g. RSL or PCU */
+ enum lchan_rel_act_kind rel_act_kind;
+ /* Pending RSL CHANnel ACTIVation message */
+ struct msgb *pending_chan_activ;
+ /* RTP header Marker bit to indicate beginning of speech after pause */
+ bool rtp_tx_marker;
+
+ /* TA Control Loop */
+ struct lchan_ta_ctrl_state ta_ctrl;
+
+ /* MS/BS power control state */
+ struct lchan_power_ctrl_state ms_power_ctrl;
+ struct lchan_power_ctrl_state bs_power_ctrl;
+
+ /* MS/BS Dynamic Power Control parameters */
+ struct gsm_power_ctrl_params ms_dpc_params;
+ struct gsm_power_ctrl_params bs_dpc_params;
+
+ /* Temporary ACCH overpower capabilities and state */
+ struct abis_rsl_osmo_temp_ovp_acch_cap top_acch_cap;
+ bool top_acch_active;
+
+ struct msgb *pending_rel_ind_msg;
+
+ /* ECU (Error Concealment Unit) state */
+ struct osmo_ecu_state *ecu_state;
+
+ /* Repeated ACCH capabilities and current state */
+ struct abis_rsl_osmo_rep_acch_cap rep_acch_cap;
+ struct {
+ bool dl_facch_active;
+ bool ul_sacch_active;
+ bool dl_sacch_active;
+
+ /* Message buffers to store repeation candidates */
+ struct gsm_rep_facch dl_facch[2];
+ struct msgb *dl_sacch_msg;
+ } rep_acch;
+
+ /* Cached early Immediate Assignment message: if the Immediate Assignment arrives before the channel is
+ * confirmed active, then cache it here and send it once the channel is confirmed to be active. This is related
+ * to the Early IA feature, see OsmoBSC config option 'immediate-assignment pre-chan-ack'. */
+ struct msgb *early_rr_ia;
+ struct osmo_timer_list early_rr_ia_delay;
+};
+
+extern const struct value_string lchan_ciph_state_names[];
+static inline const char *lchan_ciph_state_name(uint8_t state)
+{
+ return get_value_string(lchan_ciph_state_names, state);
+}
+
+#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
+
+void gsm_lchan_init(struct gsm_lchan *lchan, struct gsm_bts_trx_ts *ts, unsigned int lchan_nr);
+void gsm_lchan_name_update(struct gsm_lchan *lchan);
+int lchan_init_lapdm(struct gsm_lchan *lchan);
+void gsm_lchan_release(struct gsm_lchan *lchan, enum lchan_rel_act_kind rel_kind);
+int lchan_deactivate(struct gsm_lchan *lchan);
+const char *gsm_lchans_name(enum gsm_lchan_state s);
+
+static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
+{
+ return lchan->name;
+}
+
+uint8_t *lchan_sacch_get(struct gsm_lchan *lchan);
+
+uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
+uint8_t gsm_lchan2chan_nr_rsl(const struct gsm_lchan *lchan);
+uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
+ enum gsm_phys_chan_config as_pchan);
+
+void gsm_lchan_interf_meas_push(struct gsm_lchan *lchan, int dbm);
+void gsm_lchan_interf_meas_calc_avg(struct gsm_lchan *lchan);
+
+int lchan2ecu_codec(const struct gsm_lchan *lchan);
+
+void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state);
+
+int lchan_rtp_socket_create(struct gsm_lchan *lchan, const char *bind_ip);
+int lchan_rtp_socket_connect(struct gsm_lchan *lchan, const struct in_addr *ia, uint16_t connect_port);
+void lchan_rtp_socket_free(struct gsm_lchan *lchan);
+
+void lchan_dl_tch_queue_enqueue(struct gsm_lchan *lchan, struct msgb *msg, unsigned int limit);
+
+static inline bool lchan_is_dcch(const struct gsm_lchan *lchan)
+{
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ case GSM_LCHAN_TCH_F:
+ case GSM_LCHAN_TCH_H:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#define lchan_is_tch(lchan) \
+ ((lchan)->type == GSM_LCHAN_TCH_F || (lchan)->type == GSM_LCHAN_TCH_H)
diff --git a/include/osmo-bts/logging.h b/include/osmo-bts/logging.h
index 852c3836..ce08e47c 100644
--- a/include/osmo-bts/logging.h
+++ b/include/osmo-bts/logging.h
@@ -20,7 +20,8 @@ enum {
DLOOP,
DABIS,
DRTP,
- DSUM,
+ DOSMUX,
+ DASCI,
};
extern const struct log_info bts_log_info;
@@ -37,4 +38,12 @@ extern const struct log_info bts_log_info;
#define DEBUGPFN(ss, fn, fmt, args...) \
LOGP(ss, LOGL_DEBUG, "%s " fmt, gsm_fn_as_gsmtime_str(fn), ## args)
+/* LOGP with lchan + frame number prefix */
+#define LOGPLCFN(lchan, fn, ss, lvl, fmt, args...) \
+ LOGP(ss, lvl, "%s %s " fmt, gsm_lchan_name(lchan), gsm_fn_as_gsmtime_str(fn), ## args)
+
+/* LOGP with lchan + gsm_time prefix */
+#define LOGPLCGT(lchan, gt, ss, lvl, fmt, args...) \
+ LOGP(ss, lvl, "%s %s " fmt, gsm_lchan_name(lchan), osmo_dump_gsmtime(gt), ## args)
+
#endif /* _LOGGING_H */
diff --git a/include/osmo-bts/measurement.h b/include/osmo-bts/measurement.h
index 4f04ffa2..ad86d8de 100644
--- a/include/osmo-bts/measurement.h
+++ b/include/osmo-bts/measurement.h
@@ -4,16 +4,22 @@
#define MEAS_MAX_TIMING_ADVANCE 63
#define MEAS_MIN_TIMING_ADVANCE 0
-int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn);
+int lchan_new_ul_meas(struct gsm_lchan *lchan,
+ const struct bts_ul_meas *ulm,
+ uint32_t fn);
int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn);
-int lchan_meas_process_measurement(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn);
+int lchan_meas_process_measurement(struct gsm_lchan *lchan,
+ const struct bts_ul_meas *ulm,
+ uint32_t fn);
void lchan_meas_reset(struct gsm_lchan *lchan);
-bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn, bool is_amr_sid_update);
+bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn);
int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn);
+void lchan_meas_handle_sacch(struct gsm_lchan *lchan, struct msgb *msg);
+
#endif
diff --git a/include/osmo-bts/msg_utils.h b/include/osmo-bts/msg_utils.h
index 7ddbe88f..fb8e11a5 100644
--- a/include/osmo-bts/msg_utils.h
+++ b/include/osmo-bts/msg_utils.h
@@ -22,6 +22,9 @@ struct msgb;
/* Access 3rd part of msgb control buffer */
#define rtpmsg_ts(x) ((x)->cb[2])
+/* Access 4th part of msgb control buffer */
+#define rtpmsg_is_rfc5993_sid(x) ((x)->cb[3])
+
/**
* Classification of OML message. ETSI for plain GSM 12.21
* messages and IPA/Osmo for manufacturer messages.
diff --git a/include/osmo-bts/nm_common_fsm.h b/include/osmo-bts/nm_common_fsm.h
new file mode 100644
index 00000000..dadf806e
--- /dev/null
+++ b/include/osmo-bts/nm_common_fsm.h
@@ -0,0 +1,123 @@
+/* Header for all NM FSM. Following 3GPP TS 12.21 Figure 2/GSM 12.21:
+ GSM 12.21 Objects' Operational state and availability status behaviour during initialization */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+
+/* Common */
+enum nm_fsm_events {
+ NM_EV_SW_ACT,
+ NM_EV_RX_SETATTR, /* data: struct nm_fsm_ev_setattr_data */
+ NM_EV_RX_OPSTART,
+ NM_EV_OPSTART_ACK,
+ NM_EV_OPSTART_NACK,
+ NM_EV_SHUTDOWN_START,
+ NM_EV_SHUTDOWN_FINISH,
+ NM_EV_OML_UP,
+ NM_EV_RSL_UP, /* RadioCarrier and BaseBand Transceiver only */
+ NM_EV_RSL_DOWN, /* RadioCarrier and BaseBand Transceiver only */
+ NM_EV_PHYLINK_UP, /* RadioCarrier and BaseBand Transceiver only */
+ NM_EV_PHYLINK_DOWN, /* RadioCarrier and BaseBand Transceiver only */
+ NM_EV_DISABLE, /* RadioCarrier and BaseBand Transceiver only */
+ NM_EV_BBTRANSC_ENABLED, /* Radio Channel only */
+ NM_EV_BBTRANSC_DISABLED, /* Radio Channel only */
+ NM_EV_RCARRIER_ENABLED, /* Radio Channel only */
+ NM_EV_RCARRIER_DISABLED, /* Radio Channel only */
+};
+extern const struct value_string nm_fsm_event_names[];
+
+struct nm_fsm_ev_setattr_data {
+ const struct msgb *msg;
+};
+
+
+/* BTS SiteManager */
+enum nm_bts_sm_op_fsm_states {
+ NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BTS_SM_ST_OP_DISABLED_OFFLINE,
+ NM_BTS_SM_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bts_sm_fsm;
+
+/* BTS */
+enum nm_bts_op_fsm_states {
+ NM_BTS_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BTS_ST_OP_DISABLED_OFFLINE,
+ NM_BTS_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bts_fsm;
+
+/* BaseBand Transceiver */
+enum nm_bb_transc_op_fsm_states {
+ NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BBTRANSC_ST_OP_DISABLED_OFFLINE,
+ NM_BBTRANSC_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bb_transc_fsm;
+
+/* Radio Carrier */
+enum nm_rcarrier_op_fsm_states {
+ NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED,
+ NM_RCARRIER_ST_OP_DISABLED_OFFLINE,
+ NM_RCARRIER_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_rcarrier_fsm;
+
+/* Radio channel */
+enum nm_chan_op_fsm_states {
+ NM_CHAN_ST_OP_DISABLED_NOTINSTALLED,
+ NM_CHAN_ST_OP_DISABLED_DEPENDENCY,
+ NM_CHAN_ST_OP_DISABLED_OFFLINE,
+ NM_CHAN_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_chan_fsm;
+
+/* GPRS NSE */
+enum nm_gprs_nse_op_fsm_states {
+ NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_NSE_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_nse_fsm;
+
+/* GPRS NSVC */
+enum nm_gprs_nsvc_op_fsm_states {
+ NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_NSVC_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_nsvc_fsm;
+
+/* GPRS CELL */
+enum nm_gprs_cell_op_fsm_states {
+ NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_CELL_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_cell_fsm;
diff --git a/include/osmo-bts/notification.h b/include/osmo-bts/notification.h
new file mode 100644
index 00000000..e53d718b
--- /dev/null
+++ b/include/osmo-bts/notification.h
@@ -0,0 +1,61 @@
+/* Maintain and generate ASCI notifications */
+
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Harald Welte
+ *
+ * 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 Affero 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/>.
+ */
+
+#pragma once
+
+/* one [concurrent] ASCI (VBS/VGCS) notification */
+struct asci_notification {
+ struct llist_head list; /* linked to bts->asci.notifications */
+
+ /* Group call reference (TS 24.008 10.5.1.9 "Descriptive group or broadcast call reference") */
+ uint8_t group_call_ref[5];
+
+ /* Group Channel Description (TS 44.018 10.5.2.14b) */
+ struct {
+ bool present;
+ uint8_t value[255];
+ uint8_t len;
+ } chan_desc;
+
+ /* NCH DRX Information (TS 48.058 9.3.47) */
+ struct {
+ bool present;
+ struct rsl_ie_nch_drx_info value;
+ } nch_drx_info;
+};
+
+int bts_asci_notification_add(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
+ uint8_t chan_desc_len, const struct rsl_ie_nch_drx_info *nch_drx_info);
+
+int bts_asci_notification_del(struct gsm_bts *bts, const uint8_t *group_call_ref);
+
+int bts_asci_notification_reset(struct gsm_bts *bts);
+
+const struct asci_notification *bts_asci_notification_get_next(struct gsm_bts *bts);
+
+void append_group_call_information(struct bitvec *bv, const uint8_t *gcr, const uint8_t *ch_desc, uint8_t ch_desc_len);
+
+int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf);
+int bts_asci_notify_facch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf, const uint8_t *group_call_ref,
+ const uint8_t *chan_desc, uint8_t chan_desc_len);
diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h
index b92a9745..41cdaf50 100644
--- a/include/osmo-bts/oml.h
+++ b/include/osmo-bts/oml.h
@@ -8,8 +8,35 @@ struct gsm_abis_mo;
struct msgb;
struct gsm_lchan;
+/* Network Management State */
+struct gsm_nm_state {
+ enum abis_nm_op_state operational;
+ enum abis_nm_adm_state administrative;
+ enum abis_nm_avail_state availability;
+};
-int oml_init(struct gsm_abis_mo *mo);
+struct gsm_abis_mo {
+ /* A-bis OML Object Class */
+ uint8_t obj_class;
+ /* is there still some procedure pending? */
+ uint8_t procedure_pending;
+ /* A-bis OML Object Instance */
+ struct abis_om_obj_inst obj_inst;
+ /* human-readable name */
+ const char *name;
+ /* NM State */
+ struct gsm_nm_state nm_state;
+ /* Attributes configured in this MO */
+ struct tlv_parsed *nm_attr;
+ /* BTS to which this MO belongs */
+ struct gsm_bts *bts;
+ /* NM BTS Site Manager FSM */
+ struct osmo_fsm_inst *fi;
+ bool setattr_success;
+ bool opstart_success;
+};
+
+int oml_init(void);
int down_oml(struct gsm_bts *bts, struct msgb *msg);
struct msgb *oml_msgb_alloc(void);
@@ -21,7 +48,7 @@ int oml_mo_statechg_ack(const struct gsm_abis_mo *mo);
int oml_mo_statechg_nack(const struct gsm_abis_mo *mo, uint8_t nack_cause);
/* Change the state and send STATE CHG REP */
-int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state);
+int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state, int adm_state);
/* First initialization of MO, does _not_ generate state changes */
void oml_mo_state_init(struct gsm_abis_mo *mo, int op_state, int avail_state);
@@ -36,14 +63,26 @@ int oml_tx_state_changed(const struct gsm_abis_mo *mo);
int oml_mo_tx_sw_act_rep(const struct gsm_abis_mo *mo);
int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause);
+int oml_fom_ack_nack_copy_msg(const struct msgb *old_msg, uint8_t cause);
int oml_mo_fom_ack_nack(const struct gsm_abis_mo *mo, uint8_t orig_msg_type,
uint8_t cause);
-extern const unsigned int oml_default_t200_ms[7];
+extern const uint32_t oml_default_t200_fn[7];
/* Transmit failure event report */
int oml_tx_failure_event_rep(const struct gsm_abis_mo *mo, enum abis_nm_severity severity,
uint16_t cause_value, const char *fmt, ...);
+void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
+ uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3);
+
+struct gsm_abis_mo *gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
+ const struct abis_om_obj_inst *obj_inst,
+ enum abis_nm_nack_cause *c);
+
+void *gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
+ const struct abis_om_obj_inst *obj_inst,
+ enum abis_nm_nack_cause *c);
+
#endif // _OML_H */
diff --git a/include/osmo-bts/osmux.h b/include/osmo-bts/osmux.h
new file mode 100644
index 00000000..9cdbea19
--- /dev/null
+++ b/include/osmo-bts/osmux.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <osmocom/core/select.h>
+#include <osmocom/netif/osmux.h>
+
+struct gsm_bts;
+struct gsm_lchan;
+
+enum osmux_usage {
+ OSMUX_USAGE_OFF = 0,
+ OSMUX_USAGE_ON = 1,
+ OSMUX_USAGE_ONLY = 2,
+};
+
+struct osmux_state {
+ enum osmux_usage use;
+ char *local_addr;
+ uint16_t local_port;
+ struct osmo_fd fd;
+ uint8_t batch_factor;
+ unsigned int batch_size;
+ bool dummy_padding;
+ struct llist_head osmux_handle_list;
+};
+
+/* Contains a "struct osmux_in_handle" towards a specific peer (remote IPaddr+port) */
+struct osmux_handle {
+ struct llist_head head;
+ struct gsm_bts *bts;
+ struct osmux_in_handle *in;
+ struct osmo_sockaddr rem_addr;
+ int refcnt;
+};
+
+int bts_osmux_init(struct gsm_bts *bts);
+void bts_osmux_release(struct gsm_bts *bts);
+int bts_osmux_open(struct gsm_bts *bts);
+
+int lchan_osmux_init(struct gsm_lchan *lchan, uint8_t rtp_payload);
+void lchan_osmux_release(struct gsm_lchan *lchan);
+int lchan_osmux_connect(struct gsm_lchan *lchan);
+bool lchan_osmux_connected(const struct gsm_lchan *lchan);
+int lchan_osmux_send_frame(struct gsm_lchan *lchan, const uint8_t *payload,
+ unsigned int payload_len, unsigned int duration, bool marker);
+
+int lchan_osmux_skipped_frame(struct gsm_lchan *lchan, unsigned int duration);
diff --git a/include/osmo-bts/paging.h b/include/osmo-bts/paging.h
index 7fc0bf05..e74ba3c9 100644
--- a/include/osmo-bts/paging.h
+++ b/include/osmo-bts/paging.h
@@ -7,6 +7,55 @@
struct paging_state;
struct gsm_bts;
+struct asci_notification;
+
+/* abstract representation of P1 rest octets; we only implement those parts we need for now */
+struct p1_rest_octets {
+ struct {
+ bool present;
+ uint8_t nln;
+ uint8_t nln_status;
+ } nln_pch;
+ bool packet_page_ind[2];
+ bool r8_present;
+ struct {
+ bool prio_ul_access;
+ bool etws_present;
+ struct {
+ bool is_first;
+ uint8_t page_nr;
+ const uint8_t *page;
+ size_t page_bytes;
+ } etws;
+ } r8;
+};
+
+/* abstract representation of P2 rest octets; we only implement those parts we need for now */
+struct p2_rest_octets {
+ struct {
+ bool present;
+ uint8_t cn3;
+ } cneed;
+ struct {
+ bool present;
+ uint8_t nln;
+ uint8_t nln_status;
+ } nln_pch;
+};
+
+/* abstract representation of P3 rest octets; we only implement those parts we need for now */
+struct p3_rest_octets {
+ struct {
+ bool present;
+ uint8_t cn3;
+ uint8_t cn4;
+ } cneed;
+ struct {
+ bool present;
+ uint8_t nln;
+ uint8_t nln_status;
+ } nln_pch;
+};
/* initialize paging code */
struct paging_state *paging_init(struct gsm_bts *bts,
@@ -35,9 +84,15 @@ int paging_si_update(struct paging_state *ps, struct gsm48_control_channel_descr
int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
const uint8_t *identity_lv, uint8_t chan_needed);
-/* Add an IMM.ASS message to the paging queue */
-int paging_add_imm_ass(struct paging_state *ps, const uint8_t *data,
- uint8_t len);
+/* Add a ready formatted MAC block message to the paging queue, this can be an IMMEDIATE ASSIGNMENT, or a
+ * PAGING COMMAND (from the PCU) */
+int paging_add_macblock(struct paging_state *ps, uint32_t msg_id, const char *imsi, bool confirm, const uint8_t *macblock);
+
+/* Paging rest octests */
+void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro,
+ const struct asci_notification *notif);
+void append_p2_rest_octets(struct bitvec *bv, const struct p2_rest_octets *p2ro);
+void append_p3_rest_octets(struct bitvec *bv, const struct p3_rest_octets *p3ro);
/* generate paging message for given gsm time */
int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt,
diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h
index 114f87d1..3563c5ba 100644
--- a/include/osmo-bts/pcu_if.h
+++ b/include/osmo-bts/pcu_if.h
@@ -1,24 +1,33 @@
#ifndef _PCU_IF_H
#define _PCU_IF_H
+#include <osmo-bts/pcuif_proto.h>
+
+struct gsm_bts_sm;
+
extern int pcu_direct;
+#define PCUIF_HDR_SIZE (sizeof(struct gsm_pcu_if) - sizeof(((struct gsm_pcu_if *)0)->u))
+
int pcu_tx_info_ind(void);
-int pcu_tx_si13(const struct gsm_bts *bts, bool enable);
+int pcu_tx_si(const struct gsm_bts *bts, enum osmo_sysinfo_type si_type, bool enable);
int pcu_tx_app_info_req(struct gsm_bts *bts, uint8_t app_type, uint8_t len, const uint8_t *app_data);
int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
uint16_t arfcn, uint8_t block_nr);
int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len,
int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual);
-int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn,
- uint8_t is_11bit, enum ph_burst_type burst_type);
+int pcu_tx_rach_ind(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
+ int16_t qta, uint16_t ra, uint32_t fn, uint8_t is_11bit,
+ enum ph_burst_type burst_type, uint8_t sapi);
int pcu_tx_time_ind(uint32_t fn);
+int pcu_tx_interf_ind(const struct gsm_bts_trx *trx, uint32_t fn);
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed);
-int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len);
+int pcu_tx_data_cnf(uint32_t msg_id, uint8_t sapi);
int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id, uint8_t cause);
+int pcu_sock_send(struct msgb *msg);
-int pcu_sock_init(const char *path);
+int pcu_sock_init(const char *path, int qlength_max);
void pcu_sock_exit(void);
bool pcu_connected(void);
diff --git a/include/osmo-bts/pcuif_proto.h b/include/osmo-bts/pcuif_proto.h
index 2d24c434..04936af0 100644
--- a/include/osmo-bts/pcuif_proto.h
+++ b/include/osmo-bts/pcuif_proto.h
@@ -2,40 +2,42 @@
#define _PCUIF_PROTO_H
#include <osmocom/gsm/l1sap.h>
+#include <arpa/inet.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
#define PCU_SOCK_DEFAULT "/tmp/pcu_bts"
-#define PCU_IF_VERSION 0x09
+#define PCU_IF_VERSION 0x0c
#define TXT_MAX_LEN 128
/* msg_type */
#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */
-#define PCU_IF_MSG_DATA_CNF 0x01 /* confirm (e.g. transmission on PCH) */
#define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */
#define PCU_IF_MSG_SUSP_REQ 0x03 /* BTS forwards GPRS SUSP REQ to PCU */
-#define PCU_IF_MSG_APP_INFO_REQ 0x04 /* BTS asks PCU to tranmit APP INFO via PACCH */
+#define PCU_IF_MSG_APP_INFO_REQ 0x04 /* BTS asks PCU to transmit APP INFO via PACCH */
#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */
-#define PCU_IF_MSG_DATA_CNF_DT 0x11 /* confirm (with direct tlli) */
+#define PCU_IF_MSG_DATA_CNF_2 0x11 /* confirm (using message id) */
#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */
#define PCU_IF_MSG_INFO_IND 0x32 /* retrieve BTS info */
#define PCU_IF_MSG_ACT_REQ 0x40 /* activate/deactivate PDCH */
#define PCU_IF_MSG_TIME_IND 0x52 /* GSM time indication */
+#define PCU_IF_MSG_INTERF_IND 0x53 /* interference report */
#define PCU_IF_MSG_PAG_REQ 0x60 /* paging request */
#define PCU_IF_MSG_TXT_IND 0x70 /* Text indication for BTS */
+#define PCU_IF_MSG_CONTAINER 0x80 /* Transparent container message */
/* sapi */
#define PCU_IF_SAPI_RACH 0x01 /* channel request on CCCH */
-#define PCU_IF_SAPI_AGCH 0x02 /* assignment on AGCH */
-#define PCU_IF_SAPI_PCH 0x03 /* paging/assignment on PCH */
#define PCU_IF_SAPI_BCCH 0x04 /* SI on BCCH */
#define PCU_IF_SAPI_PDTCH 0x05 /* packet data/control/ccch block */
#define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */
#define PCU_IF_SAPI_PTCCH 0x07 /* packet TA control channel */
-#define PCU_IF_SAPI_AGCH_DT 0x08 /* assignment on AGCH but with additional TLLI */
+#define PCU_IF_SAPI_PCH_2 0x08 /* assignment on PCH (confirmed using message id) */
+#define PCU_IF_SAPI_AGCH_2 0x09 /* assignment on AGCH (confirmed using message id) */
/* flags */
#define PCU_IF_FLAG_ACTIVE (1 << 0)/* BTS is active */
-#define PCU_IF_FLAG_SYSMO (1 << 1)/* access PDCH of sysmoBTS directly */
+#define PCU_IF_FLAG_DIRECT_PHY (1 << 1)/* access PHY directly via dedicated hardware support */
#define PCU_IF_FLAG_CS1 (1 << 16)
#define PCU_IF_FLAG_CS2 (1 << 17)
#define PCU_IF_FLAG_CS3 (1 << 18)
@@ -50,6 +52,25 @@
#define PCU_IF_FLAG_MCS8 (1 << 27)
#define PCU_IF_FLAG_MCS9 (1 << 28)
+/* NSVC address type */
+#define PCU_IF_ADDR_TYPE_UNSPEC 0x00 /* No address - empty entry */
+#define PCU_IF_ADDR_TYPE_IPV4 0x04 /* IPv4 address */
+#define PCU_IF_ADDR_TYPE_IPV6 0x29 /* IPv6 address */
+
+/* BTS model */
+enum gsm_pcuif_bts_model {
+ PCU_IF_BTS_MODEL_UNSPEC,
+ PCU_IF_BTS_MODEL_LC15,
+ PCU_IF_BTS_MODEL_OC2G,
+ PCU_IF_BTS_MODEL_OCTPHY,
+ PCU_IF_BTS_MODEL_SYSMO,
+ PCU_IF_BTS_MODEL_TRX,
+ PCU_IF_BTS_MODEL_RBS,
+};
+
+#define PCU_IF_NUM_NSVC 2
+#define PCU_IF_NUM_TRX 8
+
enum gsm_pcu_if_text_type {
PCU_VERSION,
PCU_OML_ALERT,
@@ -75,19 +96,10 @@ struct gsm_pcu_if_data {
int16_t lqual_cb; /* !< \brief Link quality in centiBel */
} __attribute__ ((packed));
-/* data confirmation with direct tlli (instead of raw mac block with tlli) */
-struct gsm_pcu_if_data_cnf_dt {
+/* data confirmation with message id (instead of raw mac block) */
+struct gsm_pcu_if_data_cnf {
uint8_t sapi;
- uint32_t tlli;
- uint32_t fn;
- uint16_t arfcn;
- uint8_t trx_nr;
- uint8_t ts_nr;
- uint8_t block_nr;
- int8_t rssi;
- uint16_t ber10k; /* !< \brief BER in units of 0.01% */
- int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */
- int16_t lqual_cb; /* !< \brief Link quality in centiBel */
+ uint32_t msg_id;
} __attribute__ ((packed));
struct gsm_pcu_if_rts_req {
@@ -108,20 +120,31 @@ struct gsm_pcu_if_rach_ind {
uint16_t arfcn;
uint8_t is_11bit;
uint8_t burst_type;
+ uint8_t trx_nr;
+ uint8_t ts_nr;
+} __attribute__ ((packed));
+
+struct gsm_pcu_if_info_trx_ts {
+ uint8_t tsc;
+ uint8_t hopping;
+ uint8_t hsn;
+ uint8_t maio;
+ uint8_t ma_bit_len;
+ uint8_t ma[8];
} __attribute__ ((packed));
struct gsm_pcu_if_info_trx {
uint16_t arfcn;
- uint8_t pdch_mask; /* PDCH channels per TS */
+ uint8_t pdch_mask; /* PDCH timeslot mask */
uint8_t spare;
- uint8_t tsc[8]; /* TSC per channel */
uint32_t hlayer1;
+ struct gsm_pcu_if_info_trx_ts ts[8];
} __attribute__ ((packed));
struct gsm_pcu_if_info_ind {
uint32_t version;
uint32_t flags;
- struct gsm_pcu_if_info_trx trx[8]; /* TRX infos per BTS */
+ struct gsm_pcu_if_info_trx trx[PCU_IF_NUM_TRX]; /* TRX infos per BTS */
uint8_t bsic;
/* RAI */
uint16_t mcc, mnc;
@@ -150,10 +173,15 @@ struct gsm_pcu_if_info_ind {
uint8_t initial_cs;
uint8_t initial_mcs;
/* NSVC */
- uint16_t nsvci[2];
- uint16_t local_port[2];
- uint16_t remote_port[2];
- uint32_t remote_ip[2];
+ uint16_t nsvci[PCU_IF_NUM_NSVC];
+ uint16_t local_port[PCU_IF_NUM_NSVC];
+ uint16_t remote_port[PCU_IF_NUM_NSVC];
+ uint8_t address_type[PCU_IF_NUM_NSVC];
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } remote_ip[PCU_IF_NUM_NSVC];
+ uint8_t bts_model; /* enum gsm_pcuif_bts_model */
} __attribute__ ((packed));
struct gsm_pcu_if_act_req {
@@ -187,6 +215,48 @@ struct gsm_pcu_if_susp_req {
uint8_t cause;
} __attribute__ ((packed));
+/* Interference measurements on PDCH timeslots */
+struct gsm_pcu_if_interf_ind {
+ uint8_t trx_nr;
+ uint8_t spare[3];
+ uint32_t fn;
+ uint8_t interf[8];
+} __attribute__ ((packed));
+
+/* Contains messages transmitted BSC<->PCU, potentially forwarded by BTS via IPA/PCU */
+struct gsm_pcu_if_container {
+ uint8_t msg_type;
+ uint8_t spare;
+ uint16_t length; /* network byte order */
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via PCH. The struct is sent as a data request
+ * (data_req) under SAPI PCU_IF_SAPI_PCH_2. */
+struct gsm_pcu_if_pch {
+ /* message id as reference for confirmation */
+ uint32_t msg_id;
+ /* IMSI (to derive paging group) */
+ char imsi[OSMO_IMSI_BUF_SIZE];
+ /* GSM mac-block (with immediate assignment message) */
+ uint8_t data[GSM_MACBLOCK_LEN];
+ /* Set to true in case the receiving end must send a confirmation
+ * when the MAC block (data) has been sent. */
+ bool confirm;
+} __attribute__((packed));
+
+/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via AGCH. The struct is sent as a data request
+ * (data_req) under SAPI PCU_IF_SAPI_AGCH_2. */
+struct gsm_pcu_if_agch {
+ /* message id as reference for confirmation */
+ uint32_t msg_id;
+ /* GSM mac-block (with immediate assignment message) */
+ uint8_t data[GSM_MACBLOCK_LEN];
+ /* Set to true in case the receiving end must send a confirmation
+ * when the MAC block (data) has been sent. */
+ bool confirm;
+} __attribute__((packed));
+
struct gsm_pcu_if {
/* context based information */
uint8_t msg_type; /* message type */
@@ -195,8 +265,7 @@ struct gsm_pcu_if {
union {
struct gsm_pcu_if_data data_req;
- struct gsm_pcu_if_data data_cnf;
- struct gsm_pcu_if_data_cnf_dt data_cnf_dt;
+ struct gsm_pcu_if_data_cnf data_cnf2;
struct gsm_pcu_if_data data_ind;
struct gsm_pcu_if_susp_req susp_req;
struct gsm_pcu_if_rts_req rts_req;
@@ -207,6 +276,8 @@ struct gsm_pcu_if {
struct gsm_pcu_if_time_ind time_ind;
struct gsm_pcu_if_pag_req pag_req;
struct gsm_pcu_if_app_info_req app_info_req;
+ struct gsm_pcu_if_interf_ind interf_ind;
+ struct gsm_pcu_if_container container;
} u;
} __attribute__ ((packed));
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
index 3bf51597..862ed48f 100644
--- a/include/osmo-bts/phy_link.h
+++ b/include/osmo-bts/phy_link.h
@@ -5,11 +5,12 @@
#include <osmocom/core/linuxlist.h>
#include <osmo-bts/scheduler.h>
+#include <osmo-bts/bts_trx.h>
#include <linux/if_packet.h>
#include "btsconfig.h"
-struct gsm_bts_trx;
+
struct virt_um_inst;
enum phy_link_type {
@@ -44,16 +45,17 @@ struct phy_link {
uint16_t base_port_local;
uint16_t base_port_remote;
struct osmo_fd trx_ofd_clk;
- bool trx_ta_loop;
- bool trx_ms_power_loop;
- int8_t trx_target_rssi;
uint32_t clock_advance;
uint32_t rts_advance;
bool use_legacy_setbsic;
- uint8_t trxd_hdr_ver_max; /* Maximum TRXD header version to negotiate */
+ uint8_t trxd_pdu_ver_max; /* Maximum TRXD PDU version to negotiate */
+ bool powered; /* last POWERON (true) or POWEROFF (false) confirmed */
+ bool poweron_sent; /* is there a POWERON in transit? */
+ bool poweroff_sent; /* is there a POWEROFF in transit? */
} osmotrx;
struct {
char *mcast_dev; /* Network device for multicast */
+ int ttl; /* TTL of transmitted udp multicast */
char *bts_mcast_group; /* BTS are listening to this group */
uint16_t bts_mcast_port;
char *ms_mcast_group; /* MS are listening to this group */
@@ -96,7 +98,7 @@ struct phy_instance {
struct phy_link *phy_link;
/* back-pointer to the TRX to which we're associated */
- struct gsm_bts_trx *trx;
+ struct gsm_bts_trx *trx; /* NOTE: may be NULL! */
union {
struct {
@@ -111,12 +113,9 @@ struct phy_instance {
} sysmobts;
struct {
struct trx_l1h *hdl;
- bool sw_act_reported;
+ struct trx_dl_burst_req br[TRX_NR_TS];
} osmotrx;
struct {
- struct l1sched_trx sched;
- } virt;
- struct {
/* logical transceiver number within one PHY */
uint32_t trx_id;
/* trx lock state variable */
@@ -135,6 +134,7 @@ struct phy_instance {
uint8_t dsp_alive_period; /* DSP alive timer period */
uint8_t tx_pwr_adj_mode; /* 0: no auto adjust power, 1: auto adjust power using RMS detector */
uint8_t tx_pwr_red_8psk; /* 8-PSK maximum Tx power reduction level in dB */
+ uint8_t tx_c0_idle_pwr_red; /* C0 idle slot Tx power reduction level in dB */
} lc15;
struct {
/* configuration */
@@ -156,23 +156,26 @@ struct phy_instance {
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);
+const char *phy_link_name(const struct phy_link *plink);
void phy_link_state_set(struct phy_link *plink, enum phy_link_state state);
+enum phy_link_state phy_link_state_get(struct phy_link *plink);
+const char *phy_link_state_name(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_by_num(const 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);
+const char *phy_instance_name(const struct phy_instance *pinst);
static inline struct phy_instance *trx_phy_instance(const struct gsm_bts_trx *trx)
{
OSMO_ASSERT(trx);
- return trx->role_bts.l1h;
+ return trx->pinst;
}
int bts_model_phy_link_open(struct phy_link *plink);
+int bts_model_phy_link_close(struct phy_link *plink);
+#define LOGPPHL(plink, section, lvl, fmt, args...) LOGP(section, lvl, "%s: " fmt, phy_link_name(plink), ##args)
#define LOGPPHI(pinst, section, lvl, fmt, args...) LOGP(section, lvl, "%s: " fmt, phy_instance_name(pinst), ##args)
diff --git a/include/osmo-bts/power_control.h b/include/osmo-bts/power_control.h
index 43d4b591..0764ba76 100644
--- a/include/osmo-bts/power_control.h
+++ b/include/osmo-bts/power_control.h
@@ -1,7 +1,90 @@
#pragma once
#include <stdint.h>
-#include <osmo-bts/gsm_data.h>
+#include <stdbool.h>
+/* MS/BS Power related measurement averaging algo */
+enum gsm_power_ctrl_meas_avg_algo {
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE = 0x00,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_UNWEIGHTED = 0x01,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_WEIGHTED = 0x02,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_MOD_MEDIAN = 0x03,
+ /* EWMA is an Osmocom specific algo */
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA = 0x04,
+};
+
+/* MS/BS Power related measurement parameters */
+struct gsm_power_ctrl_meas_params {
+ /* Thresholds (see 3GPP TS 45.008, section A.3.2.1) */
+ uint8_t lower_thresh; /* lower (decreasing) direction */
+ uint8_t upper_thresh; /* upper (increasing) direction */
+
+ /* Threshold Comparators for lower (decreasing) direction */
+ uint8_t lower_cmp_p; /* P1 for RxLev, P3 for RxQual */
+ uint8_t lower_cmp_n; /* N1 for RxLev, N3 for RxQual */
+ /* Threshold Comparators for upper (increasing) direction */
+ uint8_t upper_cmp_p; /* P2 for RxLev, P4 for RxQual */
+ uint8_t upper_cmp_n; /* N2 for RxLev, N4 for RxQual */
+
+ /* Hreqave and Hreqt (see 3GPP TS 45.008, Annex A) */
+ uint8_t h_reqave;
+ uint8_t h_reqt;
+
+ /* AVG algorithm and its specific parameters */
+ enum gsm_power_ctrl_meas_avg_algo algo;
+ union {
+ /* Exponentially Weighted Moving Average */
+ struct {
+ /* Smoothing factor: higher the value - less smoothing */
+ uint8_t alpha; /* 1 .. 99 (in %) */
+ } ewma;
+ };
+};
+
+/* MS/BS Power Control parameters */
+struct gsm_power_ctrl_params {
+ /* Minimum interval between power level changes */
+ uint8_t ctrl_interval; /* 1 step is 2 SACCH periods */
+
+ /* Power change step size (maximum) */
+ uint8_t inc_step_size_db; /* increasing direction */
+ uint8_t red_step_size_db; /* reducing direction */
+
+ /* Measurement averaging parameters for RxLev & RxQual */
+ struct gsm_power_ctrl_meas_params rxqual_meas;
+ struct gsm_power_ctrl_meas_params rxlev_meas;
+
+ /* Measurement averaging parameters for C/I, per chan type */
+ struct gsm_power_ctrl_meas_params ci_fr_meas;
+ struct gsm_power_ctrl_meas_params ci_hr_meas;
+ struct gsm_power_ctrl_meas_params ci_amr_fr_meas;
+ struct gsm_power_ctrl_meas_params ci_amr_hr_meas;
+ struct gsm_power_ctrl_meas_params ci_sdcch_meas;
+ struct gsm_power_ctrl_meas_params ci_gprs_meas;
+};
+
+/* Measurement pre-processing state */
+struct gsm_power_ctrl_meas_proc_state {
+ /* Number of measurements processed */
+ unsigned int meas_num;
+ /* Algorithm specific data */
+ union {
+ struct {
+ /* Scaled up 100 times average value */
+ int Avg100;
+ } ewma;
+ };
+};
+
+/* Default MS/BS Power Control parameters */
+extern const struct gsm_power_ctrl_params power_ctrl_params_def;
+void power_ctrl_params_def_reset(struct gsm_power_ctrl_params *params, bool is_bs_pwr);
+
+struct gsm_lchan;
int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
- const uint8_t ms_power, const int rxLevel);
+ const uint8_t ms_power_lvl,
+ const int8_t ul_rssi_dbm,
+ const int16_t ul_lqual_cb);
+
+int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
+ const struct gsm48_meas_res *mr);
diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h
index 186018eb..e3950e42 100644
--- a/include/osmo-bts/rsl.h
+++ b/include/osmo-bts/rsl.h
@@ -1,21 +1,11 @@
#ifndef _RSL_H
#define _RSL_H
-/**
- * What kind of release/activation is done? A silent one for
- * the PDCH or one triggered through RSL?
- */
-enum {
- LCHAN_REL_ACT_RSL,
- LCHAN_REL_ACT_PCU,
- LCHAN_REL_ACT_OML,
- LCHAN_REL_ACT_REACT, /* remove once auto-activation hack is removed from opstart_compl() */
-};
-
#define LCHAN_FN_DUMMY 0xFFFFFFFF
#define LCHAN_FN_WAIT 0xFFFFFFFE
-int msgb_queue_flush(struct llist_head *list);
+bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt);
+bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt);
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg);
int rsl_tx_rf_res(struct gsm_bts_trx *trx);
@@ -24,11 +14,11 @@ int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime,
int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len);
int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause);
-int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause);
+int rsl_tx_conn_fail(const struct gsm_lchan *lchan, uint8_t cause);
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan);
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay);
-
-int lchan_deactivate(struct gsm_lchan *lchan);
+int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
+int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
/* call-back for LAPDm code, called when it wants to send msgs UP */
int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
@@ -45,4 +35,6 @@ void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc);
int rsl_tx_cbch_load_indication(struct gsm_bts *bts, bool ext_cbch, bool overflow, uint8_t amount);
+int rsl_tx_meas_res(struct gsm_lchan *lchan, const uint8_t *l3, unsigned int l3_len, int timing_offset);
+
#endif // _RSL_H */
diff --git a/include/osmo-bts/rtp_input_preen.h b/include/osmo-bts/rtp_input_preen.h
new file mode 100644
index 00000000..744ae2a9
--- /dev/null
+++ b/include/osmo-bts/rtp_input_preen.h
@@ -0,0 +1,20 @@
+/*
+ * RTP input validation function: makes the accept-or-drop decision,
+ * and for some codecs signals additional required actions such as
+ * dropping one header octet.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <osmo-bts/lchan.h>
+
+enum pl_input_decision {
+ PL_DECISION_DROP,
+ PL_DECISION_ACCEPT,
+ PL_DECISION_STRIP_HDR_OCTET,
+};
+
+enum pl_input_decision
+rtp_payload_input_preen(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
+ unsigned rtp_pl_len, bool *rfc5993_sid_flag);
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index e693e3ec..aea55959 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -1,18 +1,18 @@
-#ifndef TRX_SCHEDULER_H
-#define TRX_SCHEDULER_H
+#pragma once
#include <osmocom/core/utils.h>
+#include <osmocom/core/rate_ctr.h>
#include <osmo-bts/gsm_data.h>
-/* Whether a logical channel must be activated automatically */
-#define TRX_CHAN_FLAG_AUTO_ACTIVE (1 << 0)
-/* Whether a logical channel belongs to PDCH (packet switched data) */
-#define TRX_CHAN_FLAG_PDCH (1 << 1)
+#define TRX_GMSK_NB_TSC(br) \
+ _sched_train_seq_gmsk_nb[(br)->tsc_set][(br)->tsc]
-/* FIXME: we should actually activate 'auto-active' channels */
-#define TRX_CHAN_IS_ACTIVE(state, chan) \
- (trx_chan_desc[chan].flags & TRX_CHAN_FLAG_AUTO_ACTIVE || (state)->active)
+#define TRX_8PSK_NB_TSC(br) \
+ _sched_train_seq_8psk_nb[(br)->tsc]
+
+#define TRX_CHAN_IS_DEDIC(chan) \
+ (chan >= TRXC_TCHF)
/* These types define the different channels on a multiframe.
* Each channel has queues and can be activated individually.
@@ -24,6 +24,10 @@ enum trx_chan_type {
TRXC_BCCH,
TRXC_RACH,
TRXC_CCCH,
+ TRXC_CBCH,
+ TRXC_PDTCH,
+ TRXC_PTCCH,
+/* Dedicated channels start here */
TRXC_TCHF,
TRXC_TCHH_0,
TRXC_TCHH_1,
@@ -54,9 +58,6 @@ enum trx_chan_type {
TRXC_SACCH8_5,
TRXC_SACCH8_6,
TRXC_SACCH8_7,
- TRXC_PDTCH,
- TRXC_PTCCH,
- TRXC_CBCH,
_TRX_CHAN_MAX
};
@@ -64,31 +65,37 @@ enum trx_chan_type {
#define GPRS_BURST_LEN GSM_BURST_LEN
#define EGPRS_BURST_LEN 444
-enum trx_burst_type {
- TRX_BURST_GMSK,
- TRX_BURST_8PSK,
+enum trx_mod_type {
+ TRX_MOD_T_GMSK,
+ TRX_MOD_T_8PSK,
+ TRX_MOD_T_AQPSK,
+};
+
+/* A set of measurements belonging to one Uplink burst */
+struct l1sched_meas_set {
+ uint32_t fn; /* TDMA frame number */
+ int16_t toa256; /* Timing of Arrival (1/256 of a symbol) */
+ int16_t ci_cb; /* Carrier-to-Interference (cB) */
+ float rssi; /* RSSI (dBm) */
};
/* States each channel on a multiframe */
struct l1sched_chan_state {
+ /* Pointer to the associated logical channel state from gsm_data_shared.
+ * Initialized during channel activation, thus may be NULL for inactive
+ * or auto-active channels. Always check before dereferencing! */
+ struct gsm_lchan *lchan;
+
/* scheduler */
- uint8_t active; /* Channel is active */
+ bool active; /* Channel is active */
ubit_t *dl_bursts; /* burst buffer for TX */
- enum trx_burst_type dl_burst_type; /* GMSK or 8PSK burst type */
+ enum trx_mod_type dl_mod_type; /* Downlink modulation type */
+ uint8_t dl_mask; /* mask of transmitted bursts */
sbit_t *ul_bursts; /* burst buffer for RX */
uint32_t ul_first_fn; /* fn of first burst */
- uint8_t ul_mask; /* mask of received bursts */
-
- /* measurements */
- uint8_t rssi_num; /* number of RSSI values */
- float rssi_sum; /* sum of RSSI values */
- uint8_t toa_num; /* number of TOA values */
- int32_t toa256_sum; /* sum of TOA values (1/256 symbol) */
- uint8_t ci_cb_num; /* number of C/I values */
- int32_t ci_cb_sum; /* sum of C/I values (in centiBels) */
+ uint32_t ul_mask; /* mask of received bursts */
/* loss detection */
- uint8_t lost_frames; /* how many L2 frames were lost */
uint32_t last_tdma_fn; /* last processed TDMA frame number */
uint32_t proc_tdma_fs; /* how many TDMA frames were processed */
uint32_t lost_tdma_fs; /* how many TDMA frames were lost */
@@ -99,18 +106,20 @@ struct l1sched_chan_state {
/* AMR */
uint8_t codec[4]; /* 4 possible codecs for amr */
int codecs; /* number of possible codecs */
- float ber_sum; /* sum of bit error rates */
- int ber_num; /* number of bit error rates */
+ int lqual_cb_sum; /* sum of link quality samples (in cB) */
+ int lqual_cb_num; /* number of link quality samples */
uint8_t ul_ft; /* current uplink FT index */
uint8_t dl_ft; /* current downlink FT index */
uint8_t ul_cmr; /* current uplink CMR index */
uint8_t dl_cmr; /* current downlink CMR index */
- uint8_t amr_loop; /* if AMR loop is enabled */
+ uint8_t amr_last_dtx; /* last received dtx frame type */
/* TCH/H */
uint8_t dl_ongoing_facch; /* FACCH/H on downlink */
uint8_t ul_ongoing_facch; /* FACCH/H on uplink */
+ uint8_t dl_facch_bursts; /* number of remaining DL FACCH bursts */
+
/* encryption */
int ul_encr_algo; /* A5/x encry algo downlink */
int dl_encr_algo; /* A5/x encry algo uplink */
@@ -119,15 +128,14 @@ struct l1sched_chan_state {
uint8_t ul_encr_key[MAX_A5_KEY_LEN];
uint8_t dl_encr_key[MAX_A5_KEY_LEN];
- /* measurements */
+ /* Uplink measurements */
struct {
- uint8_t clock; /* cyclic clock counter */
- int8_t rssi[32]; /* last RSSI values */
- int rssi_count; /* received RSSI values */
- int rssi_valid_count; /* number of stored value */
- int rssi_got_burst; /* any burst received so far */
- int32_t toa256_sum; /* sum of TOA values (1/256 symbol) */
- int toa_num; /* number of TOA value */
+ /* Active channel measurements (simple ring buffer) */
+ struct l1sched_meas_set buf[24]; /* up to 24 (BUFMAX) entries */
+ unsigned int current; /* current position */
+
+ /* Interference measurements */
+ int interf_avg; /* sliding average */
} meas;
/* handover */
@@ -135,67 +143,62 @@ struct l1sched_chan_state {
};
struct l1sched_ts {
+ struct gsm_bts_trx_ts *ts; /* timeslot we belong to */
+
uint8_t mf_index; /* selected multiframe index */
uint8_t mf_period; /* period of multiframe */
const struct trx_sched_frame *mf_frames; /* pointer to frame layout */
struct llist_head dl_prims; /* Queue primitives for TX */
+ struct rate_ctr_group *ctrs; /* rate counters */
+
/* Channel states for all logical channels */
struct l1sched_chan_state chan_state[_TRX_CHAN_MAX];
};
-struct l1sched_trx {
- struct gsm_bts_trx *trx;
- struct l1sched_ts ts[TRX_NR_TS];
-};
-
-struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn);
-
-/*! \brief how many frame numbers in advance we should send bursts to PHY */
-extern uint32_t trx_clock_advance;
-/*! \brief advance RTS.ind to L2 by that many clocks */
-extern uint32_t trx_rts_advance;
-/*! \brief last frame number as received from PHY */
-extern uint32_t transceiver_last_fn;
-
/*! \brief Initialize the scheduler data structures */
-int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx);
+void trx_sched_init(struct gsm_bts_trx *trx);
/*! \brief De-initialize the scheduler data structures */
-void trx_sched_exit(struct l1sched_trx *l1t);
+void trx_sched_clean(struct gsm_bts_trx *trx);
/*! \brief Handle a PH-DATA.req from L2 down to L1 */
-int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
+int trx_sched_ph_data_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
/*! \brief Handle a PH-TCH.req from L2 down to L1 */
-int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
+int trx_sched_tch_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
/*! \brief PHY informs us of new (current) GSM frame number */
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn);
+/*! \brief PHY informs us clock indications should start to be received */
+int trx_sched_clock_started(struct gsm_bts *bts);
+
+/*! \brief PHY informs us no more clock indications should be received anymore */
+int trx_sched_clock_stopped(struct gsm_bts *bts);
+
/*! \brief set multiframe scheduler to given physical channel config */
-int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
- enum gsm_phys_chan_config pchan);
+int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan);
/*! \brief set all matching logical channels active/inactive */
-int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id,
- int active);
+int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active);
+
+/*! \brief set uplink access on given logical channels active/inactive */
+int trx_sched_set_ul_access(struct gsm_lchan *lchan, uint8_t chan_nr, bool active);
+
+/*! \brief set all logical channels of BCCH/CCCH active/inactive */
+int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active);
/*! \brief set mode of all matching logical channels to given mode(s) */
-int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
+int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
uint8_t codec2, uint8_t codec3, uint8_t initial_codec,
uint8_t handover);
/*! \brief set ciphering on given logical channels */
-int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
- int algo, uint8_t *key, int key_len);
-
-/* \brief close all logical channels and reset timeslots */
-void trx_sched_reset(struct l1sched_trx *l1t);
-
+int trx_sched_set_cipher(struct gsm_lchan *lchan, uint8_t chan_nr, bool downlink);
/* frame structures */
struct trx_sched_frame {
@@ -226,13 +229,17 @@ struct trx_sched_multiframe {
int find_sched_mframe_idx(enum gsm_phys_chan_config pchan, uint8_t tn);
/*! Determine if given frame number contains SACCH (true) or other (false) burst */
-bool trx_sched_is_sacch_fn(struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
+bool trx_sched_is_sacch_fn(const struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
extern const struct trx_sched_multiframe trx_sched_multiframes[];
#define TRX_BI_F_NOPE_IND (1 << 0)
#define TRX_BI_F_MOD_TYPE (1 << 1)
#define TRX_BI_F_TS_INFO (1 << 2)
#define TRX_BI_F_CI_CB (1 << 3)
+#define TRX_BI_F_TRX_NUM (1 << 4)
+#define TRX_BI_F_BATCH_IND (1 << 5)
+#define TRX_BI_F_SHADOW_IND (1 << 6)
+#define TRX_BI_F_ACCESS_BURST (1 << 7)
/*! UL burst indication with the corresponding meta info */
struct trx_ul_burst_ind {
@@ -246,17 +253,80 @@ struct trx_ul_burst_ind {
int8_t rssi; /*!< Received Signal Strength Indication */
/* Optional fields (defined by flags) */
- enum trx_burst_type bt; /*!< Modulation type */
+ enum trx_mod_type mod; /*!< Modulation type */
uint8_t tsc_set; /*!< Training Sequence Set */
uint8_t tsc; /*!< Training Sequence Code */
int16_t ci_cb; /*!< Carrier-to-Interference ratio (in centiBels) */
+ uint8_t trx_num; /*!< TRX (RF channel) number */
+
+ /* Used internally by the PDU parser */
+ uint8_t _num_pdus; /*!< Number of processed PDUs */
+
+ /* Internally used by the scheduler */
+ enum trx_chan_type chan;
+ uint8_t bid;
/*! Burst soft-bits buffer */
sbit_t burst[EGPRS_BURST_LEN];
size_t burst_len;
};
+#define TRX_BR_F_FACCH (1 << 0)
+
+/*! DL burst request with the corresponding meta info */
+struct trx_dl_burst_req {
+ uint8_t flags; /*!< see TRX_BR_F_* */
+
+ /* Mandatory fields */
+ uint32_t fn; /*!< TDMA frame number */
+ uint8_t tn; /*!< TDMA timeslot number */
+ uint8_t att; /*!< Tx power attenuation */
+ int8_t scpir; /*!< SCPIR (for AQPSK only) */
+ uint8_t trx_num; /*!< TRX (RF channel) number */
+
+ enum trx_mod_type mod; /*!< Modulation type */
+ uint8_t tsc_set; /*!< Training Sequence Set */
+ uint8_t tsc; /*!< Training Sequence Code */
+
+ /* Internally used by the scheduler */
+ enum trx_chan_type chan;
+ uint8_t bid;
+
+ /*! Burst hard-bits buffer */
+ ubit_t burst[EGPRS_BURST_LEN];
+ size_t burst_len;
+};
+
/*! Handle an UL burst received by PHY */
-int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);
+int trx_sched_route_burst_ind(const struct gsm_bts_trx *trx, struct trx_ul_burst_ind *bi);
+int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi);
+
+/* Averaging mode for trx_sched_meas_avg() */
+enum sched_meas_avg_mode {
+ /* first 22 of last 24 bursts (for TCH/F14.4, TCH/F9.6, TCH/F4.8) */
+ SCHED_MEAS_AVG_M_S24N22,
+ /* last 22 bursts (for TCH/H4.8, TCH/H2.4) */
+ SCHED_MEAS_AVG_M_S22N22,
+ /* last 4 bursts (default for xCCH, PTCCH and PDTCH) */
+ SCHED_MEAS_AVG_M_S4N4,
+ /* last 8 bursts (default for TCH/F and FACCH/F) */
+ SCHED_MEAS_AVG_M_S8N8,
+ /* first 4 of last 6 bursts (default for TCH/H) */
+ SCHED_MEAS_AVG_M_S6N4,
+ /* last 6 bursts (default for FACCH/H) */
+ SCHED_MEAS_AVG_M_S6N6,
+ /* first 4 of last 8 bursts */
+ SCHED_MEAS_AVG_M_S8N4,
+ /* first 2 of last 6 bursts */
+ SCHED_MEAS_AVG_M_S6N2,
+ /* middle 2 of last 6 bursts */
+ SCHED_MEAS_AVG_M_S4N2,
+};
-#endif /* TRX_SCHEDULER_H */
+void trx_sched_meas_push(struct l1sched_chan_state *chan_state,
+ const struct trx_ul_burst_ind *bi);
+void trx_sched_meas_avg(const struct l1sched_chan_state *chan_state,
+ struct l1sched_meas_set *avg,
+ enum sched_meas_avg_mode mode);
+uint32_t trx_sched_lookup_fn(const struct l1sched_chan_state *chan_state,
+ const unsigned int shift);
diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h
index d7139008..820cca78 100644
--- a/include/osmo-bts/scheduler_backend.h
+++ b/include/osmo-bts/scheduler_backend.h
@@ -1,20 +1,18 @@
#pragma once
-#define LOGL1S(subsys, level, l1t, tn, chan, fn, fmt, args ...) \
+#define LOGL1S(subsys, level, l1ts, chan, fn, fmt, args ...) \
LOGP(subsys, level, "%s %s %s: " fmt, \
gsm_fn_as_gsmtime_str(fn), \
- gsm_ts_name(&(l1t)->trx->ts[tn]), \
+ gsm_ts_name((l1ts)->ts), \
chan >=0 ? trx_chan_desc[chan].name : "", ## args)
-typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
- uint32_t fn, enum trx_chan_type chan);
+/* Logging helper adding context from trx_{ul,dl}_burst_{ind,req} */
+#define LOGL1SB(subsys, level, l1ts, b, fmt, args ...) \
+ LOGL1S(subsys, level, l1ts, (b)->chan, (b)->fn, fmt, ## args)
-typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn,
- uint32_t fn, enum trx_chan_type chan,
- uint8_t bid, uint16_t *nbits);
-
-typedef int trx_sched_ul_func(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
+typedef int trx_sched_rts_func(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
+typedef int trx_sched_dl_func(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+typedef int trx_sched_ul_func(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
struct trx_chan_desc {
/*! \brief Human-readable name */
@@ -36,50 +34,40 @@ struct trx_chan_desc {
};
extern const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX];
-extern const ubit_t _sched_tsc[8][26];
-extern const ubit_t _sched_egprs_tsc[8][78];
-const ubit_t _sched_fcch_burst[148];
-const ubit_t _sched_sch_train[64];
+extern const ubit_t _sched_dummy_burst[];
+extern const ubit_t _sched_train_seq_gmsk_nb[4][8][26];
+extern const ubit_t _sched_train_seq_8psk_nb[8][78];
+extern const ubit_t _sched_train_seq_gmsk_sb[64];
-struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn,
- enum trx_chan_type chan);
+struct msgb *_sched_dequeue_prim(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
-int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t *l2,
- uint8_t l2_len, float rssi,
+int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
+ enum trx_chan_type chan,
+ const uint8_t *data, size_t data_len,
+ uint16_t ber10k, float rssi,
int16_t ta_offs_256bits, int16_t link_qual_cb,
- uint16_t ber10k,
enum osmo_ph_pres_info_type presence_info);
-int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len);
+int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
+ enum trx_chan_type chan,
+ const uint8_t *data, size_t data_len,
+ uint16_t ber10k, float rssi,
+ int16_t ta_offs_256bits, int16_t link_qual_cb,
+ uint8_t is_sub);
+
+int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
-ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
-int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
-int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
-int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
-int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
-int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi);
+int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
+int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
+int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
+int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
+int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
-const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
- uint32_t fn, uint16_t *nbits);
-int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
-void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate);
+void _sched_dl_burst(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
+int _sched_rts(const struct l1sched_ts *l1ts, uint32_t fn);
+void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate);
diff --git a/include/osmo-bts/signal.h b/include/osmo-bts/signal.h
index c8168a26..8359f021 100644
--- a/include/osmo-bts/signal.h
+++ b/include/osmo-bts/signal.h
@@ -15,4 +15,10 @@ enum signals_global {
S_NEW_NSVC_ATTR,
};
+struct nm_statechg_signal_data {
+ struct gsm_abis_mo *mo;
+ uint8_t old_state;
+ uint8_t new_state;
+};
+
#endif
diff --git a/include/osmo-bts/ta_control.h b/include/osmo-bts/ta_control.h
new file mode 100644
index 00000000..bf993319
--- /dev/null
+++ b/include/osmo-bts/ta_control.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <osmo-bts/gsm_data.h>
+
+void lchan_ms_ta_ctrl(struct gsm_lchan *lchan, uint8_t ms_tx_ta, int16_t toa256);
diff --git a/include/osmo-bts/tx_power.h b/include/osmo-bts/tx_power.h
index 21887c7c..73134c8b 100644
--- a/include/osmo-bts/tx_power.h
+++ b/include/osmo-bts/tx_power.h
@@ -20,6 +20,8 @@ struct power_amp {
struct pa_calibration calib;
};
+typedef void (*ramp_compl_cb_t)(struct gsm_bts_trx *trx);
+
/* Transmit power related parameters of a transceiver */
struct trx_power_params {
/* specified maximum output of TRX at full power, has to be
@@ -55,24 +57,34 @@ struct trx_power_params {
unsigned int step_size_mdB;
unsigned int step_interval_sec;
struct osmo_timer_list step_timer;
+ /* call-back called when target is reached */
+ ramp_compl_cb_t compl_cb;
} ramp;
};
-int get_p_max_out_mdBm(struct gsm_bts_trx *trx);
+int get_p_max_out_mdBm(const struct gsm_bts_trx *trx);
+
+int get_p_nominal_mdBm(const struct gsm_bts_trx *trx);
+
+int get_p_target_mdBm(const struct gsm_bts_trx *trx, uint8_t bs_power_red);
+int get_p_target_mdBm_lchan(const struct gsm_lchan *lchan);
-int get_p_nominal_mdBm(struct gsm_bts_trx *trx);
+int get_p_actual_mdBm(const struct gsm_bts_trx *trx, int p_target_mdBm);
-int get_p_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
-int get_p_target_mdBm_lchan(struct gsm_lchan *lchan);
+int get_p_trxout_target_mdBm(const struct gsm_bts_trx *trx, uint8_t bs_power_red);
+int get_p_trxout_target_mdBm_lchan(const struct gsm_lchan *lchan);
-int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
-int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan);
+int get_p_trxout_actual_mdBm(const struct gsm_bts_trx *trx, uint8_t bs_power_red);
+int get_p_trxout_actual_mdBm_lchan(const struct gsm_lchan *lchan);
-int get_p_trxout_actual_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
-int get_p_trxout_actual_mdBm_lchan(struct gsm_lchan *lchan);
+int _power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass_max_power, ramp_compl_cb_t ramp_compl_cb, bool skip_ramping);
+#define power_ramp_start(trx, p_total_tgt_mdBm, bypass_max_power, ramp_compl_cb) \
+ _power_ramp_start(trx, p_total_tgt_mdBm, bypass_max_power, ramp_compl_cb, false)
+#define power_ramp_force(trx, p_total_tgt_mdBm, bypass_max_power, ramp_compl_cb) \
+ _power_ramp_start(trx, p_total_tgt_mdBm, bypass_max_power, ramp_compl_cb, true)
-int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass);
+void power_ramp_abort(struct gsm_bts_trx *trx);
void power_trx_change_compl(struct gsm_bts_trx *trx, int p_trxout_cur_mdBm);
-int power_ramp_initial_power_mdBm(struct gsm_bts_trx *trx);
+int power_ramp_initial_power_mdBm(const struct gsm_bts_trx *trx);
diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h
index eab58d6d..d326c5cd 100644
--- a/include/osmo-bts/vty.h
+++ b/include/osmo-bts/vty.h
@@ -12,23 +12,25 @@ enum bts_vty_node {
PHY_INST_NODE,
BTS_NODE,
TRX_NODE,
+ OSMUX_NODE,
};
-extern struct cmd_element ournode_exit_cmd;
-extern struct cmd_element ournode_end_cmd;
-
extern struct cmd_element cfg_bts_auto_band_cmd;
extern struct cmd_element cfg_bts_no_auto_band_cmd;
struct phy_instance *vty_get_phy_instance(struct vty *vty, int phy_nr, int inst_nr);
int bts_vty_go_parent(struct vty *vty);
-int bts_vty_is_config_node(struct vty *vty, int node);
-
-int bts_vty_init(struct gsm_bts *bts);
-struct gsm_network *gsmnet_from_vty(struct vty *v);
+int bts_vty_init(void *ctx);
extern struct vty_app_info bts_vty_info;
+extern struct gsm_bts *g_bts;
+
+enum bts_vty_cmd_attr {
+ BTS_VTY_ATTR_NEW_LCHAN,
+ BTS_VTY_TRX_POWERCYCLE,
+ /* NOTE: up to 32 entries */
+};
#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 70e4d968..b2870264 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,7 @@ SUBDIRS += osmo-bts-octphy
endif
if ENABLE_LC15BTS
-SUBDIRS += osmo-bts-litecell15
+SUBDIRS += osmo-bts-lc15
endif
if ENABLE_OC2GBTS
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 113ff2f4..d13415d1 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -1,17 +1,87 @@
-AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOCODEC_LIBS)
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ $(NULL)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
if ENABLE_LC15BTS
AM_CFLAGS += -DENABLE_LC15BTS
endif
noinst_LIBRARIES = libbts.a libl1sched.a
-libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
- rsl.c vty.c paging.c measurement.c amr.c lchan.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 phy_link.c \
- dtx_dl_amr_fsm.c scheduler_mframe.c
+libbts_a_SOURCES = \
+ gsm_data.c \
+ sysinfo.c \
+ logging.c \
+ abis.c \
+ abis_osmo.c \
+ oml.c \
+ osmux.c \
+ bts.c \
+ bts_sm.c \
+ bts_trx.c \
+ rsl.c \
+ rtp_input_preen.c \
+ vty.c \
+ paging.c \
+ measurement.c \
+ amr.c \
+ asci.c \
+ lchan.c \
+ load_indication.c \
+ pcu_sock.c \
+ handover.c \
+ msg_utils.c \
+ tx_power.c \
+ bts_ctrl_commands.c \
+ bts_ctrl_lookup.c \
+ bts_shutdown_fsm.c \
+ csd_v110.c \
+ l1sap.c \
+ cbch.c \
+ power_control.c \
+ main.c \
+ phy_link.c \
+ dtx_dl_amr_fsm.c \
+ scheduler_mframe.c \
+ ta_control.c \
+ nm_common_fsm.c \
+ nm_bts_sm_fsm.c \
+ nm_bts_fsm.c \
+ nm_bb_transc_fsm.c \
+ nm_channel_fsm.c \
+ nm_gprs_cell_fsm.c \
+ nm_gprs_nse_fsm.c \
+ nm_gprs_nsvc_fsm.c \
+ nm_radio_carrier_fsm.c \
+ notification.c \
+ probes.d \
+ $(NULL)
libl1sched_a_SOURCES = scheduler.c
+
+if ENABLE_SYSTEMTAP
+probes.h: probes.d
+ $(DTRACE) -C -h -s $< -o $@
+
+probes.lo: probes.d
+ $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -C -G -s $< -o $@
+
+BUILT_SOURCES = probes.h probes.lo
+libbts_la_LDADD = probes.lo
+endif
diff --git a/src/common/abis.c b/src/common/abis.c
index 84a3a047..5629cf23 100644
--- a/src/common/abis.c
+++ b/src/common/abis.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -38,46 +38,319 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/signal.h>
#include <osmocom/core/macaddr.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/abis/abis.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/abis/ipaccess.h>
#include <osmocom/gsm/ipa.h>
+#include <osmo-bts/abis.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/abis_osmo.h>
#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts_trx.h>
+#include <osmo-bts/bts_shutdown_fsm.h>
static struct gsm_bts *g_bts;
-int abis_oml_sendmsg(struct msgb *msg)
+static struct e1inp_line_ops line_ops;
+
+static struct ipaccess_unit bts_dev_info;
+
+#define S(x) (1 << (x))
+#define OML_RETRY_TIMER 5
+
+enum abis_link_fsm_state {
+ ABIS_LINK_ST_WAIT_RECONNECT, /* OML link has not yet been established */
+ ABIS_LINK_ST_CONNECTING, /* OML link in process of been established */
+ ABIS_LINK_ST_CONNECTED, /* OML link is established, RSL links may be established or not */
+ ABIS_LINK_ST_FAILED, /* There used to be an active OML connection but it became broken */
+};
+
+static const struct value_string abis_link_fsm_event_names[] = {
+ { ABIS_LINK_EV_SIGN_LINK_OML_UP, "SIGN_LINK_OML_UP", },
+ { ABIS_LINK_EV_SIGN_LINK_DOWN, "SIGN_LINK_DOWN" },
+ { ABIS_LINK_EV_VTY_RM_ADDR, "VTY_RM_ADDR" },
+ {}
+};
+
+struct abis_link_fsm_priv {
+ struct bsc_oml_host *current_bsc;
+ struct gsm_bts *bts;
+ char *model_name;
+ bool reconnect_to_current_bsc;
+};
+
+static void reset_oml_link(struct gsm_bts *bts)
{
- struct gsm_bts *bts = msg->trx->bts;
+ if (bts->oml_link) {
+ struct timespec now;
- if (!bts->oml_link) {
- llist_add_tail(&msg->list, &bts->oml_queue);
+ e1inp_sign_link_destroy(bts->oml_link);
+
+ /* Log a special notice if the OML connection was dropped relatively quickly. */
+ if (bts->oml_conn_established_timestamp.tv_sec != 0 && clock_gettime(CLOCK_MONOTONIC, &now) == 0 &&
+ bts->oml_conn_established_timestamp.tv_sec + OSMO_BTS_OML_CONN_EARLY_DISCONNECT >= now.tv_sec) {
+ LOGP(DABIS, LOGL_FATAL, "OML link was closed early within %" PRIu64 " seconds. "
+ "If this situation persists, please check your BTS and BSC configuration files for errors. "
+ "A common error is a mismatch between unit_id configuration parameters of BTS and BSC.\n",
+ (uint64_t) (now.tv_sec - bts->oml_conn_established_timestamp.tv_sec));
+ }
+ bts->oml_link = NULL;
+ }
+ memset(&bts->oml_conn_established_timestamp, 0, sizeof(bts->oml_conn_established_timestamp));
+
+ /* Same for IPAC_PROTO_OSMO on the same ipa connection: */
+ if (bts->osmo_link) {
+ e1inp_sign_link_destroy(bts->osmo_link);
+ bts->osmo_link = NULL;
+ }
+
+}
+
+static int pick_next_bsc(struct osmo_fsm_inst *fi)
+{
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+ struct bsc_oml_host *last;
+
+ if (llist_empty(&bts->bsc_oml_hosts)) {
+ LOGPFSML(fi, LOGL_ERROR, "List of BSCs to connect to is empty!\n");
+ return -1;
+ }
+
+ /* Keep current pointer to priv->current_bsc: */
+ if (priv->reconnect_to_current_bsc) {
+ OSMO_ASSERT(priv->current_bsc);
+ priv->reconnect_to_current_bsc = false;
return 0;
- } else {
- /* osmo-bts uses msg->trx internally, but libosmo-abis uses
- * the signalling link at msg->dst */
- msg->dst = bts->oml_link;
- return abis_sendmsg(msg);
}
+
+ last = (struct bsc_oml_host *)llist_last_entry(&bts->bsc_oml_hosts, struct bsc_oml_host, list);
+
+ if (!priv->current_bsc || priv->current_bsc == last) /* Pick first one (wrap around): */
+ priv->current_bsc = (struct bsc_oml_host *)llist_first_entry(&bts->bsc_oml_hosts, struct bsc_oml_host, list);
+ else
+ priv->current_bsc = (struct bsc_oml_host *)llist_entry(priv->current_bsc->list.next, struct bsc_oml_host, list);
+
+ return 0;
}
-static void drain_oml_queue(struct gsm_bts *bts)
+static void abis_link_connecting_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
- struct msgb *msg, *msg2;
-
- llist_for_each_entry_safe(msg, msg2, &bts->oml_queue, list) {
- /* osmo-bts uses msg->trx internally, but libosmo-abis uses
- * the signalling link at msg->dst */
- llist_del(&msg->list);
- msg->dst = bts->oml_link;
- abis_sendmsg(msg);
+ struct e1inp_line *line;
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+
+ if (bts_shutdown_in_progress(bts)) {
+ LOGPFSML(fi, LOGL_NOTICE, "BTS is shutting down, delaying A-bis connection establishment to BSC\n");
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_WAIT_RECONNECT, OML_RETRY_TIMER, 0);
+ return;
+ }
+
+ if (pick_next_bsc(fi) < 0) {
+ LOGPFSML(fi, LOGL_FATAL, "No BSC available, A-bis connection establishment failed\n");
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_FAILED, 0, 0);
+ return;
}
+
+ LOGP(DABIS, LOGL_NOTICE, "A-bis connection establishment to BSC (%s) in progress...\n", priv->current_bsc->addr);
+
+ /* patch in various data from VTY and other sources */
+ line_ops.cfg.ipa.addr = priv->current_bsc->addr;
+ osmo_get_macaddr(bts_dev_info.mac_addr, "eth0");
+ bts_dev_info.site_id = bts->ip_access.site_id;
+ bts_dev_info.bts_id = bts->ip_access.bts_id;
+ bts_dev_info.unit_name = priv->model_name;
+ if (bts->description)
+ bts_dev_info.unit_name = bts->description;
+ bts_dev_info.location2 = priv->model_name;
+
+ line = e1inp_line_find(0);
+ if (!line)
+ line = e1inp_line_create(0, "ipa");
+ if (!line) {
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_FAILED, 0, 0);
+ return;
+ }
+ /* Line always comes already with a "ctor" reference, enough to keep it alive forever. */
+
+ e1inp_line_bind_ops(line, &line_ops);
+ /* This will open the OML connection now */
+ if (e1inp_line_update(line) < 0) {
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_FAILED, 0, 0);
+ return;
+ }
+
+ /* The TCP connection to the BSC is now in progress.
+ * Wait for OML Link UP to transition to CONNECTED. */
+}
+
+static void abis_link_connecting(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+
+ switch (event) {
+ case ABIS_LINK_EV_SIGN_LINK_OML_UP:
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_CONNECTED, 0, 0);
+ break;
+ case ABIS_LINK_EV_SIGN_LINK_DOWN:
+ reset_oml_link(bts);
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_WAIT_RECONNECT, OML_RETRY_TIMER, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void abis_link_connected_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ bts_link_estab(g_bts);
+}
+
+static void abis_link_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+ struct gsm_bts_trx *trx;
+ OSMO_ASSERT(event == ABIS_LINK_EV_SIGN_LINK_DOWN);
+
+ /* First remove the OML signalling link */
+ reset_oml_link(bts);
+
+ /* Then iterate over the RSL signalling links */
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->bb_transc.rsl.link) {
+ e1inp_sign_link_destroy(trx->bb_transc.rsl.link);
+ trx->bb_transc.rsl.link = NULL;
+ if (trx == trx->bts->c0)
+ load_timer_stop(trx->bts);
+ } else {
+ /* If we have no rsl_link yet it may mean that lower
+ * layers are still establishing the socket (TCP, IPA).
+ * Let's tell it to stop connection establishment since
+ * we are shutting down. */
+ struct e1inp_line *line = e1inp_line_find(0);
+ if (line)
+ e1inp_ipa_bts_rsl_close_n(line, trx->nr);
+ }
+ /* Note: Here we could send NM_EV_RSL_DOWN to each
+ * trx->(bb_transc.)mo.fi, but we are starting shutdown of the
+ * entire BTS anyway through bts_model_abis_close(), so simply
+ * let bts_shutdown FSM take care of slowly powering down all
+ * the TRX. It would make sense to send NM_EV_RSL_DOWN only if a
+ * RSL link TRX!=C0 was going down, in order to selectively stop
+ * that TRX only. But libosmo-abis expects us to drop the entire
+ * line when something goes wrong... */
+ }
+ bts_model_abis_close(bts);
+
+ /* We want to try reconnecting to the current BSC at least once before switching to a new one: */
+ priv->reconnect_to_current_bsc = true;
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_WAIT_RECONNECT, OML_RETRY_TIMER, 0);
+}
+
+static void abis_link_failed_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+
+ /* None of the configured BSCs was reachable or there was an existing
+ * OML/RSL connection that broke. Initiate BTS process shut down now. */
+ bts_model_abis_close(bts);
+}
+
+static void abis_link_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct abis_link_fsm_priv *priv = fi->priv;
+ struct gsm_bts *bts = priv->bts;
+
+ OSMO_ASSERT(event == ABIS_LINK_EV_VTY_RM_ADDR);
+
+ if (priv->current_bsc == data) {
+ if (llist_count(&bts->bsc_oml_hosts) <= 1)
+ priv->current_bsc = NULL;
+ else
+ pick_next_bsc(fi);
+ }
+}
+
+int abis_link_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ switch (fi->state) {
+ case ABIS_LINK_ST_WAIT_RECONNECT:
+ osmo_fsm_inst_state_chg(fi, ABIS_LINK_ST_CONNECTING, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ return 0;
+}
+
+
+static struct osmo_fsm_state abis_link_fsm_states[] = {
+ [ABIS_LINK_ST_WAIT_RECONNECT] = {
+ .name = "WAIT_RECONNECT",
+ .out_state_mask =
+ S(ABIS_LINK_ST_CONNECTING),
+ },
+ [ABIS_LINK_ST_CONNECTING] = {
+ .name = "CONNECTING",
+ .in_event_mask =
+ S(ABIS_LINK_EV_SIGN_LINK_OML_UP) |
+ S(ABIS_LINK_EV_SIGN_LINK_DOWN),
+ .out_state_mask =
+ S(ABIS_LINK_ST_WAIT_RECONNECT) |
+ S(ABIS_LINK_ST_CONNECTED) |
+ S(ABIS_LINK_ST_FAILED),
+ .onenter = abis_link_connecting_onenter,
+ .action = abis_link_connecting,
+ },
+ [ABIS_LINK_ST_CONNECTED] = {
+ .name = "CONNECTED",
+ .in_event_mask =
+ S(ABIS_LINK_EV_SIGN_LINK_DOWN),
+ .out_state_mask =
+ S(ABIS_LINK_ST_WAIT_RECONNECT),
+ .onenter = abis_link_connected_onenter,
+ .action = abis_link_connected,
+ },
+ [ABIS_LINK_ST_FAILED] = {
+ .name = "FAILED",
+ .onenter = abis_link_failed_onenter,
+ },
+};
+
+static struct osmo_fsm abis_link_fsm = {
+ .name = "abis_link",
+ .states = abis_link_fsm_states,
+ .num_states = ARRAY_SIZE(abis_link_fsm_states),
+ .log_subsys = DABIS,
+ .event_names = abis_link_fsm_event_names,
+ .allstate_action = abis_link_allstate,
+ .allstate_event_mask = S(ABIS_LINK_EV_VTY_RM_ADDR),
+ .timer_cb = abis_link_fsm_timer_cb,
+};
+
+int abis_oml_sendmsg(struct msgb *msg)
+{
+ struct gsm_bts *bts = msg->trx->bts;
+
+ if (!bts->oml_link) {
+ LOGP(DABIS, LOGL_INFO, "Drop Tx OML msg, OML link is down\n");
+ msgb_free(msg);
+ return 0;
+ }
+
+ /* osmo-bts uses msg->trx internally, but libosmo-abis uses
+ * the signalling link at msg->dst */
+ msg->dst = bts->oml_link;
+ return abis_sendmsg(msg);
}
int abis_bts_rsl_sendmsg(struct msgb *msg)
@@ -91,33 +364,37 @@ int abis_bts_rsl_sendmsg(struct msgb *msg)
/* osmo-bts uses msg->trx internally, but libosmo-abis uses
* the signalling link at msg->dst */
- msg->dst = msg->trx->rsl_link;
+ msg->dst = msg->trx->bb_transc.rsl.link;
return abis_sendmsg(msg);
}
static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
enum e1inp_sign_type type)
{
- struct e1inp_sign_link *sign_link = NULL;
+ struct e1inp_ts *sign_ts;
struct gsm_bts_trx *trx;
int trx_nr;
switch (type) {
case E1INP_SIGN_OML:
+ sign_ts = e1inp_line_ipa_oml_ts(line);
LOGP(DABIS, LOGL_INFO, "OML Signalling link up\n");
- e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML-1], line);
- sign_link = g_bts->oml_link =
- e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
- E1INP_SIGN_OML, NULL, 255, 0);
+ e1inp_ts_config_sign(sign_ts, line);
+ g_bts->oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
+ g_bts->c0, IPAC_PROTO_OML, 0);
if (clock_gettime(CLOCK_MONOTONIC, &g_bts->oml_conn_established_timestamp) != 0)
memset(&g_bts->oml_conn_established_timestamp, 0,
sizeof(g_bts->oml_conn_established_timestamp));
- drain_oml_queue(g_bts);
- sign_link->trx = g_bts->c0;
- bts_link_estab(g_bts);
- break;
+ g_bts->osmo_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OSMO,
+ g_bts->c0, IPAC_PROTO_OSMO, 0);
+ osmo_fsm_inst_dispatch(g_bts->abis_link_fi, ABIS_LINK_EV_SIGN_LINK_OML_UP, NULL);
+ return g_bts->oml_link;
+
+ case E1INP_SIGN_RSL:
+ /* fall through to default to catch TRXn having type = E1INP_SIGN_RSL + n */
default:
trx_nr = type - E1INP_SIGN_RSL;
+ sign_ts = e1inp_line_ipa_rsl_ts(line, trx_nr);
LOGP(DABIS, LOGL_INFO, "RSL Signalling link for TRX%d up\n",
trx_nr);
trx = gsm_bts_trx_num(g_bts, trx_nr);
@@ -126,54 +403,23 @@ static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
trx_nr);
break;
}
- e1inp_ts_config_sign(&line->ts[type-1], line);
- sign_link = trx->rsl_link =
- e1inp_sign_link_create(&line->ts[type-1],
- E1INP_SIGN_RSL, NULL, 0, 0);
- sign_link->trx = trx;
+ e1inp_ts_config_sign(sign_ts, line);
+ trx->bb_transc.rsl.link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
+ trx, trx->bb_transc.rsl.tei, 0);
trx_link_estab(trx);
- break;
+ return trx->bb_transc.rsl.link;
}
-
- return sign_link;
+ return NULL;
}
static void sign_link_down(struct e1inp_line *line)
{
- struct gsm_bts_trx *trx;
- LOGP(DABIS, LOGL_ERROR, "Signalling link down\n");
-
- /* First remove the OML signalling link */
- if (g_bts->oml_link) {
- struct timespec now;
-
- e1inp_sign_link_destroy(g_bts->oml_link);
-
- /* Log a special notice if the OML connection was dropped relatively quickly. */
- if (g_bts->oml_conn_established_timestamp.tv_sec != 0 && clock_gettime(CLOCK_MONOTONIC, &now) == 0 &&
- g_bts->oml_conn_established_timestamp.tv_sec + OSMO_BTS_OML_CONN_EARLY_DISCONNECT >= now.tv_sec) {
- LOGP(DABIS, LOGL_FATAL, "OML link was closed early within %" PRIu64 " seconds. "
- "If this situation persists, please check your BTS and BSC configuration files for errors. "
- "A common error is a mismatch between unit_id configuration parameters of BTS and BSC.\n",
- (uint64_t)(now.tv_sec - g_bts->oml_conn_established_timestamp.tv_sec));
- }
- }
- g_bts->oml_link = NULL;
- memset(&g_bts->oml_conn_established_timestamp, 0, sizeof(g_bts->oml_conn_established_timestamp));
-
- /* Then iterate over the RSL signalling links */
- llist_for_each_entry(trx, &g_bts->trx_list, list) {
- if (trx->rsl_link) {
- e1inp_sign_link_destroy(trx->rsl_link);
- trx->rsl_link = NULL;
- }
- }
-
- bts_model_abis_close(g_bts);
+ LOGPIL(line, DABIS, LOGL_ERROR, "Signalling link down\n");
+ osmo_fsm_inst_dispatch(g_bts->abis_link_fi, ABIS_LINK_EV_SIGN_LINK_DOWN, NULL);
}
-/* callback for incoming mesages from A-bis/IP */
+/* callback for incoming messages from A-bis/IP */
static int sign_link_cb(struct msgb *msg)
{
struct e1inp_sign_link *link = msg->dst;
@@ -190,6 +436,9 @@ static int sign_link_cb(struct msgb *msg)
case E1INP_SIGN_RSL:
down_rsl(link->trx, msg);
break;
+ case E1INP_SIGN_OSMO:
+ down_osmo(link->trx->bts, msg);
+ break;
default:
msgb_free(msg);
break;
@@ -212,7 +461,7 @@ uint32_t get_signlink_remote_ip(struct e1inp_sign_link *link)
return 0;
}
- /* we assume that the soket is AF_INET. As Abis/IP contains
+ /* we assume that the socket is AF_INET. As Abis/IP contains
* lots of hard-coded IPv4 addresses, this safe */
OSMO_ASSERT(sin.sin_family == AF_INET);
@@ -235,7 +484,7 @@ static int inp_s_cbfn(unsigned int subsys, unsigned int signal,
static struct ipaccess_unit bts_dev_info = {
- .unit_name = "sysmoBTS",
+ .unit_name = "osmo-bts",
.equipvers = "", /* FIXME: read this from hw */
.swversion = PACKAGE_VERSION,
.location1 = "",
@@ -259,37 +508,36 @@ void abis_init(struct gsm_bts *bts)
{
g_bts = bts;
- oml_init(&bts->mo);
- libosmo_abis_init(NULL);
+ oml_init();
+ libosmo_abis_init(tall_bts_ctx);
osmo_signal_register_handler(SS_L_INPUT, &inp_s_cbfn, bts);
}
-struct e1inp_line *abis_open(struct gsm_bts *bts, char *dst_host,
- char *model_name)
+int abis_open(struct gsm_bts *bts, char *model_name)
{
- struct e1inp_line *line;
+ struct abis_link_fsm_priv *abis_link_fsm_priv;
- /* patch in various data from VTY and othe sources */
- line_ops.cfg.ipa.addr = dst_host;
- osmo_get_macaddr(bts_dev_info.mac_addr, "eth0");
- bts_dev_info.site_id = bts->ip_access.site_id;
- bts_dev_info.bts_id = bts->ip_access.bts_id;
- bts_dev_info.unit_name = model_name;
- if (bts->description)
- bts_dev_info.unit_name = bts->description;
- bts_dev_info.location2 = model_name;
+ if (llist_empty(&bts->bsc_oml_hosts)) {
+ LOGP(DABIS, LOGL_FATAL, "No BSC configured, cannot start BTS without knowing BSC OML IP\n");
+ return -EINVAL;
+ }
- line = e1inp_line_find(0);
- if (!line)
- line = e1inp_line_create(0, "ipa");
- if (!line)
- return NULL;
- e1inp_line_bind_ops(line, &line_ops);
+ bts->abis_link_fi = osmo_fsm_inst_alloc(&abis_link_fsm, bts, NULL, LOGL_DEBUG, "abis_link");
+ OSMO_ASSERT(bts->abis_link_fi);
- /* This will open the OML connection now */
- if (e1inp_line_update(line) < 0)
- return NULL;
+ abis_link_fsm_priv = talloc_zero(bts->abis_link_fi, struct abis_link_fsm_priv);
+ OSMO_ASSERT(abis_link_fsm_priv);
+ abis_link_fsm_priv->bts = bts;
+ abis_link_fsm_priv->model_name = model_name;
+ bts->abis_link_fi->priv = abis_link_fsm_priv;
+
+ osmo_fsm_inst_state_chg(bts->abis_link_fi, ABIS_LINK_ST_CONNECTING, 0, 0);
- return line;
+ return 0;
+}
+
+static __attribute__((constructor)) void abis_link_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&abis_link_fsm) == 0);
}
diff --git a/src/common/abis_osmo.c b/src/common/abis_osmo.c
new file mode 100644
index 00000000..beb9992d
--- /dev/null
+++ b/src/common/abis_osmo.c
@@ -0,0 +1,135 @@
+/* OSMO extenion link associated to same line as oml_link: */
+
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/ipa.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/pcuif_proto.h>
+#include <osmo-bts/bts_sm.h>
+
+#define OM_HEADROOM_SIZE 128
+
+////////////////////////////////////////
+// OSMO ABIS extensions (PCU)
+///////////////////////////////////////
+
+static struct msgb *abis_osmo_pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr, size_t extra_size)
+{
+ struct msgb *msg;
+ struct gsm_pcu_if *pcu_prim;
+ msg = msgb_alloc_headroom(OM_HEADROOM_SIZE + sizeof(struct gsm_pcu_if) + extra_size,
+ OM_HEADROOM_SIZE, "IPA/ABIS/OSMO");
+ /* Only header is filled, caller is responible for reserving + filling
+ * message type specific contents: */
+ msgb_put(msg, PCUIF_HDR_SIZE);
+ pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ pcu_prim->msg_type = msg_type;
+ pcu_prim->bts_nr = bts_nr;
+ return msg;
+}
+
+/* Send a OML NM Message from BSC to BTS */
+int abis_osmo_sendmsg(struct gsm_bts *bts, struct msgb *msg)
+{
+ msg->dst = bts->osmo_link;
+ msg->l2h = msg->data;
+ return abis_sendmsg(msg);
+}
+
+
+/* Send IPA/OSMO/PCU extension Abis message from PCU to BSC */
+static int abis_osmo_pcu_sendmsg(struct gsm_bts *bts, struct msgb *msg)
+{
+ ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_PCU);
+ return abis_osmo_sendmsg(bts, msg);
+}
+
+int abis_osmo_pcu_tx_container(struct gsm_bts *bts, const struct gsm_pcu_if_container *container)
+{
+ uint16_t data_length = osmo_load16be(&container->length);
+ struct msgb *msg = abis_osmo_pcu_msgb_alloc(PCU_IF_MSG_CONTAINER, bts->nr, data_length);
+ struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ struct gsm_pcu_if_container *tx_cont = &pcu_prim->u.container;
+
+ msgb_put(msg, sizeof(*tx_cont) + data_length);
+ tx_cont->msg_type = container->msg_type;
+ tx_cont->length = container->length;
+ if (data_length)
+ memcpy(tx_cont->data, container->data, data_length);
+
+ return abis_osmo_pcu_sendmsg(bts, msg);
+}
+
+
+/* incoming IPA/OSMOEXT/PCU Abis message from BSC */
+static int rx_down_osmo_pcu(struct gsm_bts *bts, struct msgb *msg)
+{
+ struct gsm_pcu_if *pcu_prim;
+ if (msgb_l2len(msg) < PCUIF_HDR_SIZE) {
+ LOGP(DPCU, LOGL_ERROR, "ABIS_OSMO_PCU message too short\n");
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "ABIS_OSMO_PCU message too short\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ pcu_prim = msgb_l2(msg);
+ LOGP(DPCU, LOGL_INFO, "Rx BSC->BTS%d ABIS_OSMO_PCU msg type %u\n",
+ pcu_prim->bts_nr, pcu_prim->msg_type);
+ /* we patch the bts_nr received from BTS with the bts_nr we used to set up in the local PCU */
+ pcu_prim->bts_nr = bts->nr;
+ /* Trim Abis lower layers: */
+ msgb_pull_to_l2(msg);
+ /* we simply forward it to PCUIF: */
+ return pcu_sock_send(msg);
+}
+
+/* incoming IPA/OSMO extension Abis message from BSC */
+int down_osmo(struct gsm_bts *bts, struct msgb *msg)
+{
+ uint8_t *type;
+
+ if (msgb_l2len(msg) < 1) {
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "OSMO message too short\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ type = msgb_l2(msg);
+ msg->l2h = type + 1;
+
+ switch (*type) {
+ case IPAC_PROTO_EXT_PCU:
+ return rx_down_osmo_pcu(bts, msg);
+ default:
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "OSMO message unknown extension %u\n", *type);
+ msgb_free(msg);
+ return -EIO;
+ }
+}
diff --git a/src/common/amr.c b/src/common/amr.c
index 05d1aaac..47c9dcb5 100644
--- a/src/common/amr.c
+++ b/src/common/amr.c
@@ -6,6 +6,85 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/amr.h>
+/* Reasonable defaults for AMR-FR and AMR-HR rate configuration.
+ * The values are taken from 3GPP TS 51.010-1 (version 13.11.0).
+ * See 14.2.19.4.1 and 14.2.20.4.1 for AMR-FR and AMR-HR, respectively.
+ *
+ * ^ C/I (dB) | FR / HR |
+ * | |
+ * | |
+ * MODE4 | |
+ * = | ----+---- THR_MX_Up(3) | 20.5 / 18.0 |
+ * | | |
+ * | = ----+---- THR_MX_Dn(4) | 18.5 / 16.0 |
+ * MODE3 | |
+ * | = ----+---- THR_MX_Up(2) | 14.5 / 14.0 |
+ * | | |
+ * = | ----+---- THR_MX_Dn(3) | 12.5 / 12.0 |
+ * MODE2 | |
+ * = | ----+---- THR_MX_Up(1) | 8.5 / 10.0 |
+ * | | |
+ * | = ----+---- THR_MX_Dn(2) | 6.5 / 8.0 |
+ * MODE1 | |
+ * | |
+ * | |
+ */
+static const struct gsm48_multi_rate_conf amr_fr_mr_cfg_def = {
+ .m4_75 = 1,
+ .m5_90 = 1,
+ .m7_95 = 1,
+ .m12_2 = 1,
+};
+static const struct amr_mode amr_fr_bts_mode_def[] = {
+ {
+ .mode = 0, /* 4.75k */
+ .threshold = 13, /* THR_MX_Dn(2): 6.5 dB */
+ .hysteresis = 4, /* THR_MX_Up(1): 8.5 dB */
+ },
+ {
+ .mode = 2, /* 5.90k */
+ .threshold = 25, /* THR_MX_Dn(3): 12.5 dB */
+ .hysteresis = 4, /* THR_MX_Up(2): 14.5 dB */
+ },
+ {
+ .mode = 5, /* 7.95k */
+ .threshold = 37, /* THR_MX_Dn(4): 18.5 dB */
+ .hysteresis = 4, /* THR_MX_Up(3): 20.5 dB */
+ },
+ {
+ .mode = 7, /* 12.2k */
+ /* this is the last mode, so no threshold */
+ },
+};
+
+static const struct gsm48_multi_rate_conf amr_hr_mr_cfg_def = {
+ .m4_75 = 1,
+ .m5_90 = 1,
+ .m6_70 = 1,
+ .m7_95 = 1,
+};
+static const struct amr_mode amr_hr_bts_mode_def[] = {
+ {
+ .mode = 0, /* 4.75k */
+ .threshold = 16, /* THR_MX_Dn(2): 8.0 dB */
+ .hysteresis = 4, /* THR_MX_Up(1): 10.0 dB */
+ },
+ {
+ .mode = 2, /* 5.90k */
+ .threshold = 24, /* THR_MX_Dn(3): 12.0 dB */
+ .hysteresis = 4, /* THR_MX_Up(2): 14.0 dB */
+ },
+ {
+ .mode = 3, /* 6.70k */
+ .threshold = 32, /* THR_MX_Dn(4): 16.0 dB */
+ .hysteresis = 4, /* THR_MX_Up(3): 18.0 dB */
+ },
+ {
+ .mode = 5, /* 7.95k */
+ /* this is the last mode, so no threshold */
+ },
+};
+
void amr_log_mr_conf(int ss, int logl, const char *pfx,
struct amr_multirate_conf *amr_mrc)
{
@@ -16,9 +95,9 @@ void amr_log_mr_conf(int ss, int logl, const char *pfx,
for (i = 0; i < amr_mrc->num_modes; i++)
LOGPC(ss, logl, ", mode[%u] = %u/%u/%u",
- i, amr_mrc->bts_mode[i].mode,
- amr_mrc->bts_mode[i].threshold,
- amr_mrc->bts_mode[i].hysteresis);
+ i, amr_mrc->mode[i].mode,
+ amr_mrc->mode[i].threshold,
+ amr_mrc->mode[i].hysteresis);
LOGPC(ss, logl, "\n");
}
@@ -27,7 +106,7 @@ static inline int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc,
{
unsigned int i;
for (i = 0; i < amr_mrc->num_modes; i++) {
- if (amr_mrc->bts_mode[i].mode == cmi)
+ if (amr_mrc->mode[i].mode == cmi)
return i;
}
return -EINVAL;
@@ -78,13 +157,16 @@ void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc,
int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc,
const uint8_t *mr_conf, unsigned int len)
{
- uint8_t mr_version = mr_conf[0] >> 5;
uint8_t num_codecs = 0;
int i, j = 0;
- if (mr_version != 1) {
- LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n",
- mr_version);
+ if (len < 2) {
+ LOGP(DRSL, LOGL_ERROR, "AMR Multirate IE is too short (%u)\n", len);
+ goto ret_einval;
+ }
+
+ if ((mr_conf[0] >> 5) != 1) {
+ LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n", (mr_conf[0] >> 5));
goto ret_einval;
}
@@ -114,23 +196,26 @@ int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc,
for (i = 0; i < 8; i++) {
if (mr_conf[1] & (1 << i)) {
- amr_mrc->bts_mode[j++].mode = i;
+ amr_mrc->mode[j++].mode = i;
}
}
+ /* skip the first two octets of the IE */
+ mr_conf += 2;
+
if (num_codecs >= 2) {
- amr_mrc->bts_mode[0].threshold = mr_conf[1] & 0x3F;
- amr_mrc->bts_mode[0].hysteresis = mr_conf[2] >> 4;
+ amr_mrc->mode[0].threshold = mr_conf[0] & 0x3F;
+ amr_mrc->mode[0].hysteresis = mr_conf[1] >> 4;
}
if (num_codecs >= 3) {
- amr_mrc->bts_mode[1].threshold =
- ((mr_conf[2] & 0xF) << 2) | (mr_conf[3] >> 6);
- amr_mrc->bts_mode[1].hysteresis = (mr_conf[3] >> 2) & 0xF;
+ amr_mrc->mode[1].threshold =
+ ((mr_conf[1] & 0xF) << 2) | (mr_conf[2] >> 6);
+ amr_mrc->mode[1].hysteresis = (mr_conf[2] >> 2) & 0xF;
}
if (num_codecs >= 4) {
- amr_mrc->bts_mode[2].threshold =
- ((mr_conf[3] & 0x3) << 4) | (mr_conf[4] >> 4);
- amr_mrc->bts_mode[2].hysteresis = mr_conf[4] & 0xF;
+ amr_mrc->mode[2].threshold =
+ ((mr_conf[2] & 0x3) << 4) | (mr_conf[3] >> 4);
+ amr_mrc->mode[2].hysteresis = mr_conf[3] & 0xF;
}
return num_codecs;
@@ -168,3 +253,26 @@ unsigned int amr_get_initial_mode(struct gsm_lchan *lchan)
}
}
}
+
+void amr_init_mr_conf_def(struct gsm_lchan *lchan)
+{
+ const struct gsm48_multi_rate_conf *mr_cfg;
+ const struct amr_mode *bts_mode;
+ unsigned int num_modes;
+
+ if (lchan->type == GSM_LCHAN_TCH_F) {
+ num_modes = ARRAY_SIZE(amr_fr_bts_mode_def);
+ bts_mode = &amr_fr_bts_mode_def[0];
+ mr_cfg = &amr_fr_mr_cfg_def;
+ } else {
+ num_modes = ARRAY_SIZE(amr_hr_bts_mode_def);
+ bts_mode = &amr_hr_bts_mode_def[0];
+ mr_cfg = &amr_hr_mr_cfg_def;
+ }
+
+ memcpy(lchan->tch.amr_mr.gsm48_ie, mr_cfg,
+ sizeof(lchan->tch.amr_mr.gsm48_ie));
+ memcpy(&lchan->tch.amr_mr.mode[0], &bts_mode[0],
+ sizeof(lchan->tch.amr_mr.mode));
+ lchan->tch.amr_mr.num_modes = num_modes;
+}
diff --git a/src/common/asci.c b/src/common/asci.c
new file mode 100644
index 00000000..4342f17c
--- /dev/null
+++ b/src/common/asci.c
@@ -0,0 +1,211 @@
+/* ASCI (VGCS/VBS) related common code */
+
+/* (C) 2023 by Harald Welte <laforge@osmocom.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 Affero 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 <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/rsl.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/asci.h>
+
+static int tx_vgcs_ul_grant(struct gsm_lchan *lchan)
+{
+ struct gsm0408_vgcs_ul_grant ul_grant;
+ struct gsm_time gt;
+ struct msgb *msg;
+
+ gsm_fn2gsmtime(&gt, lchan->asci.fn);
+
+ /* build the RR VGCS UPLINK GRANT message as per TS 44.018 Section 9.1.49 */
+ ul_grant = (struct gsm0408_vgcs_ul_grant) {
+ .hdr = {
+ .proto_discr = GSM48_PDISC_RR,
+ .msg_type = GSM48_MT_RR_VGCS_UPL_GRANT,
+ },
+ .req_ref = {
+ .ra = lchan->asci.ref,
+ .t1 = gt.t1,
+ .t2 = gt.t2,
+ .t3_low = gt.t3 & 7,
+ .t3_high = gt.t3 >> 3,
+ },
+ .ta = lchan->ta_ctrl.current,
+ };
+
+ /* Wrap it in a RSL UNITDATA REQUEST */
+ msg = rsl_rll_simple(RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), 0x00, 0);
+ msg->l3h = msg->tail; /* emulate rsl_rx_rll() behaviour */
+ msgb_tl16v_put(msg, RSL_IE_L3_INFO, sizeof(ul_grant), (uint8_t *) &ul_grant);
+
+ /* send it towards MS, just like a RSL message from the BSC */
+ return lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
+}
+
+/* timer call-back for T3115 (VGCS UPLINK GRANT re-transmit) */
+static void vgcs_t3115_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "T3115 timeout (%d resends left)\n",
+ bts->ny2 - lchan->asci.vgcs_ul_grant_count);
+
+ if (lchan->state != LCHAN_S_ACTIVE) {
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "is not active. It is in state %s. Ignoring\n",
+ gsm_lchans_name(lchan->state));
+ return;
+ }
+
+ if (lchan->asci.vgcs_ul_grant_count >= bts->ny2) {
+ lchan->asci.vgcs_ul_grant_count = 0;
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "NY2 reached, sending CONNection FAILure to BSC.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_TALKER_ACC_FAIL);
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+ return;
+ }
+
+ tx_vgcs_ul_grant(lchan);
+ lchan->asci.vgcs_ul_grant_count++;
+ osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
+}
+
+/* Received random access on dedicated channel. */
+void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "VGCS RACH on dedicated channel type %s received with "
+ "TA=%u, ref=%u\n", gsm_lchant_name(lchan->type), acc_delay, ra);
+
+ if (ra == 0x25) { /* See TS 44.018 Table 9.1.45.1 */
+ /* Listener Detection (TS 48.058 Section 4.14) */
+ if (!lchan->asci.listener_detected) {
+ rsl_tx_listener_det(lchan, &acc_delay);
+ lchan->asci.listener_detected = true;
+ }
+ } else {
+ /* Talker Detection (TS 48.058 Section 4.13) */
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ /* Talker detection on group channels only */
+ if (!rsl_chan_rt_is_vgcs(lchan->rsl_chan_rt))
+ return;
+
+ if (lchan->asci.talker_active != VGCS_TALKER_NONE) {
+ LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Ignoring RACH, there is an active talker already.\n");
+ return;
+ }
+
+ /* Set timing advance, power level and activate SACCH */
+ lchan->ta_ctrl.current = acc_delay;
+ lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
+ lchan->want_dl_sacch_active = true;
+
+ /* Stop RACH detection, wait for valid frame */
+ lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
+ if (l1sap_uplink_access(lchan, false) != 0) {
+ LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to deactivate uplink access after TALKER DET.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+ return;
+ }
+
+ lchan->asci.ref = ra;
+ lchan->asci.fn = fn;
+
+ /* Send TALKER DETECT via RSL to BSC */
+ rsl_tx_talker_det(lchan, &acc_delay);
+
+ /* Send VGCS UPLINK GRANT */
+ lchan->asci.vgcs_ul_grant_count = 1;
+ tx_vgcs_ul_grant(lchan);
+
+ /* Start T3115 */
+ LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Starting T3115 with %u ms\n", bts->t3115_ms);
+ lchan->asci.t3115.cb = vgcs_t3115_cb;
+ lchan->asci.t3115.data = lchan;
+ osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
+ }
+}
+
+/* Received channel activation. */
+void vgcs_lchan_activate(struct gsm_lchan *lchan)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Channel is activated.\n");
+ if (l1sap_uplink_access(lchan, true) != 0) {
+ LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to activate uplink access after channel activation.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ }
+}
+
+/* Received channel reactivation. (for assignment) */
+void vgcs_lchan_react(struct gsm_lchan *lchan)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Channel is activated for assignment.\n");
+ lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
+ if (l1sap_uplink_access(lchan, false) != 0) {
+ LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to deactivate uplink access for assignment.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ }
+ radio_link_timeout_reset(lchan);
+}
+
+/* Received first valid data frame on dedicated channel. */
+void vgcs_talker_frame(struct gsm_lchan *lchan)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "First valid frame detected, talker now active.\n");
+ osmo_timer_del(&lchan->asci.t3115);
+ lchan->asci.talker_active = VGCS_TALKER_ACTIVE;
+ radio_link_timeout_reset(lchan);
+}
+
+/* Release VGCS Talker state. */
+void vgcs_talker_reset(struct gsm_lchan *lchan, bool ul_access)
+{
+ if (lchan->asci.talker_active == VGCS_TALKER_NONE)
+ return;
+
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Uplink released, no talker.\n");
+
+ /* Stop T3115 */
+ osmo_timer_del(&lchan->asci.t3115);
+
+ /* Talker released. */
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+ if (ul_access) {
+ if (l1sap_uplink_access(lchan, true) != 0) {
+ LOGPLCHAN(lchan, DASCI, LOGL_ERROR,
+ "Failed to activate uplink access after uplink became free.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ }
+ }
+}
+
+/* Release VGCS Listener state. */
+void vgcs_listener_reset(struct gsm_lchan *lchan)
+{
+ lchan->asci.listener_detected = false;
+}
diff --git a/src/common/bts.c b/src/common/bts.c
index 73631ae6..56765eca 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -32,6 +32,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/tdef.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
@@ -43,24 +44,27 @@
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <osmo-bts/pcuif_proto.h>
+#include <osmo-bts/pcu_if.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/signal.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <osmo-bts/cbch.h>
+#include <osmo-bts/bts_shutdown_fsm.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/power_control.h>
+#include <osmo-bts/osmux.h>
+#include <osmo-bts/notification.h>
+#define MAX_TA_DEF 63 /* default max Timing Advance value */
#define MIN_QUAL_RACH 50 /* minimum link quality (in centiBels) for Access Bursts */
#define MIN_QUAL_NORM -5 /* minimum link quality (in centiBels) for Normal Bursts */
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 },
- .num_bts = 0,
-};
-
void *tall_bts_ctx;
/* Table 3.1 TS 04.08: Values of parameter S */
@@ -86,17 +90,29 @@ static int bts_signal_cbfn(unsigned int subsys, unsigned int signal,
static const struct rate_ctr_desc bts_ctr_desc[] = {
[BTS_CTR_PAGING_RCVD] = {"paging:rcvd", "Received paging requests (Abis)"},
[BTS_CTR_PAGING_DROP] = {"paging:drop", "Dropped paging requests (Abis)"},
+ [BTS_CTR_PAGING_DROP_PS] = {"paging:drop-ps", "Dropped paging requests (PS/PCU)"},
+ [BTS_CTR_PAGING_CONG] = {"paging:cong", "Paging congestion detected (Abis)"},
[BTS_CTR_PAGING_SENT] = {"paging:sent", "Sent paging requests (Um)"},
[BTS_CTR_RACH_RCVD] = {"rach:rcvd", "Received RACH requests (Um)"},
[BTS_CTR_RACH_DROP] = {"rach:drop", "Dropped RACH requests (Um)"},
[BTS_CTR_RACH_HO] = {"rach:handover", "Received RACH requests (Handover)"},
+ [BTS_CTR_RACH_VGCS] = {"rach:vgcs", "Received RACH requests (VGCS)"},
[BTS_CTR_RACH_CS] = {"rach:cs", "Received RACH requests (CS/Abis)"},
[BTS_CTR_RACH_PS] = {"rach:ps", "Received RACH requests (PS/PCU)"},
[BTS_CTR_AGCH_RCVD] = {"agch:rcvd", "Received AGCH requests (Abis)"},
[BTS_CTR_AGCH_SENT] = {"agch:sent", "Sent AGCH requests (Abis)"},
[BTS_CTR_AGCH_DELETED] = {"agch:delete", "Sent AGCH DELETE IND (Abis)"},
+
+ [BTS_CTR_RTP_RX_TOTAL] = {"rtp:rx:total", "Total number of received RTP packets"},
+ [BTS_CTR_RTP_RX_MARKER] = {"rtp:rx:marker", "Number of received RTP packets with marker bit set"},
+ [BTS_CTR_RTP_RX_DROP_PREEN] = {"rtp:rx:drop:preen", "Total number of received RTP packets dropped during preening"},
+ [BTS_CTR_RTP_RX_DROP_LOOPBACK] = {"rtp:rx:drop:loopback", "Total number of received RTP packets dropped during loopback"},
+ [BTS_CTR_RTP_RX_DROP_OVERFLOW] = {"rtp:rx:drop:overflow", "Total number of received RTP packets dropped during DL queue overflow"},
+ [BTS_CTR_RTP_RX_DROP_V110_DEC] = {"rtp:rx:drop:v110_dec", "Total number of received RTP packets dropped during V.110 decode"},
+ [BTS_CTR_RTP_TX_TOTAL] = {"rtp:tx:total", "Total number of transmitted RTP packets"},
+ [BTS_CTR_RTP_TX_MARKER] = {"rtp:tx:marker", "Number of transmitted RTP packets with marker bit set"},
};
static const struct rate_ctr_group_desc bts_ctrg_desc = {
"bts",
@@ -122,6 +138,178 @@ static const struct rate_ctr_group_desc cbch_ctrg_desc = {
cbch_ctr_desc
};
+struct osmo_tdef bts_T_defs[] = {
+ /* T-1: FIXME: Ideally should be dynamically calculated per trx at
+ * shutdown start based on params below, and highest trx value taken:
+ * + VTY's power-ramp step-interval.
+ * + Amount of steps needed (taking into account how many dB each step moves).
+ * + Extra time to get response back for each step.
+ * For now we simply give 5 mins, which should be enough for any
+ * acceptable setup, while still ensuring will timeout at some point if
+ * something fails in the ramp down procedure.
+ */
+ { .T=-1, .default_val=300, .desc="Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s)" },
+ { .T=-2, .default_val=3, .desc="Time after which osmo-bts exits if requesting transceivers to stop during shut down process does not finish (s)" },
+ {}
+};
+
+struct osmo_tdef abis_T_defs[] = {
+ { .T=-15, .default_val=0, .unit=OSMO_TDEF_MS, .desc="Time to wait between Channel Activation and dispatching a cached early Immediate Assignment" },
+ {}
+};
+
+static const uint8_t bts_cell_timer_default[] =
+ { 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
+static const struct gprs_rlc_cfg rlc_cfg_default = {
+ .parameter = {
+ [RLC_T3142] = 20,
+ [RLC_T3169] = 5,
+ [RLC_T3191] = 5,
+ [RLC_T3193] = 160, /* 10ms */
+ [RLC_T3195] = 5,
+ [RLC_N3101] = 10,
+ [RLC_N3103] = 4,
+ [RLC_N3105] = 8,
+ [CV_COUNTDOWN] = 15,
+ [T_DL_TBF_EXT] = 250 * 10, /* ms */
+ [T_UL_TBF_EXT] = 250 * 10, /* ms */
+ },
+ .paging = {
+ .repeat_time = 5 * 50, /* ms */
+ .repeat_count = 3,
+ },
+ .cs_mask = 0x1fff,
+ .initial_cs = 2,
+ .initial_mcs = 6,
+};
+
+const struct value_string osmo_bts_variant_names[_NUM_BTS_VARIANT + 1] = {
+ { BTS_UNKNOWN, "unknown" },
+ { BTS_OSMO_LITECELL15, "osmo-bts-lc15" },
+ { BTS_OSMO_OC2G, "osmo-bts-oc2g" },
+ { BTS_OSMO_OCTPHY, "osmo-bts-octphy" },
+ { BTS_OSMO_SYSMO, "osmo-bts-sysmo" },
+ { BTS_OSMO_TRX, "osmo-bts-trx" },
+ { BTS_OSMO_VIRTUAL, "osmo-bts-virtual" },
+ { BTS_OSMO_OMLDUMMY, "osmo-bts-omldummy" },
+ { 0, NULL }
+};
+
+const char *btsvariant2str(enum gsm_bts_type_variant v)
+{
+ return get_value_string(osmo_bts_variant_names, v);
+}
+
+const struct value_string bts_attribute_names[] = {
+ OSMO_VALUE_STRING(BTS_TYPE_VARIANT),
+ OSMO_VALUE_STRING(BTS_SUB_MODEL),
+ OSMO_VALUE_STRING(TRX_PHY_VERSION),
+ { 0, NULL }
+};
+
+const char *btsatttr2str(enum bts_attribute v)
+{
+ return get_value_string(bts_attribute_names, v);
+}
+
+const struct value_string bts_impl_flag_desc[] = {
+ { BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP, "DSP/HW based MS Power Control Loop" },
+ { BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB, "Measurement and Payload data combined" },
+ { BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER, "OML RadioChannel MO depends on RadioCarrier MO" },
+ { BTS_INTERNAL_FLAG_INTERF_MEAS, "Uplink interference measurements" },
+ { 0, NULL }
+};
+
+/* Ensure that all BTS_INTERNAL_FLAG_* entries are present in bts_impl_flag_desc[] */
+osmo_static_assert(ARRAY_SIZE(bts_impl_flag_desc) == _BTS_INTERNAL_FLAG_NUM + 1, _bts_impl_flag_desc);
+
+static int gsm_bts_talloc_destructor(struct gsm_bts *bts)
+{
+ if (bts->mo.fi) {
+ osmo_fsm_inst_free(bts->mo.fi);
+ bts->mo.fi = NULL;
+ }
+ if (bts->shutdown_fi) {
+ osmo_fsm_inst_free(bts->shutdown_fi);
+ bts->shutdown_fi = NULL;
+ }
+
+ bts_osmux_release(bts);
+
+ llist_del(&bts->list);
+ g_bts_sm->num_bts--;
+ return 0;
+}
+
+struct gsm_bts *gsm_bts_alloc(struct gsm_bts_sm *bts_sm, uint8_t bts_num)
+{
+ struct gsm_bts *bts = talloc_zero(bts_sm, struct gsm_bts);
+
+ if (!bts)
+ return NULL;
+
+ talloc_set_destructor(bts, gsm_bts_talloc_destructor);
+
+ /* add to list of BTSs */
+ llist_add_tail(&bts->list, &bts_sm->bts_list);
+ g_bts_sm->num_bts++;
+
+ bts->site_mgr = bts_sm;
+ bts->nr = bts_num;
+ bts->num_trx = 0;
+ INIT_LLIST_HEAD(&bts->trx_list);
+ bts->ms_max_power = 15; /* dBm */
+
+ bts->T_defs = bts_T_defs;
+ osmo_tdefs_reset(bts->T_defs);
+ osmo_tdefs_reset(abis_T_defs);
+ bts->shutdown_fi = osmo_fsm_inst_alloc(&bts_shutdown_fsm, bts, bts,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(bts->shutdown_fi, "bts%d", bts->nr);
+
+ /* NM BTS */
+ bts->mo.fi = osmo_fsm_inst_alloc(&nm_bts_fsm, bts, bts,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(bts->mo.fi, "bts%d", bts->nr);
+ gsm_mo_init(&bts->mo, bts, NM_OC_BTS, bts->nr, 0xff, 0xff);
+
+ /* NM GPRS CELL */
+ bts->gprs.cell.mo.fi = osmo_fsm_inst_alloc(&nm_gprs_cell_fsm, bts, &bts->gprs.cell,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(bts->gprs.cell.mo.fi, "gprs_cell%d-0", bts->nr);
+ gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL, bts->nr, 0, 0xff);
+ memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default, sizeof(bts->gprs.cell.rlc_cfg));
+ memcpy(&bts->gprs.cell.timer, bts_cell_timer_default, sizeof(bts->gprs.cell.timer));
+
+ /* create our primary TRX. It will be initialized during bts_init() */
+ bts->c0 = gsm_bts_trx_alloc(bts);
+ if (!bts->c0) {
+ talloc_free(bts);
+ return NULL;
+ }
+ bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
+
+ bts->features = bitvec_alloc(MAX_BTS_FEATURES / 8, bts);
+ OSMO_ASSERT(bts->features != NULL);
+
+ return bts;
+}
+
+struct gsm_bts *gsm_bts_num(const struct gsm_bts_sm *bts_sm, int num)
+{
+ struct gsm_bts *bts;
+
+ if (num >= bts_sm->num_bts)
+ return NULL;
+
+ llist_for_each_entry(bts, &bts_sm->bts_list, list) {
+ if (bts->nr == num)
+ return bts;
+ }
+
+ return NULL;
+}
+
/* Initialize the BTS data structures, called before config
* file reading */
int bts_init(struct gsm_bts *bts)
@@ -130,19 +318,14 @@ int bts_init(struct gsm_bts *bts)
static int initialized = 0;
void *tall_rtp_ctx;
- /* add to list of BTSs */
- llist_add_tail(&bts->list, &bts_gsmnet.bts_list);
-
bts->band = GSM_BAND_1800;
INIT_LLIST_HEAD(&bts->agch_queue.queue);
bts->agch_queue.length = 0;
bts->ctrs = rate_ctr_group_alloc(bts, &bts_ctrg_desc, bts->nr);
- if (!bts->ctrs) {
- llist_del(&bts->list);
+ if (!bts->ctrs)
return -1;
- }
/* enable management with default levels,
* raise threshold to GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE to
@@ -154,56 +337,72 @@ int bts_init(struct gsm_bts *bts)
/* configurable via VTY */
bts->paging_state = paging_init(bts, 200, 0);
- bts->ul_power_target = -75; /* dBm default */
bts->rtp_jitter_adaptive = false;
bts->rtp_port_range_start = 16384;
bts->rtp_port_range_end = 17407;
bts->rtp_port_range_next = bts->rtp_port_range_start;
+ bts->rtp_ip_dscp = -1;
+ bts->rtp_priority = -1;
+ bts->emit_hr_rfc5993 = true;
+
+ /* Default (fall-back) MS/BS Power control parameters */
+ power_ctrl_params_def_reset(&bts->bs_dpc_params, true);
+ power_ctrl_params_def_reset(&bts->ms_dpc_params, false);
/* configurable via OML */
+ bts->bsic = 0xff; /* invalid value, guarded by bsc_configured=false */
+ bts->bsic_configured = false;
bts->load.ccch.load_ind_period = 112;
- load_timer_start(bts);
bts->rtp_jitter_buf_ms = 100;
- bts->max_ta = 63;
+ bts->max_ta = MAX_TA_DEF;
bts->ny1 = 4;
+ bts->ny2 = 4;
bts->t3105_ms = 300;
+ bts->t3115_ms = 300;
bts->min_qual_rach = MIN_QUAL_RACH;
bts->min_qual_norm = MIN_QUAL_NORM;
bts->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
bts->pcu.sock_path = talloc_strdup(bts, PCU_SOCK_DEFAULT);
- for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++)
- bts->t200_ms[i] = oml_default_t200_ms[i];
+ bts->pcu.sock_wqueue_len_max = BTS_PCU_SOCK_WQUEUE_LEN_DEFAULT;
+ for (i = 0; i < ARRAY_SIZE(bts->t200_fn); i++)
+ bts->t200_fn[i] = oml_default_t200_fn[i];
/* default RADIO_LINK_TIMEOUT */
- bts->radio_link_timeout = 32;
-
- /* Start with the site manager */
- oml_mo_state_init(&bts->site_mgr.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
+ bts->radio_link_timeout.oml = 32;
+ bts->radio_link_timeout.current = bts->radio_link_timeout.oml;
- /* set BTS to dependency */
- oml_mo_state_init(&bts->mo, -1, NM_AVSTATE_DEPENDENCY);
- oml_mo_state_init(&bts->gprs.nse.mo, -1, NM_AVSTATE_DEPENDENCY);
- oml_mo_state_init(&bts->gprs.cell.mo, -1, NM_AVSTATE_DEPENDENCY);
- oml_mo_state_init(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_DEPENDENCY);
- oml_mo_state_init(&bts->gprs.nsvc[1].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
+ /* Start with the BTS */
+ oml_mo_state_init(&bts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+ oml_mo_state_init(&bts->gprs.cell.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
/* allocate a talloc pool for ORTP to ensure it doesn't have to go back
* to the libc malloc all the time */
tall_rtp_ctx = talloc_pool(tall_bts_ctx, 262144);
osmo_rtp_init(tall_rtp_ctx);
- /* features implemented in 'common', available for all models */
- gsm_bts_set_feature(bts, BTS_FEAT_ETWS_PN);
+ /* Osmux */
+ rc = bts_osmux_init(bts);
+ if (rc < 0)
+ return rc;
+
+ /* features implemented in 'common', available for all models,
+ * order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_ABIS_OSMO_PCU);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CCN);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_DYN_TS_SDCCH8);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_ETWS_PN);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_IPV6_NSVC);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_PAGING_COORDINATION);
+
+ /* Maximum TA supported by the PHY (can be overridden by PHY specific code) */
+ bts->support.max_ta = MAX_TA_DEF;
rc = bts_model_init(bts);
- if (rc < 0) {
- llist_del(&bts->list);
+ if (rc < 0)
return rc;
- }
/* TRX0 was allocated early during gsm_bts_alloc, not later through VTY */
- bts_trx_init(bts->c0);
- bts_gsmnet.num_bts++;
+ bts_model_trx_init(bts->c0);
if (!initialized) {
osmo_signal_register_handler(SS_GLOBAL, bts_signal_cbfn, NULL);
@@ -220,7 +419,10 @@ int bts_init(struct gsm_bts *bts)
bts->smscb_queue_tgt_len = 2;
bts->smscb_queue_hyst = 2;
- INIT_LLIST_HEAD(&bts->oml_queue);
+ bts->asci.pos_nch = -ENOTSUP;
+ INIT_LLIST_HEAD(&bts->asci.notifications);
+
+ INIT_LLIST_HEAD(&bts->bsc_oml_hosts);
/* register DTX DL FSM */
rc = osmo_fsm_register(&dtx_dl_amr_fsm);
@@ -234,206 +436,20 @@ int bts_init(struct gsm_bts *bts)
return rc;
}
-/* Initialize the TRX data structures, called before config
- * file reading */
-int bts_trx_init(struct gsm_bts_trx *trx)
-{
- /* initialize bts data structure */
- struct trx_power_params *tpp = &trx->power_params;
- int rc, i;
-
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[i];
- int k;
-
- for (k = 0; k < ARRAY_SIZE(ts->lchan); k++) {
- struct gsm_lchan *lchan = &ts->lchan[k];
- INIT_LLIST_HEAD(&lchan->dl_tch_queue);
- }
- }
- /* Default values for the power adjustments */
- tpp->ramp.max_initial_pout_mdBm = to_mdB(0);
- tpp->ramp.step_size_mdB = to_mdB(2);
- tpp->ramp.step_interval_sec = 1;
-
- rc = bts_model_trx_init(trx);
- if (rc < 0) {
- llist_del(&trx->list);
- return rc;
- }
- return 0;
-}
-
-static void shutdown_timer_cb(void *data)
-{
- fprintf(stderr, "Shutdown timer expired\n");
- exit(42);
-}
-
-static struct osmo_timer_list shutdown_timer = {
- .cb = &shutdown_timer_cb,
-};
-
-void bts_shutdown(struct gsm_bts *bts, const char *reason)
-{
- struct gsm_bts_trx *trx;
-
- if (osmo_timer_pending(&shutdown_timer)) {
- LOGP(DOML, LOGL_NOTICE,
- "BTS is already being shutdown.\n");
- return;
- }
-
- LOGP(DOML, LOGL_NOTICE, "Shutting down BTS %u, Reason %s\n",
- bts->nr, reason);
-
- llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
- bts_model_trx_deact_rf(trx);
- bts_model_trx_close(trx);
- }
-
- /* shedule a timer to make sure select loop logic can run again
- * to dispatch any pending primitives */
- osmo_timer_schedule(&shutdown_timer, 3, 0);
-}
-
/* main link is established, send status report */
int bts_link_estab(struct gsm_bts *bts)
{
- int i, j;
-
- LOGP(DSUM, LOGL_INFO, "Main link established, sending Status'.\n");
-
- /* BTS and SITE MGR are EANBLED, BTS is DEPENDENCY */
- oml_tx_state_changed(&bts->site_mgr.mo);
- oml_tx_state_changed(&bts->mo);
+ LOGP(DOML, LOGL_INFO, "Main link established, sending NM Status\n");
- /* those should all be in DEPENDENCY */
- oml_tx_state_changed(&bts->gprs.nse.mo);
- oml_tx_state_changed(&bts->gprs.cell.mo);
- oml_tx_state_changed(&bts->gprs.nsvc[0].mo);
- oml_tx_state_changed(&bts->gprs.nsvc[1].mo);
-
- /* All other objects start off-line until the BTS Model code says otherwise */
- for (i = 0; i < bts->num_trx; i++) {
- struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
-
- oml_tx_state_changed(&trx->mo);
- oml_tx_state_changed(&trx->bb_transc.mo);
-
- for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[j];
-
- oml_tx_state_changed(&ts->mo);
- }
- }
+ /* Signal OML UP to BTS SITE MGR. It will automatically SW_ACT repoort
+ * and become Disabled-Offline, then dispatch same event to its children
+ * objects.
+ */
+ osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_OML_UP, NULL);
return bts_model_oml_estab(bts);
}
-/* RSL link is established, send status report */
-int trx_link_estab(struct gsm_bts_trx *trx)
-{
- struct e1inp_sign_link *link = trx->rsl_link;
- uint8_t radio_state = link ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
- int rc;
-
- LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n",
- trx->nr, link ? "up" : "down");
-
- oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK);
-
- if (link)
- rc = rsl_tx_rf_res(trx);
- else
- rc = bts_model_trx_deact_rf(trx);
- if (rc < 0) {
- oml_tx_failure_event_rep(&trx->bb_transc.mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_RSL_FAIL,
- link ?
- "Failed to establish RSL link (%d)" :
- "Failed to deactivate RF (%d)", rc);
- }
-
- 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) {
- int op_state = trx->rsl_link ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
- oml_mo_state_chg(&trx->mo, op_state, NM_AVSTATE_OK);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
- for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, op_state, NM_AVSTATE_OK);
- } else {
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_NOT_INSTALLED);
-
- for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
- }
- return 0;
-}
-
-/* prepare the per-SAPI T200 arrays for a given lchan */
-static int t200_by_lchan(int *t200_ms_dcch, int *t200_ms_acch, struct gsm_lchan *lchan)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
-
- /* we have to compensate for the "RTS advance" due to the asynchronous interface between
- * the BTS (LAPDm) and the PHY/L1 (OsmoTRX or DSP in case of osmo-bts-{sysmo,lc15,oc2g,octphy} */
- int32_t fn_advance = bts_get_avg_fn_advance(bts);
- int32_t fn_advance_us = fn_advance * 4615;
- int fn_advance_ms = fn_advance_us / 1000;
-
- t200_ms_acch[DL_SAPI0] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
- t200_ms_acch[DL_SAPI3] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
-
- switch (lchan->type) {
- case GSM_LCHAN_SDCCH:
- t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_SDCCH] + fn_advance_ms;
- t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_SDCCH_SAPI3] + fn_advance_ms;
- break;
- case GSM_LCHAN_TCH_F:
- t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
- t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
- break;
- case GSM_LCHAN_TCH_H:
- t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
- t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
- break;
- default:
- /* Channels such as CCCH don't use lapdm DL, and hence no T200 is needed */
- return -1;
- }
- return 0;
-}
-
-int lchan_init_lapdm(struct gsm_lchan *lchan)
-{
- struct lapdm_channel *lc = &lchan->lapdm_ch;
- int t200_ms_dcch[_NR_DL_SAPI], t200_ms_acch[_NR_DL_SAPI];
-
- if (t200_by_lchan(t200_ms_dcch, t200_ms_acch, lchan) == 0) {
- LOGPLCHAN(lchan, DLLAPD, LOGL_DEBUG,
- "Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in ms)\n",
- t200_ms_dcch[DL_SAPI0], t200_ms_dcch[DL_SAPI3],
- t200_ms_acch[DL_SAPI0], t200_ms_acch[DL_SAPI3]);
- lapdm_channel_init2(lc, LAPDM_MODE_BTS, t200_ms_dcch, t200_ms_acch, lchan->type);
- lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY);
- lapdm_channel_set_l1(lc, NULL, lchan);
- }
- /* We still need to set Rx callback to receive RACH requests: */
- lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);
-
- return 0;
-}
-
#define CCCH_RACH_RATIO_COMBINED256 (256*1/9)
#define CCCH_RACH_RATIO_SEPARATE256 (256*10/55)
@@ -591,7 +607,7 @@ static int try_merge_imm_ass_rej(struct gsm48_imm_ass_rej *old_rej,
return 0;
/* GSM 08.58, 5.7
- * -> The BTS may combine serveral IMM.ASS.REJ messages
+ * -> The BTS may combine several IMM.ASS.REJ messages
* -> Identical request refs in one message may be squeezed
*
* GSM 04.08, 9.1.20.2
@@ -628,7 +644,7 @@ int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
struct gsm48_imm_ass_rej *imm_ass_cmd = msgb_l3(msg);
if (bts->agch_queue.length > hard_limit) {
- LOGP(DSUM, LOGL_ERROR,
+ LOGP(DRR, LOGL_ERROR,
"AGCH: too many messages in queue, "
"refusing message type %s, length = %d/%d\n",
gsm48_rr_msg_name(((struct gsm48_imm_ass *)msgb_l3(msg))->msg_type),
@@ -656,7 +672,7 @@ int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
return 0;
}
-struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
+static struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
{
struct msgb *msg = msgb_dequeue(&bts->agch_queue.queue);
if (!msg)
@@ -669,7 +685,7 @@ struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
/*
* Remove lower prio messages if the queue has grown too long.
*
- * \return 0 iff the number of messages in the queue would fit into the AGCH
+ * \return 0 if the number of messages in the queue would fit into the AGCH
* reserved part of the CCCH.
*/
static void compact_agch_queue(struct gsm_bts *bts)
@@ -722,12 +738,12 @@ static void compact_agch_queue(struct gsm_bts *bts)
return;
}
-int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
- int is_ag_res)
+int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch)
{
struct msgb *msg = NULL;
int rc = 0;
int is_empty = 1;
+ const struct bts_agch_msg_cb *msg_cb;
/* Do queue house keeping.
* This needs to be done every time a CCCH message is requested, since
@@ -736,26 +752,39 @@ int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt
*/
compact_agch_queue(bts);
- /* Check for paging messages first if this is PCH */
- if (!is_ag_res)
- rc = paging_gen_msg(bts->paging_state, out_buf, gt, &is_empty);
-
- /* Check whether the block may be overwritten */
- if (!is_empty)
- return rc;
-
- msg = bts_agch_dequeue(bts);
- if (!msg)
+ switch (ccch) {
+ case CCCH_MSGT_NCH:
+ /* Send NCH message, it has priority over AGCH and does not overlap with PCH. */
+ rc = bts_asci_notify_nch_gen_msg(bts, out_buf);
return rc;
+ case CCCH_MSGT_PCH:
+ /* Check whether the block may be overwritten by AGCH. */
+ rc = paging_gen_msg(bts->paging_state, out_buf, gt, &is_empty);
+ if (!is_empty)
+ return rc;
+ /* fall-through */
+ case CCCH_MSGT_AGCH:
+ /* If fallen here and the AGCH queue is empty, return empty PCH message. */
+ msg = bts_agch_dequeue(bts);
+ if (!msg)
+ return rc;
+ /* Continue to return AGCH message. */
+ break;
+ }
rate_ctr_inc2(bts->ctrs, BTS_CTR_AGCH_SENT);
+ /* Confirm sending of the AGCH message towards the PCU */
+ msg_cb = (struct bts_agch_msg_cb *) msg->cb;
+ if (msg_cb->confirm)
+ pcu_tx_data_cnf(msg_cb->msg_id, PCU_IF_SAPI_AGCH_2);
+
/* Copy AGCH message */
memcpy(out_buf, msgb_l3(msg), msgb_l3len(msg));
rc = msgb_l3len(msg);
msgb_free(msg);
- if (is_ag_res)
+ if (ccch == CCCH_MSGT_AGCH)
bts->agch_queue.agch_msgs++;
else
bts->agch_queue.pch_msgs++;
@@ -778,69 +807,206 @@ int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher)
return sup > 0;
}
-int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx)
-{
- return trx->ms_power_control == 1;
-}
-
struct gsm_time *get_time(struct gsm_bts *bts)
{
return &bts->gsm_time;
}
-int bts_supports_cm(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
- enum gsm48_chan_mode cm)
+bool bts_supports_cm_speech(const struct gsm_bts *bts,
+ const struct rsl_ie_chan_mode *cm)
{
- enum gsm_bts_features feature = _NUM_BTS_FEAT;
-
- /* We assume that signalling support is mandatory,
- * there is no BTS_FEAT_* definition to check that. */
- if (cm == GSM48_CMODE_SIGN)
- return 1;
+ enum osmo_bts_features feature = _NUM_BTS_FEAT;
+
+ /* Stage 1: check support for the requested channel type */
+ switch (cm->chan_rt) {
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VGCS))
+ return false;
+ break;
+ case RSL_CMOD_CRT_TCH_BCAST_Bm:
+ case RSL_CMOD_CRT_TCH_BCAST_Lm:
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VBS))
+ return false;
+ break;
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VAMOS))
+ return false;
+ break;
+ }
- /* Before the requested pchan/cm combination can be checked, we need to
- * convert it to a feature identifier we can check */
- switch (pchan) {
- case GSM_PCHAN_TCH_F:
- switch(cm) {
- case GSM48_CMODE_SPEECH_V1:
+ /* Stage 2: check support for the requested codec */
+ switch (cm->chan_rt) {
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_BCAST_Bm:
+ case RSL_CMOD_CRT_TCH_Bm:
+ switch (cm->chan_rate) {
+ case RSL_CMOD_SP_GSM1:
feature = BTS_FEAT_SPEECH_F_V1;
break;
- case GSM48_CMODE_SPEECH_EFR:
+ case RSL_CMOD_SP_GSM2:
feature = BTS_FEAT_SPEECH_F_EFR;
break;
- case GSM48_CMODE_SPEECH_AMR:
+ case RSL_CMOD_SP_GSM3:
feature = BTS_FEAT_SPEECH_F_AMR;
break;
default:
/* Invalid speech codec type => Not supported! */
- return 0;
+ return false;
}
break;
- case GSM_PCHAN_TCH_H:
- switch(cm) {
- case GSM48_CMODE_SPEECH_V1:
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ case RSL_CMOD_CRT_TCH_BCAST_Lm:
+ case RSL_CMOD_CRT_TCH_Lm:
+ switch (cm->chan_rate) {
+ case RSL_CMOD_SP_GSM1:
feature = BTS_FEAT_SPEECH_H_V1;
break;
- case GSM48_CMODE_SPEECH_AMR:
+ case RSL_CMOD_SP_GSM3:
feature = BTS_FEAT_SPEECH_H_AMR;
break;
default:
/* Invalid speech codec type => Not supported! */
- return 0;
+ return false;
}
break;
default:
- LOGP(DRSL, LOGL_ERROR, "BTS %u: unhandled pchan %s when checking mode %s\n",
- bts->nr, gsm_pchan_name(pchan), gsm48_chan_mode_name(cm));
- return 0;
+ LOGP(DRSL, LOGL_ERROR,
+ "Unhandled RSL channel type=0x%02x/rate=0x%02x\n",
+ cm->chan_rt, cm->chan_rate);
+ return false;
}
/* Check if the feature is supported by this BTS */
- if (gsm_bts_has_feature(bts, feature))
- return 1;
+ if (osmo_bts_has_feature(bts->features, feature))
+ return true;
+
+ return false;
+}
+
+static bool bts_supports_cm_data(const struct gsm_bts *bts,
+ const struct rsl_ie_chan_mode *cm)
+{
+ switch (bts->variant) {
+ case BTS_OSMO_TRX:
+ switch (cm->chan_rate) {
+ /* TODO: RSL_CMOD_CSD_NT_14k5 */
+ /* TODO: RSL_CMOD_CSD_T_14k4 */
+ case RSL_CMOD_CSD_NT_12k0:
+ case RSL_CMOD_CSD_T_9k6:
+ if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm)
+ return false; /* invalid */
+ /* fall-through */
+ case RSL_CMOD_CSD_NT_6k0:
+ case RSL_CMOD_CSD_T_4k8:
+ case RSL_CMOD_CSD_T_2k4:
+ case RSL_CMOD_CSD_T_1k2:
+ case RSL_CMOD_CSD_T_600:
+ case RSL_CMOD_CSD_T_1200_75:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return 0;
+ }
+}
+
+bool bts_supports_cm(const struct gsm_bts *bts,
+ const struct rsl_ie_chan_mode *cm)
+{
+ switch (cm->spd_ind) {
+ case RSL_CMOD_SPD_SIGN:
+ /* We assume that signalling support is mandatory,
+ * there is no BTS_FEAT_* definition to check that. */
+ return true;
+ case RSL_CMOD_SPD_SPEECH:
+ return bts_supports_cm_speech(bts, cm);
+ case RSL_CMOD_SPD_DATA:
+ return bts_supports_cm_data(bts, cm);
+ default:
+ return false;
+ }
+}
+
+/* return the gsm_lchan for the CBCH (if it exists at all) */
+struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx = bts->c0;
+
+ /* According to 3GPP TS 45.002, table 3, CBCH can be allocated
+ * either on C0/TS0 (CCCH+SDCCH4) or on C0..n/TS0..3 (SDCCH/8). */
+ if (trx->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH)
+ return &trx->ts[0].lchan[2]; /* C0/TS0 */
+
+ llist_for_each_entry(trx, &bts->trx_list, list) { /* C0..n */
+ unsigned int tn;
+ for (tn = 0; tn <= 3; tn++) { /* TS0..3 */
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C_CBCH)
+ return &ts->lchan[2];
+ }
+ }
+
+ return NULL;
+}
+
+/* BCCH carrier power reduction (see 3GPP TS 45.008, section 7.1) */
+int bts_set_c0_pwr_red(struct gsm_bts *bts, const uint8_t red)
+{
+ struct gsm_bts_trx *c0 = bts->c0;
+ unsigned int tn;
+
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_BCCH_POWER_RED)) {
+ LOGPTRX(c0, DRSL, LOGL_ERROR, "BCCH carrier power reduction "
+ "is not supported by this BTS model\n");
+ return -ENOTSUP;
+ }
+
+ if (red > 6 || red % 2 != 0) {
+ LOGPTRX(c0, DRSL, LOGL_ERROR, "BCCH carrier power reduction "
+ "value (%u dB) is incorrect or out of range\n", red);
+ return -EINVAL;
+ }
+
+ LOGPTRX(c0, DRSL, LOGL_NOTICE, "BCCH carrier power reduction: "
+ "%u dB (%s)\n", red, red ? "enabled" : "disabled");
+
+ /* Timeslot 0 is always transmitting BCCH/CCCH */
+ c0->ts[0].c0_power_red_db = 0;
+
+ for (tn = 1; tn < ARRAY_SIZE(c0->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &c0->ts[tn];
+ struct gsm_bts_trx_ts *prev = ts - 1;
+
+ switch (ts_pchan(ts)) {
+ /* Not allowed on CCCH/BCCH */
+ case GSM_PCHAN_CCCH:
+ /* Preceeding timeslot shall not exceed 2 dB */
+ if (prev->c0_power_red_db > 0)
+ prev->c0_power_red_db = 2;
+ /* fall-through */
+ /* Not recommended on SDCCH/8 */
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ ts->c0_power_red_db = 0;
+ break;
+ default:
+ ts->c0_power_red_db = red;
+ break;
+ }
+ }
+
+ /* Timeslot 7 is always preceding BCCH/CCCH */
+ if (c0->ts[7].c0_power_red_db > 0)
+ c0->ts[7].c0_power_red_db = 2;
+
+ bts->c0_power_red_db = red;
return 0;
}
diff --git a/src/common/bts_ctrl_commands.c b/src/common/bts_ctrl_commands.c
index 0d318900..5f6857cf 100644
--- a/src/common/bts_ctrl_commands.c
+++ b/src/common/bts_ctrl_commands.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -57,7 +57,7 @@ static int set_therm_att(struct ctrl_cmd *cmd, void *data)
tpp->thermal_attenuation_mdB = val;
- power_ramp_start(trx, tpp->p_total_cur_mdBm, 0);
+ power_ramp_start(trx, tpp->p_total_cur_mdBm, 0, NULL);
return get_therm_att(cmd, data);
}
@@ -84,12 +84,45 @@ static int set_oml_alert(struct ctrl_cmd *cmd, void *data)
return CTRL_CMD_REPLY;
}
+static int verify_max_ber10k_rach(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ int max_ber10k_rach = atoi(cmd->value);
+
+ if (max_ber10k_rach < 0 || max_ber10k_rach > 10000) {
+ cmd->reply = "Value is out of range";
+ return 1;
+ }
+
+ return 0;
+}
+
+static int get_max_ber10k_rach(struct ctrl_cmd *cmd, void *data)
+{
+ cmd->reply = talloc_asprintf(cmd, "%u", g_bts->max_ber10k_rach);
+ if (!cmd->reply) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+
+ return CTRL_CMD_REPLY;
+}
+
+static int set_max_ber10k_rach(struct ctrl_cmd *cmd, void *data)
+{
+ g_bts->max_ber10k_rach = atoi(cmd->value);
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE(max_ber10k_rach, "max-ber10k-rach");
+
int bts_ctrl_cmds_install(struct gsm_bts *bts)
{
int rc = 0;
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_therm_att);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_oml_alert);
+ rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_max_ber10k_rach);
g_bts = bts;
return rc;
diff --git a/src/common/bts_ctrl_lookup.c b/src/common/bts_ctrl_lookup.c
index f0157e9a..2a5ff522 100644
--- a/src/common/bts_ctrl_lookup.c
+++ b/src/common/bts_ctrl_lookup.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -28,6 +28,7 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/control_if.h>
+#include <osmo-bts/bts_trx.h>
extern vector ctrl_node_vec;
@@ -87,14 +88,12 @@ err_index:
return -ERANGE;
}
-struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
- const char *bind_addr, uint16_t port)
+struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts, uint16_t port)
{
struct ctrl_handle *hdl;
int rc = 0;
- hdl = ctrl_interface_setup_dynip(bts, bind_addr, port,
- bts_ctrl_node_lookup);
+ hdl = ctrl_interface_setup(bts, port, bts_ctrl_node_lookup);
if (!hdl)
return NULL;
diff --git a/src/common/bts_shutdown_fsm.c b/src/common/bts_shutdown_fsm.c
new file mode 100644
index 00000000..13a0e1d0
--- /dev/null
+++ b/src/common/bts_shutdown_fsm.c
@@ -0,0 +1,283 @@
+/* BTS shutdown FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/bts_shutdown_fsm.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+#define X(s) (1 << (s))
+
+#define BTS_SHUTDOWN_POWER_RAMP_TGT -10
+
+static const struct osmo_tdef_state_timeout bts_shutdown_fsm_timeouts[32] = {
+ [BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL] = { .T = -1 },
+ [BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED] = { .T = -2 },
+};
+
+#define bts_shutdown_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, bts_shutdown_fsm_timeouts, ((struct gsm_bts *)fi->priv)->T_defs, -1)
+
+static unsigned int count_trx_operational(struct gsm_bts *bts) {
+ unsigned int count = 0;
+ struct gsm_bts_trx *trx;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED)
+ count++;
+ }
+ return count;
+}
+
+static void st_none(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ unsigned int count;
+ switch(event) {
+ case BTS_SHUTDOWN_EV_START:
+ /* Firt announce to NM objects that we are starting a shutdown procedure: */
+ osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_SHUTDOWN_START, NULL);
+
+ count = count_trx_operational(bts);
+ if (count) {
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL);
+ } else {
+ /* we can skip ramp down since no TRX is running anyway.
+ * Let's jump into WAIT_TRX_CLOSED to make sure we
+ * tell lower layer to close all TRX in case there's some
+ * open() WIP */
+ LOGPFSML(fi, LOGL_INFO, "No TRX is operational, skipping power ramp down\n");
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED);
+ }
+ break;
+ }
+}
+
+static void ramp_down_compl_cb(struct gsm_bts_trx *trx) {
+ osmo_fsm_inst_dispatch(trx->bts->shutdown_fi, BTS_SHUTDOWN_EV_TRX_RAMP_COMPL, trx);
+}
+
+static void st_wait_ramp_down_compl_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct gsm_bts_trx *trx;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (bts->shutdown_fi_skip_power_ramp)
+ power_ramp_force(trx, to_mdB(BTS_SHUTDOWN_POWER_RAMP_TGT), 1, ramp_down_compl_cb);
+ else
+ power_ramp_start(trx, to_mdB(BTS_SHUTDOWN_POWER_RAMP_TGT), 1, ramp_down_compl_cb);
+ }
+}
+
+static void st_wait_ramp_down_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct gsm_bts_trx *src_trx;
+ unsigned int remaining = 0;
+ struct gsm_bts_trx *trx;
+
+ switch(event) {
+ case BTS_SHUTDOWN_EV_TRX_RAMP_COMPL:
+ src_trx = (struct gsm_bts_trx *)data;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED &&
+ trx->power_params.p_total_cur_mdBm > BTS_SHUTDOWN_POWER_RAMP_TGT)
+ remaining++;
+ }
+
+ LOGPFSML(fi, LOGL_INFO, "%s Ramping down complete, %u TRX remaining\n",
+ gsm_trx_name(src_trx), remaining);
+ if (remaining == 0) {
+ /* Make sure we end up any remaining ongoing power ramp
+ * down under target shutdown tx power level, then
+ * finally transit to next state:
+ */
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ power_ramp_abort(trx);
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED);
+ }
+ break;
+ }
+}
+
+static void st_wait_trx_closed_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct gsm_bts_trx *trx;
+ llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
+ bts_model_trx_deact_rf(trx);
+ }
+ llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
+ bts_model_trx_close(trx);
+ }
+ /* Now wait until all TRX are closed asynchronously, we'll get feedback through events... */
+}
+
+static void st_wait_trx_closed(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct gsm_bts_trx *src_trx;
+ unsigned int remaining;
+
+ switch(event) {
+ case BTS_SHUTDOWN_EV_TRX_CLOSED:
+ src_trx = (struct gsm_bts_trx *)data;
+ remaining = count_trx_operational(bts);
+
+ LOGPFSML(fi, LOGL_INFO, "%s TRX closed, %u TRX remaining\n",
+ gsm_trx_name(src_trx), remaining);
+ if (remaining == 0)
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_EXIT);
+ break;
+ }
+}
+
+static void st_exit_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+
+ osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_SHUTDOWN_FINISH, NULL);
+
+ if (bts->shutdown_fi_exit_proc) {
+ LOGPFSML(fi, LOGL_NOTICE, "Shutdown process completed successfully, exiting process\n");
+ exit(0);
+ }
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_NONE);
+}
+
+static struct osmo_fsm_state bts_shutdown_fsm_states[] = {
+ [BTS_SHUTDOWN_ST_NONE] = {
+ .in_event_mask =
+ X(BTS_SHUTDOWN_EV_START),
+ .out_state_mask =
+ X(BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL) |
+ X(BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED),
+ .name = "NONE",
+ .action = st_none,
+ },
+ [BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL] = {
+ .in_event_mask =
+ X(BTS_SHUTDOWN_EV_TRX_RAMP_COMPL),
+ .out_state_mask =
+ X(BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED),
+ .name = "WAIT_RAMP_DOWN_COMPL",
+ .onenter = st_wait_ramp_down_compl_on_enter,
+ .action = st_wait_ramp_down_compl,
+ },
+ [BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED] = {
+ .in_event_mask =
+ X(BTS_SHUTDOWN_EV_TRX_CLOSED),
+ .out_state_mask =
+ X(BTS_SHUTDOWN_ST_EXIT),
+ .name = "WAIT_TRX_CLOSED",
+ .onenter = st_wait_trx_closed_on_enter,
+ .action = st_wait_trx_closed,
+ },
+ [BTS_SHUTDOWN_ST_EXIT] = {
+ .name = "EXIT",
+ .out_state_mask =
+ X(BTS_SHUTDOWN_ST_NONE),
+ .onenter = st_exit_on_enter,
+ }
+};
+
+const struct value_string bts_shutdown_fsm_event_names[] = {
+ OSMO_VALUE_STRING(BTS_SHUTDOWN_EV_START),
+ OSMO_VALUE_STRING(BTS_SHUTDOWN_EV_TRX_RAMP_COMPL),
+ OSMO_VALUE_STRING(BTS_SHUTDOWN_EV_TRX_CLOSED),
+ { 0, NULL }
+};
+
+int bts_shutdown_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ switch (fi->state) {
+ case BTS_SHUTDOWN_ST_WAIT_RAMP_DOWN_COMPL:
+ LOGPFSML(fi, LOGL_ERROR, "Timer expired waiting for ramp down complete\n");
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED);
+ break;
+ case BTS_SHUTDOWN_ST_WAIT_TRX_CLOSED:
+ LOGPFSML(fi, LOGL_ERROR, "Timer expired waiting for TRX close\n");
+ bts_shutdown_fsm_state_chg(fi, BTS_SHUTDOWN_ST_EXIT);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+ return 0;
+}
+
+struct osmo_fsm bts_shutdown_fsm = {
+ .name = "BTS_SHUTDOWN",
+ .states = bts_shutdown_fsm_states,
+ .num_states = ARRAY_SIZE(bts_shutdown_fsm_states),
+ .event_names = bts_shutdown_fsm_event_names,
+ .log_subsys = DOML,
+ .timer_cb = bts_shutdown_fsm_timer_cb,
+};
+
+static __attribute__((constructor)) void bts_shutdown_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&bts_shutdown_fsm) == 0);
+}
+
+bool bts_shutdown_in_progress(const struct gsm_bts *bts)
+{
+ const struct osmo_fsm_inst *fi = bts->shutdown_fi;
+ return fi->state != BTS_SHUTDOWN_ST_NONE;
+}
+
+void bts_shutdown_ext(struct gsm_bts *bts, const char *reason, bool exit_proc, bool skip_power_ramp)
+{
+ struct osmo_fsm_inst *fi = bts->shutdown_fi;
+ if (bts_shutdown_in_progress(bts)) {
+ LOGPFSML(fi, LOGL_NOTICE, "BTS is already being shutdown.\n");
+ if (exit_proc)
+ bts->shutdown_fi_exit_proc = true;
+ return;
+ }
+ bts->shutdown_fi_exit_proc = exit_proc;
+ bts->shutdown_fi_skip_power_ramp = skip_power_ramp;
+ LOGPFSML(fi, LOGL_NOTICE, "Shutting down BTS, exit %u, reason: %s\n",
+ exit_proc, reason);
+ osmo_fsm_inst_dispatch(fi, BTS_SHUTDOWN_EV_START, NULL);
+}
+
+void bts_shutdown(struct gsm_bts *bts, const char *reason)
+{
+ bts_shutdown_ext(bts, reason, true, true);
+}
+
+void bts_model_trx_close_cb(struct gsm_bts_trx *trx, int rc)
+{
+ struct osmo_fsm_inst *fi = trx->bts->shutdown_fi;
+ LOGPFSML(fi, LOGL_DEBUG, "%s Received TRX close cb rc=%d\n", gsm_trx_name(trx), rc);
+ osmo_fsm_inst_dispatch(fi, BTS_SHUTDOWN_EV_TRX_CLOSED, trx);
+}
diff --git a/src/common/bts_sm.c b/src/common/bts_sm.c
new file mode 100644
index 00000000..6e889b71
--- /dev/null
+++ b/src/common/bts_sm.c
@@ -0,0 +1,95 @@
+/* BTS support code common to all supported BTS models */
+
+/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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 <osmocom/core/talloc.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/fsm.h>
+
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+struct gsm_bts_sm *g_bts_sm;
+
+static const uint8_t nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
+
+struct gsm_bts *gsm_gprs_nse_get_bts(const struct gsm_gprs_nse *nse)
+{
+ return gsm_bts_num(g_bts_sm, nse->mo.obj_inst.bts_nr);
+}
+
+static int gsm_bts_sm_talloc_destructor(struct gsm_bts_sm *bts_sm)
+{
+ struct gsm_bts *bts;
+
+ while ((bts = llist_first_entry_or_null(&bts_sm->bts_list, struct gsm_bts, list)))
+ talloc_free(bts);
+
+ if (bts_sm->mo.fi) {
+ osmo_fsm_inst_free(bts_sm->mo.fi);
+ bts_sm->mo.fi = NULL;
+ }
+
+ return 0;
+}
+
+struct gsm_bts_sm *gsm_bts_sm_alloc(void *talloc_ctx)
+{
+ struct gsm_bts_sm *bts_sm = talloc_zero(talloc_ctx, struct gsm_bts_sm);
+ struct gsm_gprs_nse *nse = &bts_sm->gprs.nse;
+ unsigned int i;
+
+ if (!bts_sm)
+ return NULL;
+
+ talloc_set_destructor(bts_sm, gsm_bts_sm_talloc_destructor);
+
+ INIT_LLIST_HEAD(&bts_sm->bts_list);
+
+ /* NM SITE_MGR */
+ bts_sm->mo.fi = osmo_fsm_inst_alloc(&nm_bts_sm_fsm, bts_sm, bts_sm,
+ LOGL_INFO, "bts_sm");
+ gsm_mo_init(&bts_sm->mo, NULL, NM_OC_SITE_MANAGER,
+ 0xff, 0xff, 0xff);
+ oml_mo_state_init(&bts_sm->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+
+ /* NM GPRS NSE */
+ nse->mo.fi = osmo_fsm_inst_alloc(&nm_gprs_nse_fsm, bts_sm, nse,
+ LOGL_INFO, "gprs_nse0");
+ gsm_mo_init(&nse->mo, NULL, NM_OC_GPRS_NSE, 0, 0xff, 0xff);
+ oml_mo_state_init(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+ memcpy(&nse->timer, nse_timer_default, sizeof(nse->timer));
+
+ /* NM GPRS NSVCs */
+ for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
+ struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
+ nsvc->nse = nse;
+ nsvc->id = i;
+ nsvc->mo.fi = osmo_fsm_inst_alloc(&nm_gprs_nsvc_fsm, bts_sm, nsvc,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(nsvc->mo.fi, "gprs_nsvc%d-%d",
+ nse->mo.obj_inst.bts_nr, i);
+ gsm_mo_init(&nsvc->mo, NULL, NM_OC_GPRS_NSVC, nse->mo.obj_inst.bts_nr, i, 0xff);
+ oml_mo_state_init(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+ }
+
+ return bts_sm;
+}
diff --git a/src/common/bts_trx.c b/src/common/bts_trx.c
new file mode 100644
index 00000000..251b6735
--- /dev/null
+++ b/src/common/bts_trx.c
@@ -0,0 +1,256 @@
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * 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 Affero 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 <osmocom/core/fsm.h>
+
+#include <osmocom/gsm/abis_nm.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_trx.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/phy_link.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+static int gsm_bts_trx_talloc_destructor(struct gsm_bts_trx *trx)
+{
+ unsigned int i;
+
+ if (trx->bb_transc.mo.fi) {
+ osmo_fsm_inst_free(trx->bb_transc.mo.fi);
+ trx->bb_transc.mo.fi = NULL;
+ }
+ if (trx->mo.fi) {
+ osmo_fsm_inst_free(trx->mo.fi);
+ trx->mo.fi = NULL;
+ }
+ for (i = 0; i < TRX_NR_TS; i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ if (ts->mo.fi) {
+ osmo_fsm_inst_free(ts->mo.fi);
+ ts->mo.fi = NULL;
+ }
+ }
+ return 0;
+}
+
+/* Initialize all logical channels of the given timeslot */
+static void gsm_bts_trx_ts_init_lchan(struct gsm_bts_trx_ts *ts)
+{
+ unsigned int ln;
+
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+ gsm_lchan_init(lchan, ts, ln);
+ }
+}
+
+/* Initialize primary timeslots of the given transceiver */
+static void gsm_bts_trx_init_ts(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ ts->trx = trx;
+ ts->nr = tn;
+
+ ts->tsc_oml_configured = false;
+ ts->tsc_rsl_configured = false;
+ ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
+
+ ts->mo.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(ts->mo.fi, "%s-ts%u",
+ trx->bb_transc.mo.fi->id, ts->nr);
+ gsm_mo_init(&ts->mo, trx->bts, NM_OC_CHANNEL,
+ trx->bts->nr, trx->nr, ts->nr);
+ oml_mo_state_init(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+
+ gsm_bts_trx_ts_init_lchan(ts);
+ }
+}
+
+/* Initialize shadow timeslots of the given transceiver */
+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts;
+
+ ts = talloc_zero(trx, struct gsm_bts_trx_ts);
+ OSMO_ASSERT(ts != NULL);
+
+ ts->trx = trx;
+ ts->nr = tn;
+
+ ts->tsc_oml_configured = false;
+ ts->tsc_rsl_configured = false;
+ ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
+
+ /* Link both primary and shadow */
+ trx->ts[tn].vamos.peer = ts;
+ ts->vamos.peer = &trx->ts[tn];
+ ts->vamos.is_shadow = true;
+
+ /* Shadow timeslot uses the primary's NM FSM */
+ OSMO_ASSERT(trx->ts[tn].mo.fi != NULL);
+ ts->mo.fi = trx->ts[tn].mo.fi;
+
+ gsm_bts_trx_ts_init_lchan(ts);
+ }
+}
+
+void gsm_bts_trx_free_shadow_ts(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+ unsigned int ln;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *shadow_ts = trx->ts[tn].vamos.peer;
+ if (!shadow_ts)
+ continue;
+
+ /* free lchan related mem allocated on the trx object: */
+ for (ln = 0; ln < ARRAY_SIZE(shadow_ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &shadow_ts->lchan[ln];
+ TALLOC_FREE(lchan->name);
+ }
+
+ talloc_free(shadow_ts);
+ trx->ts[tn].vamos.peer = NULL;
+ }
+}
+
+struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
+
+ if (!trx)
+ return NULL;
+
+ talloc_set_destructor(trx, gsm_bts_trx_talloc_destructor);
+
+ trx->bts = bts;
+ trx->nr = bts->num_trx++;
+
+ trx->mo.fi = osmo_fsm_inst_alloc(&nm_rcarrier_fsm, trx, trx,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(trx->mo.fi, "bts%d-trx%d", bts->nr, trx->nr);
+ gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER, bts->nr, trx->nr, 0xff);
+ oml_mo_state_init(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+
+ trx->bb_transc.mo.fi = osmo_fsm_inst_alloc(&nm_bb_transc_fsm, trx, &trx->bb_transc,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(trx->bb_transc.mo.fi, "bts%d-trx%d", bts->nr, trx->nr);
+ gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC, bts->nr, trx->nr, 0xff);
+ oml_mo_state_init(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
+
+ gsm_bts_trx_init_ts(trx);
+
+ if (trx->nr != 0)
+ trx->nominal_power = bts->c0->nominal_power;
+
+ /* Default values for the power adjustments */
+ trx->power_params.ramp.max_initial_pout_mdBm = to_mdB(0);
+ trx->power_params.ramp.step_size_mdB = to_mdB(2);
+ trx->power_params.ramp.step_interval_sec = 1;
+
+ /* Default (fall-back) Dynamic Power Control parameters */
+ trx->bs_dpc_params = &bts->bs_dpc_params;
+ trx->ms_dpc_params = &bts->ms_dpc_params;
+
+ /* IF BTS model doesn't DSP/HW support MS Power Control Loop, enable osmo algo by default: */
+ if (!bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP))
+ trx->ms_pwr_ctl_soft = true;
+
+ llist_add_tail(&trx->list, &bts->trx_list);
+
+ return trx;
+}
+
+struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num)
+{
+ struct gsm_bts_trx *trx;
+
+ if (num >= bts->num_trx)
+ return NULL;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->nr == num)
+ return trx;
+ }
+
+ return NULL;
+}
+
+static char ts2str[255];
+
+char *gsm_trx_name(const struct gsm_bts_trx *trx)
+{
+ if (!trx)
+ snprintf(ts2str, sizeof(ts2str), "(trx=NULL)");
+ else
+ snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
+ trx->bts->nr, trx->nr);
+
+ return ts2str;
+}
+
+const char *gsm_trx_unit_id(struct gsm_bts_trx *trx)
+{
+ static char buf[23];
+
+ snprintf(buf, sizeof(buf), "%u/%u/%u", trx->bts->ip_access.site_id,
+ trx->bts->ip_access.bts_id, trx->nr);
+ return buf;
+}
+
+/* RSL link is established, send status report */
+int trx_link_estab(struct gsm_bts_trx *trx)
+{
+ int rc;
+
+ LOGPTRX(trx, DRSL, LOGL_INFO, "RSL link up\n");
+
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_RSL_UP, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_RSL_UP, NULL);
+
+ if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED ||
+ trx->bb_transc.mo.nm_state.operational == NM_OPSTATE_ENABLED) {
+ rc = rsl_tx_rf_res(trx);
+ if (rc < 0)
+ oml_tx_failure_event_rep(&trx->bb_transc.mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_RSL_FAIL,
+ "Failed to establish RSL link (%d)", rc);
+ }
+ if (trx == trx->bts->c0)
+ load_timer_start(trx->bts);
+
+ return 0;
+}
+
+
+bool trx_ms_pwr_ctrl_is_osmo(const struct gsm_bts_trx *trx)
+{
+ return trx->ms_pwr_ctl_soft;
+}
diff --git a/src/common/cbch.c b/src/common/cbch.c
index 7ed11c2f..363eb672 100644
--- a/src/common/cbch.c
+++ b/src/common/cbch.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -38,7 +38,7 @@ struct smscb_msg {
uint8_t num_segs; /* total number of segments */
};
-/* determine if current queue length differes more than permitted hysteresis from target
+/* determine if current queue length differs more than permitted hysteresis from target
* queue length. If it does, send CBCH LOAD IND */
static void check_and_send_cbch_load(struct gsm_bts *bts, struct bts_smscb_state *bts_ss)
{
@@ -139,12 +139,8 @@ static int get_smscb_block(struct bts_smscb_state *bts_ss, uint8_t *out, uint8_t
block_type->seq_nr = block_nr;
/* determine if this is the last block */
- if (block_nr + 1 == msg->num_segs)
- block_type->lb = 1;
- else
- block_type->lb = 0;
-
- if (block_nr == 4) {
+ block_type->lb = (block_nr + 1 == msg->num_segs);
+ if (block_type->lb) {
if (msg != bts_ss->default_msg) {
DEBUGPGT(DLSMS, g_time, "%s: deleting fully-transmitted message %p\n",
chan_name, msg);
@@ -198,7 +194,7 @@ int bts_process_smscb_cmd(struct gsm_bts *bts, struct rsl_ie_cb_cmd_type cmd_typ
return -EINVAL;
}
- scm = talloc_zero_size(bts, sizeof(*scm));
+ scm = talloc_zero(bts, struct smscb_msg);
if (!scm)
return -1;
@@ -233,10 +229,10 @@ int bts_process_smscb_cmd(struct gsm_bts *bts, struct rsl_ie_cb_cmd_type cmd_typ
rate_ctr_inc2(bts_ss->ctrs, CBCH_CTR_RCVD_QUEUED);
break;
case RSL_CB_CMD_TYPE_DEFAULT:
- /* old default msg will be free'd in get_smscb_block() if it is currently in transit
- * and we set a new default_msg here */
+ /* clear the cur_msg pointer if it is the old default message */
if (bts_ss->cur_msg && bts_ss->cur_msg == bts_ss->default_msg)
- talloc_free(bts_ss->cur_msg);
+ bts_ss->cur_msg = NULL;
+ talloc_free(bts_ss->default_msg);
if (cmd_type.def_bcast == RSL_CB_CMD_DEFBCAST_NORMAL)
/* def_bcast == 0: normal message */
bts_ss->default_msg = scm;
@@ -322,3 +318,25 @@ int bts_cbch_get(struct gsm_bts *bts, uint8_t *outbuf, struct gsm_time *g_time)
return rc;
}
+
+static void bts_smscb_state_reset(struct bts_smscb_state *bts_ss)
+{
+ struct smscb_msg *scm, *tmp;
+ llist_for_each_entry_safe(scm, tmp, &bts_ss->queue, list) {
+ llist_del(&scm->list);
+ talloc_free(scm);
+ }
+ bts_ss->queue_len = 0;
+ rate_ctr_group_reset(bts_ss->ctrs);
+ /* avoid double-free of default_msg in case cur_msg == default_msg */
+ if (bts_ss->cur_msg && bts_ss->cur_msg != bts_ss->default_msg)
+ talloc_free(bts_ss->cur_msg);
+ bts_ss->cur_msg = NULL;
+ TALLOC_FREE(bts_ss->default_msg);
+}
+
+void bts_cbch_reset(struct gsm_bts *bts)
+{
+ bts_smscb_state_reset(&bts->smscb_basic);
+ bts_smscb_state_reset(&bts->smscb_extended);
+}
diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c
new file mode 100644
index 00000000..d6c00b03
--- /dev/null
+++ b/src/common/csd_v110.c
@@ -0,0 +1,188 @@
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm44021.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/isdn/v110.h>
+
+#include <osmo-bts/csd_v110.h>
+#include <osmo-bts/lchan.h>
+
+/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */
+const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = {
+#if 0
+ [GSM48_CMODE_DATA_14k5] = {
+ /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */
+ .fr = { .num_blocks = 1, .num_bits = 290 },
+ },
+#endif
+ [GSM48_CMODE_DATA_12k0] = {
+ /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */
+ .fr = { .num_blocks = 4, .num_bits = 60 },
+ },
+ [GSM48_CMODE_DATA_6k0] = {
+ /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */
+ .fr = { .num_blocks = 2, .num_bits = 60 },
+ /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */
+ .hr = { .num_blocks = 4, .num_bits = 60 },
+ },
+ [GSM48_CMODE_DATA_3k6] = {
+ /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */
+ .fr = { .num_blocks = 2, .num_bits = 36 },
+ /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */
+ .hr = { .num_blocks = 4, .num_bits = 36 },
+ },
+};
+
+/* 3GPP TS 44.021, Figure 4: Coding of data rates (E1/E2/E3 bits) */
+static const uint8_t e1e2e3_map[_LCHAN_CSD_M_NUM][3] = {
+ [LCHAN_CSD_M_T_600] = { 1, 0, 0 },
+ [LCHAN_CSD_M_T_1200] = { 0, 1, 0 },
+ [LCHAN_CSD_M_T_2400] = { 1, 1, 0 },
+ [LCHAN_CSD_M_T_4800] = { 0, 1, 1 },
+ [LCHAN_CSD_M_T_9600] = { 0, 1, 1 },
+#if 0
+ [LCHAN_CSD_M_T_19200] = { 0, 1, 1 },
+ [LCHAN_CSD_M_T_38400] = { 0, 1, 1 },
+ [LCHAN_CSD_M_T_14400] = { 1, 0, 1 },
+ [LCHAN_CSD_M_T_28800] = { 1, 0, 1 },
+#endif
+};
+
+int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp,
+ const uint8_t *data, size_t data_len)
+{
+ const struct csd_v110_frame_desc *desc;
+ ubit_t ra_bits[80 * 4];
+
+ OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc));
+ if (lchan->type == GSM_LCHAN_TCH_F)
+ desc = &csd_v110_lchan_desc[lchan->tch_mode].fr;
+ else
+ desc = &csd_v110_lchan_desc[lchan->tch_mode].hr;
+ if (OSMO_UNLIKELY(desc->num_blocks == 0))
+ return -ENOTSUP;
+
+ /* handle empty/incomplete Uplink frames gracefully */
+ if (OSMO_UNLIKELY(data_len < (desc->num_blocks * desc->num_bits))) {
+ /* encode N idle frames as per 3GPP TS 44.021, section 8.1.6 */
+ memset(&ra_bits[0], 0x01, sizeof(ra_bits));
+ for (unsigned int i = 0; i < desc->num_blocks; i++)
+ memset(&ra_bits[i * 80], 0x00, 8); /* alignment pattern */
+ goto ra1_ra2;
+ }
+
+ /* RA1'/RA1: convert from radio rate to an intermediate data rate */
+ for (unsigned int i = 0; i < desc->num_blocks; i++) {
+ struct osmo_v110_decoded_frame df;
+
+ /* convert a V.110 36-/60-bit frame to a V.110 80-bit frame */
+ if (desc->num_bits == 60)
+ osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60);
+ else /* desc->num_bits == 36 */
+ osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36);
+
+ /* E1 .. E3 must set by out-of-band knowledge */
+ if (lchan->csd_mode == LCHAN_CSD_M_NT) {
+ /* non-transparent: as per 3GPP TS 48.020, Table 7 */
+ df.e_bits[0] = 0; /* E1: as per 15.1.2, shall be set to 0 (for BSS-MSC) */
+ df.e_bits[1] = (i >> 1) & 0x01; /* E2: 0 for Q1/Q2, 1 for Q3/Q4 */
+ df.e_bits[2] = (i >> 0) & 0x01; /* E3: 0 for Q1/Q3, 1 for Q2/Q4 */
+ } else {
+ /* transparent: as per 3GPP TS 44.021, Figure 4 */
+ df.e_bits[0] = e1e2e3_map[lchan->csd_mode][0]; /* E1 */
+ df.e_bits[1] = e1e2e3_map[lchan->csd_mode][1]; /* E2 */
+ df.e_bits[2] = e1e2e3_map[lchan->csd_mode][2]; /* E3 */
+ }
+
+ osmo_v110_encode_frame(&ra_bits[i * 80], 80, &df);
+ }
+
+ra1_ra2:
+ /* RA1/RA2: convert from an intermediate rate to 64 kbit/s */
+ if (desc->num_blocks == 4) {
+ /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */
+ for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) {
+ rtp[i] = (0xff >> 2);
+ rtp[i] |= (ra_bits[j++] << 7);
+ rtp[i] |= (ra_bits[j++] << 6);
+ }
+ } else {
+ /* 2 * 80 bits (8 kbit/s) => 1 bit per octet */
+ for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++) {
+ rtp[i] = (0xff >> 1);
+ rtp[i] |= (ra_bits[i] << 7);
+ }
+ }
+
+ return RFC4040_RTP_PLEN;
+}
+
+int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data,
+ const uint8_t *rtp, size_t rtp_len)
+{
+ const struct csd_v110_frame_desc *desc;
+ ubit_t ra_bits[80 * 4];
+
+ OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc));
+ if (lchan->type == GSM_LCHAN_TCH_F)
+ desc = &csd_v110_lchan_desc[lchan->tch_mode].fr;
+ else
+ desc = &csd_v110_lchan_desc[lchan->tch_mode].hr;
+ if (OSMO_UNLIKELY(desc->num_blocks == 0))
+ return -ENOTSUP;
+
+ if (OSMO_UNLIKELY(rtp_len != RFC4040_RTP_PLEN))
+ return -EINVAL;
+
+ /* RA1/RA2: convert from 64 kbit/s to an intermediate rate */
+ if (desc->num_blocks == 4) {
+ /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */
+ for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) {
+ ra_bits[j++] = (rtp[i] >> 7);
+ ra_bits[j++] = (rtp[i] >> 6) & 0x01;
+ }
+ } else {
+ /* 2 * 80 bits (8 kbit/s) => 1 bit per octet */
+ for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++)
+ ra_bits[i] = (rtp[i] >> 7);
+ }
+
+ /* RA1'/RA1: convert from an intermediate rate to radio rate */
+ for (unsigned int i = 0; i < desc->num_blocks; i++) {
+ struct osmo_v110_decoded_frame df;
+
+ /* convert a V.110 80-bit frame to a V.110 36-/60-bit frame */
+ osmo_v110_decode_frame(&df, &ra_bits[i * 80], 80);
+ if (desc->num_bits == 60)
+ osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df);
+ else /* desc->num_bits == 36 */
+ osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df);
+ }
+
+ return desc->num_blocks * desc->num_bits;
+}
diff --git a/src/common/dtx_dl_amr_fsm.c b/src/common/dtx_dl_amr_fsm.c
index 38e22c95..bbe1b0ad 100644
--- a/src/common/dtx_dl_amr_fsm.c
+++ b/src/common/dtx_dl_amr_fsm.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/common/gsm_data.c b/src/common/gsm_data.c
new file mode 100644
index 00000000..dad5587b
--- /dev/null
+++ b/src/common/gsm_data.c
@@ -0,0 +1,348 @@
+/* (C) 2008-2010 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 Affero 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <netinet/in.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/statistics.h>
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/abis_nm.h>
+#include <osmocom/codec/ecu.h>
+
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_trx.h>
+#include <osmo-bts/logging.h>
+
+struct osmo_tdef_group bts_tdef_groups[] = {
+ { .name = "bts", .tdefs = bts_T_defs, .desc = "BTS process timers" },
+ { .name = "abis", .tdefs = abis_T_defs, .desc = "Abis (RSL) related timers" },
+ {}
+};
+
+const struct value_string gsm_pchant_names[13] = {
+ { GSM_PCHAN_NONE, "NONE" },
+ { GSM_PCHAN_CCCH, "CCCH" },
+ { GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" },
+ { GSM_PCHAN_TCH_F, "TCH/F" },
+ { GSM_PCHAN_TCH_H, "TCH/H" },
+ { GSM_PCHAN_SDCCH8_SACCH8C, "SDCCH8" },
+ { GSM_PCHAN_PDCH, "PDCH" },
+ { GSM_PCHAN_TCH_F_PDCH, "TCH/F_PDCH" },
+ { GSM_PCHAN_UNKNOWN, "UNKNOWN" },
+ { GSM_PCHAN_CCCH_SDCCH4_CBCH, "CCCH+SDCCH4+CBCH" },
+ { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "SDCCH8+CBCH" },
+ { GSM_PCHAN_OSMO_DYN, "TCH/F_TCH/H_SDCCH8_PDCH" },
+ { 0, NULL }
+};
+
+const struct value_string gsm_pchant_descs[13] = {
+ { GSM_PCHAN_NONE, "Physical Channel not configured" },
+ { GSM_PCHAN_CCCH, "FCCH + SCH + BCCH + CCCH (Comb. IV)" },
+ { GSM_PCHAN_CCCH_SDCCH4,
+ "FCCH + SCH + BCCH + CCCH + 4 SDCCH + 2 SACCH (Comb. V)" },
+ { GSM_PCHAN_TCH_F, "TCH/F + FACCH/F + SACCH (Comb. I)" },
+ { GSM_PCHAN_TCH_H, "2 TCH/H + 2 FACCH/H + 2 SACCH (Comb. II)" },
+ { GSM_PCHAN_SDCCH8_SACCH8C, "8 SDCCH + 4 SACCH (Comb. VII)" },
+ { GSM_PCHAN_PDCH, "Packet Data Channel for GPRS/EDGE" },
+ { GSM_PCHAN_TCH_F_PDCH, "Dynamic TCH/F or GPRS PDCH" },
+ { GSM_PCHAN_UNKNOWN, "Unknown / Unsupported channel combination" },
+ { GSM_PCHAN_CCCH_SDCCH4_CBCH, "FCCH + SCH + BCCH + CCCH + CBCH + 3 SDCCH + 2 SACCH (Comb. V)" },
+ { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "7 SDCCH + 4 SACCH + CBCH (Comb. VII)" },
+ { GSM_PCHAN_OSMO_DYN, "Dynamic TCH/F or TCH/H or SDCCH/8 or GPRS PDCH" },
+ { 0, NULL }
+};
+
+const char *gsm_pchan_name(enum gsm_phys_chan_config c)
+{
+ return get_value_string(gsm_pchant_names, c);
+}
+
+/* TODO: move to libosmocore, next to gsm_chan_t_names? */
+const char *gsm_lchant_name(enum gsm_chan_t c)
+{
+ return get_value_string(gsm_chan_t_names, c);
+}
+
+static char ts2str[255];
+
+char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
+{
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ")",
+ GSM_TS_NAME_ARGS(ts));
+
+ return ts2str;
+}
+
+/*! Log timeslot number with full pchan information */
+char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
+{
+ switch (ts->pchan) {
+ case GSM_PCHAN_OSMO_DYN:
+ if (ts->dyn.pchan_is == ts->dyn.pchan_want)
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",
+ GSM_TS_NAME_ARGS(ts),
+ gsm_pchan_name(ts->pchan),
+ gsm_pchan_name(ts->dyn.pchan_is));
+ else
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",
+ GSM_TS_NAME_ARGS(ts),
+ gsm_pchan_name(ts->pchan),
+ gsm_pchan_name(ts->dyn.pchan_is),
+ gsm_pchan_name(ts->dyn.pchan_want));
+ break;
+ case GSM_PCHAN_TCH_F_PDCH:
+ if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",
+ GSM_TS_NAME_ARGS(ts),
+ gsm_pchan_name(ts->pchan),
+ (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
+ : "TCH/F");
+ else
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",
+ GSM_TS_NAME_ARGS(ts),
+ gsm_pchan_name(ts->pchan),
+ (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
+ : "TCH/F",
+ (ts->flags & TS_F_PDCH_ACT_PENDING)? "PDCH"
+ : "TCH/F");
+ break;
+ default:
+ snprintf(ts2str, sizeof(ts2str), "(" GSM_TS_NAME_FMT ",pchan=%s)",
+ GSM_TS_NAME_ARGS(ts), gsm_pchan_name(ts->pchan));
+ break;
+ }
+
+ return ts2str;
+}
+
+/* determine logical channel based on TRX and channel number IE */
+struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
+ int *rc)
+{
+ uint8_t ts_nr = chan_nr & 0x07;
+ uint8_t cbits = chan_nr >> 3;
+ uint8_t lch_idx;
+ struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
+ bool ok = true;
+
+ if (rc)
+ *rc = -EINVAL;
+
+ switch (cbits) {
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Bm_ACCHs:
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ /* fall-through */
+ case ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs:
+ lch_idx = 0; /* TCH/F */
+ if (ts->pchan != GSM_PCHAN_TCH_F &&
+ ts->pchan != GSM_PCHAN_PDCH &&
+ ts->pchan != GSM_PCHAN_TCH_F_PDCH &&
+ ts->pchan != GSM_PCHAN_OSMO_DYN)
+ ok = false;
+ break;
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(0):
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(1):
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ /* fall-through */
+ case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(0):
+ case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(1):
+ lch_idx = cbits & 0x1; /* TCH/H */
+ if (ts->pchan != GSM_PCHAN_TCH_H &&
+ ts->pchan != GSM_PCHAN_OSMO_DYN)
+ ok = false;
+ break;
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(0):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(1):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(2):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(3):
+ lch_idx = cbits & 0x3; /* SDCCH/4 */
+ if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
+ ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
+ ok = false;
+ break;
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(0):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(1):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(2):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(3):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(4):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(5):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(6):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(7):
+ lch_idx = cbits & 0x7; /* SDCCH/8 */
+ if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C &&
+ ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C_CBCH &&
+ ts->pchan != GSM_PCHAN_OSMO_DYN)
+ ok = false;
+ break;
+ case ABIS_RSL_CHAN_NR_CBITS_BCCH:
+ case ABIS_RSL_CHAN_NR_CBITS_RACH:
+ case ABIS_RSL_CHAN_NR_CBITS_PCH_AGCH:
+ lch_idx = 0;
+ if (ts->pchan != GSM_PCHAN_CCCH &&
+ ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
+ ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
+ ok = false;
+ /* FIXME: we should not return first sdcch4 !!! */
+ break;
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH:
+ lch_idx = 0;
+ if (ts->pchan != GSM_PCHAN_OSMO_DYN)
+ ok = false;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (rc && ok)
+ *rc = 0;
+
+ return &ts->lchan[lch_idx];
+}
+
+static const uint8_t subslots_per_pchan[] = {
+ [GSM_PCHAN_NONE] = 0,
+ [GSM_PCHAN_CCCH] = 0,
+ [GSM_PCHAN_PDCH] = 0,
+ [GSM_PCHAN_CCCH_SDCCH4] = 4,
+ [GSM_PCHAN_TCH_F] = 1,
+ [GSM_PCHAN_TCH_H] = 2,
+ [GSM_PCHAN_SDCCH8_SACCH8C] = 8,
+ [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4,
+ [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8,
+ /*
+ * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_OSMO_DYN should not be
+ * part of this, those TS are handled according to their dynamic state.
+ */
+};
+
+/*! Return the actual pchan type, also heeding dynamic TS. */
+enum gsm_phys_chan_config ts_pchan(const struct gsm_bts_trx_ts *ts)
+{
+ switch (ts->pchan) {
+ case GSM_PCHAN_OSMO_DYN:
+ return ts->dyn.pchan_is;
+ case GSM_PCHAN_TCH_F_PDCH:
+ if (ts->flags & TS_F_PDCH_ACTIVE)
+ return GSM_PCHAN_PDCH;
+ else
+ return GSM_PCHAN_TCH_F;
+ default:
+ return ts->pchan;
+ }
+}
+
+/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of
+ * logical channels available in the timeslot. */
+uint8_t ts_subslots(const struct gsm_bts_trx_ts *ts)
+{
+ return subslots_per_pchan[ts_pchan(ts)];
+}
+
+static bool pchan_is_tch(enum gsm_phys_chan_config pchan)
+{
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ case GSM_PCHAN_TCH_H:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ts_is_tch(const struct gsm_bts_trx_ts *ts)
+{
+ return pchan_is_tch(ts_pchan(ts));
+}
+
+bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
+{
+ switch (ts->pchan) {
+ case GSM_PCHAN_PDCH:
+ return true;
+ case GSM_PCHAN_TCH_F_PDCH:
+ return (ts->flags & TS_F_PDCH_ACTIVE)
+ && !(ts->flags & TS_F_PDCH_PENDING_MASK);
+ case GSM_PCHAN_OSMO_DYN:
+ return ts->dyn.pchan_is == GSM_PCHAN_PDCH
+ && ts->dyn.pchan_want == ts->dyn.pchan_is;
+ default:
+ return false;
+ }
+}
+
+/* Apply ts->tsc based on what was configured coming from different sources.
+ * Priorities (preferred first, overrides ones afterward):
+ * 1- RSL OSMO_TSC IE
+ * 2- OML SetChannelAttr TSC IE
+ * 3- OML SetBtsAttr BSIC IE
+ */
+void gsm_ts_apply_configured_tsc(struct gsm_bts_trx_ts *ts)
+{
+ if (ts->tsc_rsl_configured) {
+ ts->tsc = ts->tsc_rsl;
+ return;
+ }
+ if (ts->tsc_oml_configured) {
+ ts->tsc = ts->tsc_oml;
+ return;
+ }
+ if (ts->trx->bts->bsic_configured) {
+ ts->tsc = BTS_TSC(ts->trx->bts);
+ return;
+ }
+ ts->tsc = 0xff; /* invalid value */
+}
+
+void gsm_ts_release(struct gsm_bts_trx_ts *ts)
+{
+ unsigned int ln;
+
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+ gsm_lchan_release(lchan, LCHAN_REL_ACT_OML);
+ }
+ ts->pchan = GSM_PCHAN_NONE;
+ /* Make sure pchan_is is reset, since PCU act_req to release it will be
+ * ignored as the lchan will already be released. */
+ ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
+
+ ts->tsc_oml_configured = false;
+ ts->tsc_rsl_configured = false;
+ ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
+}
diff --git a/src/common/gsm_data_shared.c b/src/common/gsm_data_shared.c
deleted file mode 100644
index f0f5ae20..00000000
--- a/src/common/gsm_data_shared.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/* (C) 2008-2010 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 Affero 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <netinet/in.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <osmocom/gsm/abis_nm.h>
-#include <osmocom/core/statistics.h>
-#include <osmocom/codec/ecu.h>
-
-#include <osmo-bts/gsm_data.h>
-
-void gsm_abis_mo_reset(struct gsm_abis_mo *mo)
-{
- mo->nm_state.operational = NM_OPSTATE_NULL;
- mo->nm_state.availability = NM_AVSTATE_POWER_OFF;
- mo->nm_state.administrative = NM_STATE_LOCKED;
-}
-
-static void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
- uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3)
-{
- mo->bts = bts;
- mo->obj_class = obj_class;
- mo->obj_inst.bts_nr = p1;
- mo->obj_inst.trx_nr = p2;
- mo->obj_inst.ts_nr = p3;
- gsm_abis_mo_reset(mo);
-}
-
-const struct value_string bts_attribute_names[] = {
- OSMO_VALUE_STRING(BTS_TYPE_VARIANT),
- OSMO_VALUE_STRING(BTS_SUB_MODEL),
- OSMO_VALUE_STRING(TRX_PHY_VERSION),
- { 0, NULL }
-};
-
-enum bts_attribute str2btsattr(const char *s)
-{
- return get_string_value(bts_attribute_names, s);
-}
-
-const char *btsatttr2str(enum bts_attribute v)
-{
- return get_value_string(bts_attribute_names, v);
-}
-
-const struct value_string osmo_bts_variant_names[_NUM_BTS_VARIANT + 1] = {
- { BTS_UNKNOWN, "unknown" },
- { BTS_OSMO_LITECELL15, "osmo-bts-lc15" },
- { BTS_OSMO_OC2G, "osmo-bts-oc2g" },
- { BTS_OSMO_OCTPHY, "osmo-bts-octphy" },
- { BTS_OSMO_SYSMO, "osmo-bts-sysmo" },
- { BTS_OSMO_TRX, "omso-bts-trx" },
- { BTS_OSMO_VIRTUAL, "omso-bts-virtual" },
- { BTS_OSMO_OMLDUMMY, "omso-bts-omldummy" },
- { 0, NULL }
-};
-
-enum gsm_bts_type_variant str2btsvariant(const char *arg)
-{
- return get_string_value(osmo_bts_variant_names, arg);
-}
-
-const char *btsvariant2str(enum gsm_bts_type_variant v)
-{
- return get_value_string(osmo_bts_variant_names, v);
-}
-
-const struct value_string gsm_bts_features_descs[] = {
- { BTS_FEAT_HSCSD, "HSCSD" },
- { BTS_FEAT_GPRS, "GPRS" },
- { BTS_FEAT_EGPRS, "EGPRS" },
- { BTS_FEAT_ECSD, "ECSD" },
- { BTS_FEAT_HOPPING, "Frequency Hopping" },
- { BTS_FEAT_MULTI_TSC, "Multi-TSC" },
- { BTS_FEAT_OML_ALERTS, "OML Alerts" },
- { BTS_FEAT_AGCH_PCH_PROP, "AGCH/PCH proportional allocation" },
- { BTS_FEAT_CBCH, "CBCH" },
- { BTS_FEAT_SPEECH_F_V1, "Fullrate speech V1" },
- { BTS_FEAT_SPEECH_H_V1, "Halfrate speech V1" },
- { BTS_FEAT_SPEECH_F_EFR, "Fullrate speech EFR" },
- { BTS_FEAT_SPEECH_F_AMR, "Fullrate speech AMR" },
- { BTS_FEAT_SPEECH_H_AMR, "Halfrate speech AMR" },
- { BTS_FEAT_ETWS_PN, "ETWS Primary Notification on PCH" },
- { 0, NULL }
-};
-
-const struct value_string gsm_chreq_descs[] = {
- { GSM_CHREQ_REASON_EMERG, "emergency call" },
- { GSM_CHREQ_REASON_PAG, "answer to paging" },
- { GSM_CHREQ_REASON_CALL, "call re-establishment" },
- { GSM_CHREQ_REASON_LOCATION_UPD,"Location updating" },
- { GSM_CHREQ_REASON_PDCH, "one phase packet access" },
- { GSM_CHREQ_REASON_OTHER, "other" },
- { 0, NULL }
-};
-
-const struct value_string gsm_pchant_names[13] = {
- { GSM_PCHAN_NONE, "NONE" },
- { GSM_PCHAN_CCCH, "CCCH" },
- { GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" },
- { GSM_PCHAN_TCH_F, "TCH/F" },
- { GSM_PCHAN_TCH_H, "TCH/H" },
- { GSM_PCHAN_SDCCH8_SACCH8C, "SDCCH8" },
- { GSM_PCHAN_PDCH, "PDCH" },
- { GSM_PCHAN_TCH_F_PDCH, "TCH/F_PDCH" },
- { GSM_PCHAN_UNKNOWN, "UNKNOWN" },
- { GSM_PCHAN_CCCH_SDCCH4_CBCH, "CCCH+SDCCH4+CBCH" },
- { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "SDCCH8+CBCH" },
- { GSM_PCHAN_TCH_F_TCH_H_PDCH, "TCH/F_TCH/H_PDCH" },
- { 0, NULL }
-};
-
-const struct value_string gsm_pchant_descs[13] = {
- { GSM_PCHAN_NONE, "Physical Channel not configured" },
- { GSM_PCHAN_CCCH, "FCCH + SCH + BCCH + CCCH (Comb. IV)" },
- { GSM_PCHAN_CCCH_SDCCH4,
- "FCCH + SCH + BCCH + CCCH + 4 SDCCH + 2 SACCH (Comb. V)" },
- { GSM_PCHAN_TCH_F, "TCH/F + FACCH/F + SACCH (Comb. I)" },
- { GSM_PCHAN_TCH_H, "2 TCH/H + 2 FACCH/H + 2 SACCH (Comb. II)" },
- { GSM_PCHAN_SDCCH8_SACCH8C, "8 SDCCH + 4 SACCH (Comb. VII)" },
- { GSM_PCHAN_PDCH, "Packet Data Channel for GPRS/EDGE" },
- { GSM_PCHAN_TCH_F_PDCH, "Dynamic TCH/F or GPRS PDCH" },
- { GSM_PCHAN_UNKNOWN, "Unknown / Unsupported channel combination" },
- { GSM_PCHAN_CCCH_SDCCH4_CBCH, "FCCH + SCH + BCCH + CCCH + CBCH + 3 SDCCH + 2 SACCH (Comb. V)" },
- { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "7 SDCCH + 4 SACCH + CBCH (Comb. VII)" },
- { GSM_PCHAN_TCH_F_TCH_H_PDCH, "Dynamic TCH/F or TCH/H or GPRS PDCH" },
- { 0, NULL }
-};
-
-const char *gsm_pchan_name(enum gsm_phys_chan_config c)
-{
- return get_value_string(gsm_pchant_names, c);
-}
-
-enum gsm_phys_chan_config gsm_pchan_parse(const char *name)
-{
- return get_string_value(gsm_pchant_names, name);
-}
-
-/* TODO: move to libosmocore, next to gsm_chan_t_names? */
-const char *gsm_lchant_name(enum gsm_chan_t c)
-{
- return get_value_string(gsm_chan_t_names, c);
-}
-
-static const struct value_string lchan_s_names[] = {
- { LCHAN_S_NONE, "NONE" },
- { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
- { LCHAN_S_ACTIVE, "ACTIVE" },
- { LCHAN_S_INACTIVE, "INACTIVE" },
- { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
- { LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
- { LCHAN_S_BROKEN, "BROKEN UNUSABLE" },
- { 0, NULL }
-};
-
-const char *gsm_lchans_name(enum gsm_lchan_state s)
-{
- return get_value_string(lchan_s_names, s);
-}
-
-static const struct value_string chreq_names[] = {
- { GSM_CHREQ_REASON_EMERG, "EMERGENCY" },
- { GSM_CHREQ_REASON_PAG, "PAGING" },
- { GSM_CHREQ_REASON_CALL, "CALL" },
- { GSM_CHREQ_REASON_LOCATION_UPD,"LOCATION_UPDATE" },
- { GSM_CHREQ_REASON_OTHER, "OTHER" },
- { 0, NULL }
-};
-
-const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
-{
- return get_value_string(chreq_names, c);
-}
-
-struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num)
-{
- struct gsm_bts *bts;
-
- if (num >= net->num_bts)
- return NULL;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- if (bts->nr == num)
- return bts;
- }
-
- return NULL;
-}
-
-struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
- int k;
-
- if (!trx)
- return NULL;
-
- trx->bts = bts;
- trx->nr = bts->num_trx++;
-
- gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER,
- bts->nr, trx->nr, 0xff);
-
- gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,
- bts->nr, trx->nr, 0xff);
-
- for (k = 0; k < TRX_NR_TS; k++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[k];
- int l;
-
- ts->trx = trx;
- ts->nr = k;
- ts->pchan = GSM_PCHAN_NONE;
- ts->dyn.pchan_is = GSM_PCHAN_NONE;
- ts->dyn.pchan_want = GSM_PCHAN_NONE;
- ts->tsc = -1;
-
- gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,
- bts->nr, trx->nr, ts->nr);
-
- ts->hopping.arfcns.data_len = sizeof(ts->hopping.arfcns_data);
- ts->hopping.arfcns.data = ts->hopping.arfcns_data;
- ts->hopping.ma.data_len = sizeof(ts->hopping.ma_data);
- ts->hopping.ma.data = ts->hopping.ma_data;
-
- for (l = 0; l < TS_MAX_LCHAN; l++) {
- struct gsm_lchan *lchan;
- char *name;
- lchan = &ts->lchan[l];
-
- lchan->ts = ts;
- lchan->nr = l;
- lchan->type = GSM_LCHAN_NONE;
-
- name = gsm_lchan_name_compute(lchan);
- lchan->name = talloc_strdup(trx, name);
- INIT_LLIST_HEAD(&lchan->sapi_cmds);
- }
- }
-
- if (trx->nr != 0)
- trx->nominal_power = bts->c0->nominal_power;
-
- llist_add_tail(&trx->list, &bts->trx_list);
-
- return trx;
-}
-
-
-static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
-static const uint8_t bts_cell_timer_default[] =
- { 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
-static const struct gprs_rlc_cfg rlc_cfg_default = {
- .parameter = {
- [RLC_T3142] = 20,
- [RLC_T3169] = 5,
- [RLC_T3191] = 5,
- [RLC_T3193] = 160, /* 10ms */
- [RLC_T3195] = 5,
- [RLC_N3101] = 10,
- [RLC_N3103] = 4,
- [RLC_N3105] = 8,
- [CV_COUNTDOWN] = 15,
- [T_DL_TBF_EXT] = 250 * 10, /* ms */
- [T_UL_TBF_EXT] = 250 * 10, /* ms */
- },
- .paging = {
- .repeat_time = 5 * 50, /* ms */
- .repeat_count = 3,
- },
- .cs_mask = 0x1fff,
- .initial_cs = 2,
- .initial_mcs = 6,
-};
-
-struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
-{
- struct gsm_bts *bts = talloc_zero(ctx, struct gsm_bts);
- int i;
-
- if (!bts)
- return NULL;
-
- bts->nr = bts_num;
- bts->num_trx = 0;
- INIT_LLIST_HEAD(&bts->trx_list);
- bts->ms_max_power = 15; /* dBm */
-
- gsm_mo_init(&bts->mo, bts, NM_OC_BTS,
- bts->nr, 0xff, 0xff);
- gsm_mo_init(&bts->site_mgr.mo, bts, NM_OC_SITE_MANAGER,
- 0xff, 0xff, 0xff);
-
- for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
- bts->gprs.nsvc[i].bts = bts;
- bts->gprs.nsvc[i].id = i;
- gsm_mo_init(&bts->gprs.nsvc[i].mo, bts, NM_OC_GPRS_NSVC,
- bts->nr, i, 0xff);
- }
- memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
- sizeof(bts->gprs.nse.timer));
- gsm_mo_init(&bts->gprs.nse.mo, bts, NM_OC_GPRS_NSE,
- bts->nr, 0xff, 0xff);
- memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
- sizeof(bts->gprs.cell.timer));
- gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL,
- bts->nr, 0xff, 0xff);
- memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default,
- sizeof(bts->gprs.cell.rlc_cfg));
-
- /* create our primary TRX. It will be initialized during bts_init() */
- bts->c0 = gsm_bts_trx_alloc(bts);
- if (!bts->c0) {
- talloc_free(bts);
- return NULL;
- }
- bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
-
- bts->rach_b_thresh = -1;
- bts->rach_ldavg_slots = -1;
- bts->features.data = &bts->_features_data[0];
- bts->features.data_len = sizeof(bts->_features_data);
-
- /* si handling */
- bts->bcch_change_mark = 1;
-
- return bts;
-}
-
-struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num)
-{
- struct gsm_bts_trx *trx;
-
- if (num >= bts->num_trx)
- return NULL;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->nr == num)
- return trx;
- }
-
- return NULL;
-}
-
-static char ts2str[255];
-
-char *gsm_trx_name(const struct gsm_bts_trx *trx)
-{
- if (!trx)
- snprintf(ts2str, sizeof(ts2str), "(trx=NULL)");
- else
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
- trx->bts->nr, trx->nr);
-
- return ts2str;
-}
-
-
-char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
-{
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr);
-
- return ts2str;
-}
-
-/*! Log timeslot number with full pchan information */
-char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
-{
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- if (ts->dyn.pchan_is == ts->dyn.pchan_want)
- snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan),
- gsm_pchan_name(ts->dyn.pchan_is));
- else
- snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s"
- " switching %s -> %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan),
- gsm_pchan_name(ts->dyn.pchan_is),
- gsm_pchan_name(ts->dyn.pchan_want));
- break;
- case GSM_PCHAN_TCH_F_PDCH:
- if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)
- snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan),
- (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
- : "TCH/F");
- else
- snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s"
- " switching %s -> %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan),
- (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
- : "TCH/F",
- (ts->flags & TS_F_PDCH_ACT_PENDING)? "PDCH"
- : "TCH/F");
- break;
- default:
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,pchan=%s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan));
- break;
- }
-
- return ts2str;
-}
-
-char *gsm_lchan_name_compute(const struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr);
-
- return ts2str;
-}
-
-/* obtain the MO structure for a given object instance */
-struct gsm_abis_mo *
-gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst)
-{
- struct gsm_bts_trx *trx;
- struct gsm_abis_mo *mo = NULL;
-
- switch (obj_class) {
- case NM_OC_BTS:
- mo = &bts->mo;
- break;
- case NM_OC_RADIO_CARRIER:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- mo = &trx->mo;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- mo = &trx->bb_transc.mo;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- if (obj_inst->ts_nr >= TRX_NR_TS)
- return NULL;
- mo = &trx->ts[obj_inst->ts_nr].mo;
- break;
- case NM_OC_SITE_MANAGER:
- mo = &bts->site_mgr.mo;
- break;
- case NM_OC_GPRS_NSE:
- mo = &bts->gprs.nse.mo;
- break;
- case NM_OC_GPRS_CELL:
- mo = &bts->gprs.cell.mo;
- break;
- case NM_OC_GPRS_NSVC:
- if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
- return NULL;
- mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo;
- break;
- }
- return mo;
-}
-
-/* obtain the gsm_nm_state data structure for a given object instance */
-struct gsm_nm_state *
-gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst)
-{
- struct gsm_abis_mo *mo;
-
- mo = gsm_objclass2mo(bts, obj_class, obj_inst);
- if (!mo)
- return NULL;
-
- return &mo->nm_state;
-}
-
-/* obtain the in-memory data structure of a given object instance */
-void *
-gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
- const struct abis_om_obj_inst *obj_inst)
-{
- struct gsm_bts_trx *trx;
- void *obj = NULL;
-
- switch (obj_class) {
- case NM_OC_BTS:
- obj = bts;
- break;
- case NM_OC_RADIO_CARRIER:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- obj = trx;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- obj = &trx->bb_transc;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr >= bts->num_trx) {
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- if (obj_inst->ts_nr >= TRX_NR_TS)
- return NULL;
- obj = &trx->ts[obj_inst->ts_nr];
- break;
- case NM_OC_SITE_MANAGER:
- obj = &bts->site_mgr;
- break;
- case NM_OC_GPRS_NSE:
- obj = &bts->gprs.nse;
- break;
- case NM_OC_GPRS_CELL:
- obj = &bts->gprs.cell;
- break;
- case NM_OC_GPRS_NSVC:
- if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
- return NULL;
- obj = &bts->gprs.nsvc[obj_inst->trx_nr];
- break;
- }
- return obj;
-}
-
-/* See Table 10.5.25 of GSM04.08 */
-static uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
- uint8_t ts_nr, uint8_t lchan_nr)
-{
- uint8_t cbits, chan_nr;
-
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
-
- switch (pchan) {
- case GSM_PCHAN_TCH_F:
- OSMO_ASSERT(lchan_nr == 0);
- cbits = 0x01;
- break;
- case GSM_PCHAN_PDCH:
- OSMO_ASSERT(lchan_nr == 0);
- cbits = RSL_CHAN_OSMO_PDCH >> 3;
- break;
- case GSM_PCHAN_TCH_H:
- OSMO_ASSERT(lchan_nr < 2);
- cbits = 0x02;
- cbits += lchan_nr;
- break;
- case GSM_PCHAN_CCCH_SDCCH4:
- case GSM_PCHAN_CCCH_SDCCH4_CBCH:
- /*
- * As a special hack for BCCH, lchan_nr == 4 may be passed
- * here. This should never be sent in an RSL message.
- * See osmo-bts-xxx/oml.c:opstart_compl().
- */
- if (lchan_nr == CCCH_LCHAN)
- cbits = 0x10; /* BCCH */
- else {
- OSMO_ASSERT(lchan_nr < 4);
- cbits = 0x04;
- cbits += lchan_nr;
- }
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
- OSMO_ASSERT(lchan_nr < 8);
- cbits = 0x08;
- cbits += lchan_nr;
- break;
- case GSM_PCHAN_CCCH:
- default:
- /* OSMO_ASSERT(lchan_nr == 0);
- * FIXME: On octphy and litecell, we hit above assertion (see
- * Max's comment at https://gerrit.osmocom.org/589 ); disabled
- * for BTS until this is clarified; remove the #ifdef when it
- * is fixed. Tracked in OS#2906.
- */
-#pragma message "fix caller that passes lchan_nr != 0"
- cbits = 0x10;
- break;
- }
-
- chan_nr = (cbits << 3) | (ts_nr & 0x7);
-
- return chan_nr;
-}
-
-uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
-{
- switch (lchan->ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- /* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
- * nonstandard value reflecting PDCH for Osmocom style dyn TS. */
- return gsm_lchan_as_pchan2chan_nr(lchan,
- lchan->ts->dyn.pchan_is);
- case GSM_PCHAN_TCH_F_PDCH:
- /* For ip.access style dyn TS, we always want to use the chan_nr as if it was TCH/F.
- * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
- return gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
- default:
- return gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
- }
-}
-
-uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
- enum gsm_phys_chan_config as_pchan)
-{
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
- && as_pchan == GSM_PCHAN_PDCH)
- return RSL_CHAN_OSMO_PDCH | (lchan->ts->nr & ~RSL_CHAN_NR_MASK);
- return gsm_pchan2chan_nr(as_pchan, lchan->ts->nr, lchan->nr);
-}
-
-/* return the gsm_lchan for the CBCH (if it exists at all) */
-struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts)
-{
- struct gsm_lchan *lchan = NULL;
- struct gsm_bts_trx *trx = bts->c0;
-
- if (trx->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH)
- lchan = &trx->ts[0].lchan[2];
- else {
- int i;
- for (i = 0; i < 8; i++) {
- if (trx->ts[i].pchan == GSM_PCHAN_SDCCH8_SACCH8C_CBCH) {
- lchan = &trx->ts[i].lchan[2];
- break;
- }
- }
- }
-
- return lchan;
-}
-
-/* determine logical channel based on TRX and channel number IE */
-struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
- int *rc)
-{
- uint8_t ts_nr = chan_nr & 0x07;
- uint8_t cbits = chan_nr >> 3;
- uint8_t lch_idx;
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
- bool ok = true;
-
- if (rc)
- *rc = -EINVAL;
-
- if (cbits == 0x01) {
- lch_idx = 0; /* TCH/F */
- if (ts->pchan != GSM_PCHAN_TCH_F &&
- ts->pchan != GSM_PCHAN_PDCH &&
- ts->pchan != GSM_PCHAN_TCH_F_PDCH &&
- ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
- ok = false;
- } else if ((cbits & 0x1e) == 0x02) {
- lch_idx = cbits & 0x1; /* TCH/H */
- if (ts->pchan != GSM_PCHAN_TCH_H &&
- ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
- ok = false;
- } else if ((cbits & 0x1c) == 0x04) {
- lch_idx = cbits & 0x3; /* SDCCH/4 */
- if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
- ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
- ok = false;
- } else if ((cbits & 0x18) == 0x08) {
- lch_idx = cbits & 0x7; /* SDCCH/8 */
- if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C &&
- ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C_CBCH)
- ok = false;
- } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
- lch_idx = 0;
- if (ts->pchan != GSM_PCHAN_CCCH &&
- ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
- ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
- ok = false;
- /* FIXME: we should not return first sdcch4 !!! */
- } else if ((chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_OSMO_PDCH) {
- lch_idx = 0;
- if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
- ok = false;
- } else
- return NULL;
-
- if (rc && ok)
- *rc = 0;
-
- return &ts->lchan[lch_idx];
-}
-
-static const uint8_t subslots_per_pchan[] = {
- [GSM_PCHAN_NONE] = 0,
- [GSM_PCHAN_CCCH] = 0,
- [GSM_PCHAN_PDCH] = 0,
- [GSM_PCHAN_CCCH_SDCCH4] = 4,
- [GSM_PCHAN_TCH_F] = 1,
- [GSM_PCHAN_TCH_H] = 2,
- [GSM_PCHAN_SDCCH8_SACCH8C] = 8,
- [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4,
- [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8,
- /*
- * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be
- * part of this, those TS are handled according to their dynamic state.
- */
-};
-
-/*! Return the actual pchan type, also heeding dynamic TS. */
-enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts)
-{
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- return ts->dyn.pchan_is;
- case GSM_PCHAN_TCH_F_PDCH:
- if (ts->flags & TS_F_PDCH_ACTIVE)
- return GSM_PCHAN_PDCH;
- else
- return GSM_PCHAN_TCH_F;
- default:
- return ts->pchan;
- }
-}
-
-/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of
- * logical channels available in the timeslot. */
-uint8_t ts_subslots(struct gsm_bts_trx_ts *ts)
-{
- return subslots_per_pchan[ts_pchan(ts)];
-}
-
-static bool pchan_is_tch(enum gsm_phys_chan_config pchan)
-{
- switch (pchan) {
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- return true;
- default:
- return false;
- }
-}
-
-bool ts_is_tch(struct gsm_bts_trx_ts *ts)
-{
- return pchan_is_tch(ts_pchan(ts));
-}
-
-const char *gsm_trx_unit_id(struct gsm_bts_trx *trx)
-{
- static char buf[23];
-
- snprintf(buf, sizeof(buf), "%u/%u/%u", trx->bts->ip_access.site_id,
- trx->bts->ip_access.bts_id, trx->nr);
- return buf;
-}
-
-const struct value_string lchan_ciph_state_names[] = {
- { LCHAN_CIPH_NONE, "NONE" },
- { LCHAN_CIPH_RX_REQ, "RX_REQ" },
- { LCHAN_CIPH_RX_CONF, "RX_CONF" },
- { LCHAN_CIPH_RXTX_REQ, "RXTX_REQ" },
- { LCHAN_CIPH_RX_CONF_TX_REQ, "RX_CONF_TX_REQ" },
- { LCHAN_CIPH_RXTX_CONF, "RXTX_CONF" },
- { 0, NULL }
-};
-
-/* determine the ECU codec constant for the codec used by given lchan */
-int lchan2ecu_codec(const struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- if (ts_pchan(ts) == GSM_PCHAN_TCH_H)
- return OSMO_ECU_CODEC_HR;
- else
- return OSMO_ECU_CODEC_FR;
- break;
- case GSM48_CMODE_SPEECH_EFR:
- return OSMO_ECU_CODEC_EFR;
- case GSM48_CMODE_SPEECH_AMR:
- return OSMO_ECU_CODEC_AMR;
- default:
- return -1;
- }
-}
diff --git a/src/common/handover.c b/src/common/handover.c
index 63a98324..4b2e6bec 100644
--- a/src/common/handover.c
+++ b/src/common/handover.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -51,7 +51,7 @@ static int ho_tx_phys_info(struct gsm_lchan *lchan)
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_RR;
gh->msg_type = GSM48_MT_RR_HANDO_INFO;
- msgb_put_u8(msg, lchan->rqd_ta);
+ msgb_put_u8(msg, lchan->ta_ctrl.current);
rsl_rll_push_l3(msg, RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan),
0x00, 0);
@@ -111,7 +111,8 @@ void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
"TA=%u, ref=%u\n", gsm_lchant_name(lchan->type), acc_delay, ra);
/* Set timing advance */
- lchan->rqd_ta = acc_delay;
+ lchan->ta_ctrl.current = acc_delay;
+ lchan->want_dl_sacch_active = true;
/* Stop handover detection, wait for valid frame */
lchan->ho.active = HANDOVER_WAIT_FRAME;
@@ -122,7 +123,7 @@ void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
}
/* Send HANDover DETect to BSC */
- rsl_tx_hando_det(lchan, &lchan->rqd_ta);
+ rsl_tx_hando_det(lchan, &lchan->ta_ctrl.current);
/* Send PHYS INFO */
lchan->ho.phys_info_count = 1;
@@ -135,7 +136,7 @@ void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
osmo_timer_schedule(&lchan->ho.t3105, 0, bts->t3105_ms * 1000);
}
-/* received frist valid data frame on dedicated channel */
+/* received first valid data frame on dedicated channel */
void handover_frame(struct gsm_lchan *lchan)
{
LOGPLCHAN(lchan, DHO, LOGL_INFO, "First valid frame detected\n");
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index f07e79ca..5f275cd8 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -33,10 +33,13 @@
#include <osmocom/gsm/l1sap.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/rlp.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+
#include <osmocom/trau/osmo_ortp.h>
#include <osmo-bts/logging.h>
@@ -51,41 +54,17 @@
#include <osmo-bts/abis.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/handover.h>
-#include <osmo-bts/power_control.h>
#include <osmo-bts/msg_utils.h>
+#include <osmo-bts/rtp_input_preen.h>
#include <osmo-bts/pcuif_proto.h>
#include <osmo-bts/cbch.h>
-
-
-#define CB_FCCH -1
-#define CB_SCH -2
-#define CB_BCCH -3
-#define CB_IDLE -4
-
-/* according to TS 05.02 Clause 7 Table 3 of 9 an Figure 8a */
-static const int ccch_block_table[51] = {
- CB_FCCH, CB_SCH,/* 0..1 */
- CB_BCCH, CB_BCCH, CB_BCCH, CB_BCCH, /* 2..5: BCCH */
- 0, 0, 0, 0, /* 6..9: B0 */
- CB_FCCH, CB_SCH,/* 10..11 */
- 1, 1, 1, 1, /* 12..15: B1 */
- 2, 2, 2, 2, /* 16..19: B2 */
- CB_FCCH, CB_SCH,/* 20..21 */
- 3, 3, 3, 3, /* 22..25: B3 */
- 4, 4, 4, 4, /* 26..29: B4 */
- CB_FCCH, CB_SCH,/* 30..31 */
- 5, 5, 5, 5, /* 32..35: B5 */
- 6, 6, 6, 6, /* 36..39: B6 */
- CB_FCCH, CB_SCH,/* 40..41 */
- 7, 7, 7, 7, /* 42..45: B7 */
- 8, 8, 8, 8, /* 46..49: B8 */
- -4 /* 50: Idle */
-};
+#include <osmo-bts/asci.h>
+#include <osmo-bts/csd_v110.h>
/* determine the CCCH block number based on the frame number */
unsigned int l1sap_fn2ccch_block(uint32_t fn)
{
- int rc = ccch_block_table[fn%51];
+ int rc = gsm0502_fn2ccch_block(fn);
/* if FN is negative, we were called for something that's not CCCH! */
OSMO_ASSERT(rc >= 0);
return rc;
@@ -94,18 +73,25 @@ unsigned int l1sap_fn2ccch_block(uint32_t fn)
struct gsm_lchan *get_lchan_by_chan_nr(struct gsm_bts_trx *trx,
unsigned int chan_nr)
{
+ struct gsm_bts_trx_ts *ts;
unsigned int tn, ss;
tn = L1SAP_CHAN2TS(chan_nr);
- OSMO_ASSERT(tn < ARRAY_SIZE(trx->ts));
+ ts = &trx->ts[tn];
+
+ if (L1SAP_IS_CHAN_VAMOS(chan_nr)) {
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ }
if (L1SAP_IS_CHAN_CBCH(chan_nr))
ss = 2; /* CBCH is always on sub-slot 2 */
else
ss = l1sap_chan2ss(chan_nr);
- OSMO_ASSERT(ss < ARRAY_SIZE(trx->ts[tn].lchan));
+ OSMO_ASSERT(ss < ARRAY_SIZE(ts->lchan));
- return &trx->ts[tn].lchan[ss];
+ return &ts->lchan[ss];
}
static struct gsm_lchan *
@@ -131,7 +117,8 @@ static uint32_t fn_ms_adj(uint32_t fn, const struct gsm_lchan *lchan)
/* 12/13 frames usable for audio in TCH,
160 samples per RTP packet,
1 RTP packet per 4 frames */
- samples_passed = (fn - lchan->tch.last_fn) * 12 * 160 / (13 * 4);
+ const uint32_t num_fn = GSM_TDMA_FN_SUB(fn, lchan->tch.last_fn);
+ samples_passed = num_fn * 12 * 160 / (13 * 4);
/* round number of samples to the nearest multiple of
GSM_RTP_DURATION */
r = samples_passed + GSM_RTP_DURATION / 2;
@@ -145,27 +132,13 @@ static uint32_t fn_ms_adj(uint32_t fn, const struct gsm_lchan *lchan)
return GSM_RTP_DURATION;
}
-/*! limit number of queue entries to %u; drops any surplus messages */
-static void queue_limit_to(const char *prefix, struct llist_head *queue, unsigned int limit)
-{
- unsigned int count = llist_count(queue);
-
- if (count > limit)
- LOGP(DL1P, LOGL_NOTICE, "%s: freeing %d queued frames\n", prefix, count-limit);
- while (count > limit) {
- struct msgb *tmp = msgb_dequeue(queue);
- msgb_free(tmp);
- count--;
- }
-}
-
/* allocate a msgb containing a osmo_phsap_prim + optional l2 data
- * in order to wrap femtobts header arround l2 data, there must be enough space
+ * in order to wrap femtobts header around l2 data, there must be enough space
* in front and behind data pointer */
struct msgb *l1sap_msgb_alloc(unsigned int l2_len)
{
- int headroom = 128;
- int size = headroom + sizeof(struct osmo_phsap_prim) + l2_len;
+ const int headroom = L1SAP_MSGB_HEADROOM;
+ const int size = headroom + sizeof(struct osmo_phsap_prim) + l2_len;
struct msgb *msg = msgb_alloc_headroom(size, headroom, "l1sap_prim");
if (!msg)
@@ -176,9 +149,15 @@ struct msgb *l1sap_msgb_alloc(unsigned int l2_len)
return msg;
}
+/* Enclose rmsg into an osmo_phsap primitive and hand it over to the higher
+ * layers. The phsap primitive also contains measurement information. The
+ * parameters rssi, ta_offs and is_sub are only needed when the measurement
+ * information is passed along with the TCH data. When separate measurement
+ * indications are used, those last three parameters may be set to zero. */
int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
struct gsm_lchan *lchan, uint8_t chan_nr, uint32_t fn,
- uint16_t ber10k, int16_t lqual_cb)
+ uint16_t ber10k, int16_t lqual_cb, int8_t rssi,
+ int16_t ta_offs, uint8_t is_sub)
{
struct osmo_phsap_prim *l1sap;
@@ -194,6 +173,10 @@ int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
l1sap->u.tch.ber10k = ber10k;
l1sap->u.tch.lqual_cb = lqual_cb;
+ l1sap->u.tch.rssi = rssi;
+ l1sap->u.tch.ta_offs_256bits = ta_offs;
+ l1sap->u.tch.is_sub = is_sub;
+
return l1sap_up(trx, l1sap);
}
@@ -257,37 +240,96 @@ int bts_check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan,
return check_for_ciph_cmd(msg, lchan, chan_nr);
}
-struct gsmtap_inst *gsmtap = NULL;
-uint32_t gsmtap_sapi_mask = 0;
-uint8_t gsmtap_sapi_acch = 0;
-
-const struct value_string gsmtap_sapi_names[] = {
- { GSMTAP_CHANNEL_BCCH, "BCCH" },
- { GSMTAP_CHANNEL_CCCH, "CCCH" },
- { GSMTAP_CHANNEL_RACH, "RACH" },
- { GSMTAP_CHANNEL_AGCH, "AGCH" },
- { GSMTAP_CHANNEL_PCH, "PCH" },
- { GSMTAP_CHANNEL_SDCCH, "SDCCH" },
- { GSMTAP_CHANNEL_TCH_F, "TCH/F" },
- { GSMTAP_CHANNEL_TCH_H, "TCH/H" },
- { GSMTAP_CHANNEL_PACCH, "PACCH" },
- { GSMTAP_CHANNEL_PDCH, "PDTCH" },
- { GSMTAP_CHANNEL_PTCCH, "PTCCH" },
- { GSMTAP_CHANNEL_CBCH51,"CBCH" },
- { GSMTAP_CHANNEL_ACCH, "SACCH" },
+uint16_t l1sap_log_ctx_sapi;
+
+const struct value_string l1sap_common_sapi_names[] = {
+ { L1SAP_COMMON_SAPI_UNKNOWN, "UNKNOWN" },
+ /* alphabetic order */
+ { L1SAP_COMMON_SAPI_AGCH, "AGCH" },
+ { L1SAP_COMMON_SAPI_BCCH, "BCCH" },
+ { L1SAP_COMMON_SAPI_CBCH, "CBCH" },
+ { L1SAP_COMMON_SAPI_FACCH_F, "FACCH/F" },
+ { L1SAP_COMMON_SAPI_FACCH_H, "FACCH/H" },
+ { L1SAP_COMMON_SAPI_FCCH, "FCCH" },
+ { L1SAP_COMMON_SAPI_IDLE, "IDLE" },
+ { L1SAP_COMMON_SAPI_NCH, "NCH" },
+ { L1SAP_COMMON_SAPI_PACCH, "PACCH" },
+ { L1SAP_COMMON_SAPI_PAGCH, "PAGCH" },
+ { L1SAP_COMMON_SAPI_PBCCH, "PBCCH" },
+ { L1SAP_COMMON_SAPI_PCH, "PCH" },
+ { L1SAP_COMMON_SAPI_PDTCH, "PDTCH" },
+ { L1SAP_COMMON_SAPI_PNCH, "PNCH" },
+ { L1SAP_COMMON_SAPI_PPCH, "PPCH" },
+ { L1SAP_COMMON_SAPI_PRACH, "PRACH" },
+ { L1SAP_COMMON_SAPI_PTCCH, "PTCCH" },
+ { L1SAP_COMMON_SAPI_RACH, "RACH" },
+ { L1SAP_COMMON_SAPI_SACCH, "SACCH" },
+ { L1SAP_COMMON_SAPI_SCH, "SCH" },
+ { L1SAP_COMMON_SAPI_SDCCH, "SDCCH" },
+ { L1SAP_COMMON_SAPI_TCH_F, "TCH/F" },
+ { L1SAP_COMMON_SAPI_TCH_H, "TCH/H" },
{ 0, NULL }
};
+static enum l1sap_common_sapi get_common_sapi_ph_data(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
+{
+ uint8_t link_id = l1sap->u.data.link_id;
+ uint8_t chan_nr = l1sap->u.data.chan_nr;
+ uint32_t u32Fn = l1sap->u.data.fn;
+
+ if (L1SAP_IS_CHAN_TCHF(chan_nr))
+ return L1SAP_COMMON_SAPI_TCH_F;
+
+ if (L1SAP_IS_CHAN_TCHH(chan_nr))
+ return L1SAP_COMMON_SAPI_TCH_H;
+
+ if (L1SAP_IS_CHAN_SDCCH4(chan_nr) || L1SAP_IS_CHAN_SDCCH8(chan_nr))
+ return L1SAP_COMMON_SAPI_SDCCH;
+
+ if (L1SAP_IS_CHAN_BCCH(chan_nr))
+ return L1SAP_COMMON_SAPI_BCCH;
+
+ if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr))
+ /* The sapi depends on DSP configuration, not on the actual SYSTEM INFORMATION 3. */
+ return ((l1sap_fn2ccch_block(u32Fn) >= num_agch(trx, "PH-DATA-REQ"))
+ ? L1SAP_COMMON_SAPI_PCH
+ : L1SAP_COMMON_SAPI_AGCH);
+
+ if (L1SAP_IS_CHAN_CBCH(chan_nr))
+ return L1SAP_COMMON_SAPI_CBCH;
+
+ if (L1SAP_IS_LINK_SACCH(link_id))
+ return L1SAP_COMMON_SAPI_SACCH;
+
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+}
+
+static enum l1sap_common_sapi get_common_sapi_by_trx_prim(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
+{
+ /* Only downlink prims are relevant */
+ switch (OSMO_PRIM_HDR(&l1sap->oph)) {
+ case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST):
+ if (ts_is_pdch(&trx->ts[L1SAP_CHAN2TS(l1sap->u.data.chan_nr)]))
+ return ((L1SAP_IS_PTCCH(l1sap->u.data.fn))
+ ? L1SAP_COMMON_SAPI_PTCCH
+ : L1SAP_COMMON_SAPI_PDTCH);
+ return get_common_sapi_ph_data(trx, l1sap);
+ default:
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ }
+}
+
/* send primitive as gsmtap */
-static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type,
- uint8_t *ss, uint32_t fn, uint8_t **data, unsigned int *len,
+static int gsmtap_ph_data(const struct osmo_phsap_prim *l1sap,
+ uint8_t *chan_type, uint8_t *ss, uint32_t fn,
+ uint8_t **data, unsigned int *len,
uint8_t num_agch)
{
struct msgb *msg = l1sap->oph.msg;
uint8_t chan_nr, link_id;
*data = msgb_l2(msg);
- *len = msgb_l2len(msg);
+ *len = msgb_l2(msg) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -322,47 +364,63 @@ static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type,
return 0;
}
-static int gsmtap_pdch(struct osmo_phsap_prim *l1sap, uint8_t *chan_type,
- uint8_t *ss, uint32_t fn, uint8_t **data, unsigned int *len)
+static int gsmtap_pdch(const struct osmo_phsap_prim *l1sap,
+ uint8_t *chan_type, uint8_t *ss, uint32_t fn,
+ uint8_t **data, unsigned int *len)
{
struct msgb *msg = l1sap->oph.msg;
*data = msgb_l2(msg);
- *len = msgb_l2len(msg);
+ *len = msgb_l2(msg) ? msgb_l2len(msg) : 0;
if (L1SAP_IS_PTCCH(fn)) {
*chan_type = GSMTAP_CHANNEL_PTCCH;
*ss = L1SAP_FN2PTCCHBLOCK(fn);
- if (l1sap->oph.primitive == PRIM_OP_INDICATION) {
- OSMO_ASSERT(len > 0);
- if ((*data[0]) == 7)
- return -EINVAL;
- (*data)++;
- (*len)--;
- }
- } else
- *chan_type = GSMTAP_CHANNEL_PACCH;
+ } else {
+ /* TODO: distinguish PACCH */
+ *chan_type = GSMTAP_CHANNEL_PDTCH;
+ }
return 0;
}
-static int gsmtap_ph_rach(struct osmo_phsap_prim *l1sap, uint8_t *chan_type,
- uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, unsigned int *len)
+static int gsmtap_ph_rach(const struct osmo_phsap_prim *l1sap, uint8_t *chan_type,
+ uint8_t *tn, uint8_t *ss, uint32_t *fn,
+ uint8_t **data, unsigned int *len)
{
- uint8_t chan_nr;
+ uint8_t chan_nr = l1sap->u.rach_ind.chan_nr;
+ static uint8_t ra_buf[2];
*chan_type = GSMTAP_CHANNEL_RACH;
*fn = l1sap->u.rach_ind.fn;
- *tn = L1SAP_CHAN2TS(l1sap->u.rach_ind.chan_nr);
- chan_nr = l1sap->u.rach_ind.chan_nr;
+ *tn = L1SAP_CHAN2TS(chan_nr);
+
if (L1SAP_IS_CHAN_TCHH(chan_nr))
*ss = L1SAP_CHAN2SS_TCHH(chan_nr);
else if (L1SAP_IS_CHAN_SDCCH4(chan_nr))
*ss = L1SAP_CHAN2SS_SDCCH4(chan_nr);
else if (L1SAP_IS_CHAN_SDCCH8(chan_nr))
*ss = L1SAP_CHAN2SS_SDCCH8(chan_nr);
- *data = (uint8_t *)&l1sap->u.rach_ind.ra;
- *len = 1;
+ else if (L1SAP_IS_CHAN_PDCH(chan_nr)) {
+ if (L1SAP_IS_PTCCH(*fn)) {
+ /* TODO: calculate sub-slot from frame-number */
+ *chan_type = GSMTAP_CHANNEL_PTCCH;
+ } else {
+ *chan_type = GSMTAP_CHANNEL_PDTCH;
+ }
+ }
+
+ if (l1sap->u.rach_ind.is_11bit) {
+ /* Pack as described in 3GPP TS 44.004, figure 7.4a.b */
+ ra_buf[0] = (uint8_t) (l1sap->u.rach_ind.ra >> 3);
+ ra_buf[1] = (uint8_t) (l1sap->u.rach_ind.ra & 0x07);
+ *len = sizeof(ra_buf);
+ *data = ra_buf;
+ } else {
+ ra_buf[0] = (uint8_t) (l1sap->u.rach_ind.ra & 0xff);
+ *len = sizeof(ra_buf[0]);
+ *data = ra_buf;
+ }
return 0;
}
@@ -375,8 +433,14 @@ static const uint8_t paging_fill[GSM_MACBLOCK_LEN] = {
static bool is_fill_frame(uint8_t chan_type, const uint8_t *data, unsigned int len)
{
+ if (len != GSM_MACBLOCK_LEN)
+ return false;
+
switch (chan_type) {
case GSMTAP_CHANNEL_AGCH:
+ case GSMTAP_CHANNEL_SDCCH:
+ case GSMTAP_CHANNEL_TCH_F:
+ case GSMTAP_CHANNEL_TCH_H:
if (!memcmp(data, fill_frame, GSM_MACBLOCK_LEN))
return true;
break;
@@ -384,6 +448,7 @@ static bool is_fill_frame(uint8_t chan_type, const uint8_t *data, unsigned int l
if (!memcmp(data, paging_fill, GSM_MACBLOCK_LEN))
return true;
break;
+ /* FIXME: implement the same for GSMTAP_CHANNEL_PDTCH from/to PCU */
/* don't use 'default' case here as the above only conditionally return true */
}
return false;
@@ -396,9 +461,11 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
uint8_t chan_type = 0, tn = 0, ss = 0;
uint32_t fn;
uint16_t uplink = GSMTAP_ARFCN_F_UPLINK;
+ int8_t signal_dbm;
int rc;
- if (!gsmtap)
+ struct gsmtap_inst *inst = trx->bts->gsmtap.inst;
+ if (!inst)
return 0;
switch (OSMO_PRIM_HDR(&l1sap->oph)) {
@@ -414,10 +481,12 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
else
rc = gsmtap_ph_data(l1sap, &chan_type, &ss, fn, &data,
&len, num_agch(trx, "GSMTAP"));
+ signal_dbm = l1sap->u.data.rssi;
break;
case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION):
rc = gsmtap_ph_rach(l1sap, &chan_type, &tn, &ss, &fn, &data,
&len);
+ signal_dbm = l1sap->u.rach_ind.rssi;
break;
default:
rc = -ENOTSUP;
@@ -429,10 +498,10 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (len == 0)
return 0;
if ((chan_type & GSMTAP_CHANNEL_ACCH)) {
- if (!gsmtap_sapi_acch)
+ if (!trx->bts->gsmtap.sapi_acch)
return 0;
} else {
- if (!((1 << (chan_type & 31)) & gsmtap_sapi_mask))
+ if (!((1 << (chan_type & 31)) & trx->bts->gsmtap.sapi_mask))
return 0;
}
@@ -441,8 +510,8 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (is_fill_frame(chan_type, data, len))
return 0;
- gsmtap_send(gsmtap, trx->arfcn | uplink, tn, chan_type, ss, fn, 0, 0,
- data, len);
+ gsmtap_send(inst, trx->arfcn | uplink, tn, chan_type, ss, fn,
+ signal_dbm, 0 /* TODO: SNR */, data, len);
return 0;
}
@@ -487,22 +556,73 @@ static unsigned int calc_exprd_rach_frames(struct gsm_bts *bts, uint32_t fn)
return rach_frames_expired;
}
+static void l1sap_interf_meas_calc_avg(struct gsm_bts_trx *trx)
+{
+ unsigned int tn, ln;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (ts->mo.nm_state.availability != NM_AVSTATE_OK)
+ continue;
+
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+
+ lchan->meas.interf_meas_avg_dbm = 0;
+ lchan->meas.interf_band = 0;
+
+ /* There must be at least one sample */
+ if (lchan->meas.interf_meas_num == 0)
+ continue;
+
+ /* Average all collected samples */
+ gsm_lchan_interf_meas_calc_avg(lchan);
+ }
+ }
+}
+
+static void l1sap_interf_meas_report(struct gsm_bts *bts)
+{
+ const uint32_t period = bts->interference.intave * 104;
+ struct gsm_bts_trx *trx;
+
+ if (bts->interference.intave == 0)
+ return;
+ if (bts->gsm_time.fn % period != 0)
+ return;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
+ trx->bb_transc.mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ /* Calculate the average of all received samples */
+ l1sap_interf_meas_calc_avg(trx);
+ /* Report to the BSC over the A-bis/RSL */
+ rsl_tx_rf_res(trx);
+ /* Report to the PCU over the PCUIF */
+ pcu_tx_interf_ind(trx, bts->gsm_time.fn);
+ }
+}
+
/* time information received from bts model */
static int l1sap_info_time_ind(struct gsm_bts *bts,
struct osmo_phsap_prim *l1sap,
struct info_time_ind_param *info_time_ind)
{
- int frames_expired;
- int i;
+ unsigned int frames_expired;
+ unsigned int i;
DEBUGPFN(DL1P, info_time_ind->fn, "Rx MPH_INFO time ind\n");
/* Calculate and check frame difference */
- frames_expired = info_time_ind->fn - bts->gsm_time.fn;
+ frames_expired = GSM_TDMA_FN_SUB(info_time_ind->fn, bts->gsm_time.fn);
if (frames_expired > 1) {
if (bts->gsm_time.fn)
LOGPFN(DL1P, LOGL_ERROR, info_time_ind->fn,
- "Invalid condition detected: Frame difference is %"PRIu32"-%"PRIu32"=%d > 1!\n",
+ "Invalid condition detected: Frame difference is %"PRIu32"-%"PRIu32"=%u > 1!\n",
info_time_ind->fn, bts->gsm_time.fn, frames_expired);
}
@@ -515,10 +635,14 @@ static int l1sap_info_time_ind(struct gsm_bts *bts,
/* increment number of RACH slots that have passed by since the
* last time indication */
for (i = 0; i < frames_expired; i++) {
- uint32_t fn = (info_time_ind->fn + GSM_HYPERFRAME - i) % GSM_HYPERFRAME;
+ uint32_t fn = GSM_TDMA_FN_SUB(info_time_ind->fn, i);
bts->load.rach.total += calc_exprd_rach_frames(bts, fn);
}
+ /* Report interference levels to the BSC */
+ if (bts_internal_flag_get(bts, BTS_INTERNAL_FLAG_INTERF_MEAS))
+ l1sap_interf_meas_report(bts);
+
return 0;
}
@@ -542,49 +666,93 @@ static inline void set_ms_to_data(struct gsm_lchan *lchan, int16_t data, bool se
}
}
+bool trx_sched_is_sacch_fn(const struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
+
/* measurement information received from bts model */
-static int l1sap_info_meas_ind(struct gsm_bts_trx *trx,
- struct osmo_phsap_prim *l1sap,
- struct info_meas_ind_param *info_meas_ind)
+static void process_l1sap_meas_data(struct gsm_lchan *lchan,
+ const struct osmo_phsap_prim *l1sap,
+ enum osmo_ph_prim ind_type)
{
struct bts_ul_meas ulm;
- struct gsm_lchan *lchan;
-
- lchan = get_active_lchan_by_chan_nr(trx, info_meas_ind->chan_nr);
- if (!lchan) {
- LOGPFN(DL1P, LOGL_ERROR, info_meas_ind->fn,
- "No lchan for MPH INFO MEAS IND (chan_nr=%s)\n", rsl_chan_nr_str(info_meas_ind->chan_nr));
- return 0;
- }
+ const struct info_meas_ind_param *info_meas_ind;
+ const struct ph_data_param *ph_data_ind;
+ const struct ph_tch_param *ph_tch_ind;
+ uint32_t fn;
+ const char *ind_name;
- DEBUGPFN(DL1P, info_meas_ind->fn,
- "%s MPH_INFO meas ind, ta_offs_256bits=%d, ber10k=%d, inv_rssi=%u\n",
- gsm_lchan_name(lchan), info_meas_ind->ta_offs_256bits,
- info_meas_ind->ber10k, info_meas_ind->inv_rssi);
+ /* Do not process measurement reports from non-active VGCS calls. */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt) && lchan->asci.talker_active != VGCS_TALKER_ACTIVE)
+ return;
- /* in the GPRS case we are not interested in measurement
- * processing. The PCU will take care of it */
- if (lchan->type == GSM_LCHAN_PDTCH)
- return 0;
+ switch (ind_type) {
+ case PRIM_MPH_INFO:
+ /* (legacy way, see also OS#2977) */
+ info_meas_ind = &l1sap->u.info.u.meas_ind;
+ fn = info_meas_ind->fn;
+ ind_name = "MPH INFO";
+ ulm = (struct bts_ul_meas) {
+ .ta_offs_256bits = info_meas_ind->ta_offs_256bits,
+ .inv_rssi = info_meas_ind->inv_rssi,
+ .ber10k = info_meas_ind->ber10k,
+ .ci_cb = info_meas_ind->c_i_cb,
+ };
+ /* additionally treat SACCH frames (match by TDMA FN) as SUB frames */
+ if (info_meas_ind->is_sub || trx_sched_is_sacch_fn(lchan->ts, fn, true))
+ ulm.is_sub = 1;
+ break;
+ case PRIM_TCH:
+ ph_tch_ind = &l1sap->u.tch;
+ if (ph_tch_ind->rssi == 0)
+ return;
+ fn = ph_tch_ind->fn;
+ ind_name = "TCH";
+ ulm = (struct bts_ul_meas) {
+ .ta_offs_256bits = ph_tch_ind->ta_offs_256bits,
+ .inv_rssi = abs(ph_tch_ind->rssi),
+ .ber10k = ph_tch_ind->ber10k,
+ .ci_cb = ph_tch_ind->lqual_cb,
+ .is_sub = ph_tch_ind->is_sub,
+ };
+ /* PRIM_TCH always carries DCCH, not SACCH */
+ break;
+ case PRIM_PH_DATA:
+ ph_data_ind = &l1sap->u.data;
+ if (ph_data_ind->rssi == 0)
+ return;
+ fn = ph_data_ind->fn;
+ ind_name = "DATA";
+ ulm = (struct bts_ul_meas) {
+ .ta_offs_256bits = ph_data_ind->ta_offs_256bits,
+ .inv_rssi = abs(ph_data_ind->rssi),
+ .ber10k = ph_data_ind->ber10k,
+ .ci_cb = ph_data_ind->lqual_cb,
+ };
+ /* additionally treat SACCH frames (match by RSL link ID) as SUB frames */
+ if (ph_data_ind->is_sub || L1SAP_IS_LINK_SACCH(ph_data_ind->link_id))
+ ulm.is_sub = 1;
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
- memset(&ulm, 0, sizeof(ulm));
- ulm.ta_offs_256bits = info_meas_ind->ta_offs_256bits;
- ulm.ber10k = info_meas_ind->ber10k;
- ulm.inv_rssi = info_meas_ind->inv_rssi;
- ulm.is_sub = info_meas_ind->is_sub;
+ LOGPLCFN(lchan, fn, DL1P, LOGL_DEBUG,
+ "%s meas ind, ta_offs_256bits=%d, ber10k=%d, inv_rssi=%u, C/I=%d cB\n", ind_name,
+ ulm.ta_offs_256bits, ulm.ber10k, ulm.inv_rssi, ulm.ci_cb);
/* we assume that symbol period is 1 bit: */
- set_ms_to_data(lchan, info_meas_ind->ta_offs_256bits / 256, true);
+ set_ms_to_data(lchan, ulm.ta_offs_256bits / 256, true);
- lchan_meas_process_measurement(lchan, &ulm, info_meas_ind->fn);
+ lchan_meas_process_measurement(lchan, &ulm, fn);
- return 0;
+ return;
}
-/* any L1 MPH_INFO indication prim recevied from bts model */
+/* any L1 MPH_INFO indication prim received from bts model */
static int l1sap_mph_info_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct mph_info_param *info)
{
+ const struct info_meas_ind_param *meas_ind;
+ struct gsm_lchan *lchan;
int rc = 0;
switch (info->type) {
@@ -599,7 +767,22 @@ static int l1sap_mph_info_ind(struct gsm_bts_trx *trx,
&info->u.time_ind);
break;
case PRIM_INFO_MEAS:
- rc = l1sap_info_meas_ind(trx, l1sap, &info->u.meas_ind);
+ /* We should never get an INFO_IND with PRIM_INFO_MEAS
+ * when BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB is set */
+ if (bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB))
+ OSMO_ASSERT(false);
+
+ meas_ind = &l1sap->u.info.u.meas_ind;
+
+ lchan = get_active_lchan_by_chan_nr(trx, meas_ind->chan_nr);
+ if (!lchan) {
+ LOGPFN(DL1P, LOGL_ERROR, meas_ind->fn,
+ "No lchan for chan_nr=%s\n",
+ rsl_chan_nr_str(meas_ind->chan_nr));
+ return 0;
+ }
+
+ process_l1sap_meas_data(lchan, l1sap, PRIM_MPH_INFO);
break;
default:
LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n",
@@ -616,6 +799,12 @@ static int l1sap_info_act_cnf(struct gsm_bts_trx *trx,
struct info_act_cnf_param *info_act_cnf)
{
struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr);
+ if (lchan == NULL) {
+ LOGPTRX(trx, DL1C, LOGL_ERROR, "get_lchan_by_chan_nr(chan_nr=%s) "
+ "yields NULL for PRIM_INFO_ACTIVATE.conf\n",
+ rsl_chan_nr_str(info_act_cnf->chan_nr));
+ return -ENODEV;
+ }
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "activate confirm chan_nr=%s trx=%d\n",
rsl_chan_nr_str(info_act_cnf->chan_nr), trx->nr);
@@ -639,6 +828,12 @@ static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx,
struct info_act_cnf_param *info_act_cnf)
{
struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, info_act_cnf->chan_nr);
+ if (lchan == NULL) {
+ LOGPTRX(trx, DL1C, LOGL_ERROR, "get_lchan_by_chan_nr(chan_nr=%s) "
+ "yields NULL for PRIM_INFO_ACTIVATE.conf\n",
+ rsl_chan_nr_str(info_act_cnf->chan_nr));
+ return -ENODEV;
+ }
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "deactivate confirm chan_nr=%s trx=%d\n",
rsl_chan_nr_str(info_act_cnf->chan_nr), trx->nr);
@@ -655,7 +850,7 @@ static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx,
return 0;
}
-/* any L1 MPH_INFO confirm prim recevied from bts model */
+/* any L1 MPH_INFO confirm prim received from bts model */
static int l1sap_mph_info_cnf(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct mph_info_param *info)
{
@@ -692,16 +887,15 @@ static int lchan_pdtch_ph_rts_ind_loop(struct gsm_lchan *lchan,
uint8_t *p;
/* de-queue response message (loopback) */
- loop_msg = msgb_dequeue(&lchan->dl_tch_queue);
+ loop_msg = msgb_dequeue_count(&lchan->dl_tch_queue, &lchan->dl_tch_queue_len);
if (!loop_msg) {
- LOGPGT(DL1P, LOGL_NOTICE, tm, "%s: no looped PDTCH message, sending empty\n",
- gsm_lchan_name(lchan));
+ LOGPLCGT(lchan, tm, DL1P, LOGL_NOTICE, "no looped PDTCH message, sending empty\n");
/* empty downlink message */
p = msgb_put(msg, GSM_MACBLOCK_LEN);
memset(p, 0, GSM_MACBLOCK_LEN);
} else {
- LOGPGT(DL1P, LOGL_NOTICE, tm, "%s: looped PDTCH message of %u bytes\n",
- gsm_lchan_name(lchan), msgb_l2len(loop_msg));
+ LOGPLCGT(lchan, tm, DL1P, LOGL_NOTICE, "looped PDTCH message of %u bytes\n",
+ msgb_l2len(loop_msg));
/* copy over data from queued response message */
p = msgb_put(msg, msgb_l2len(loop_msg));
memcpy(p, msgb_l2(loop_msg), msgb_l2len(loop_msg));
@@ -710,17 +904,34 @@ static int lchan_pdtch_ph_rts_ind_loop(struct gsm_lchan *lchan,
return 0;
}
-/* Check if given CCCH frame number is for a PCH or for an AGCH (this function is
+/* Check if given CCCH frame number is for a NCH, PCH or for an AGCH (this function is
* only used internally, it is public to call it from unit-tests) */
-int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn) {
+enum ccch_msgt get_ccch_msgt(struct gsm_bts_trx *trx, uint32_t fn)
+{
+ uint8_t block, first_block, num_blocks;
+ int rc;
+
+ block = l1sap_fn2ccch_block(fn);
+
+ /* If there is an NCH, check if the block number matches. It has priority over PCH/AGCH. */
+ if (trx->bts->asci.pos_nch >= 0) {
+ rc = osmo_gsm48_si1ro_nch_pos_decode(trx->bts->asci.pos_nch, &num_blocks, &first_block);
+ if (rc >= 0 && block >= first_block && block < first_block + num_blocks)
+ return CCCH_MSGT_NCH;
+ }
+
/* Note: The number of available access grant channels is set by the
* parameter BS_AG_BLKS_RES via system information type 3. This SI is
- * transfered to osmo-bts via RSL */
- return l1sap_fn2ccch_block(fn) < num_agch(trx, "PH-RTS-IND");
+ * transferred to osmo-bts via RSL */
+ if (l1sap_fn2ccch_block(fn) < num_agch(trx, "PH-RTS-IND"))
+ return CCCH_MSGT_AGCH;
+
+ return CCCH_MSGT_PCH;
}
+
/* return the measured average of frame numbers that the RTS clock is running in advance */
-int32_t bts_get_avg_fn_advance(struct gsm_bts *bts)
+int32_t bts_get_avg_fn_advance(const struct gsm_bts *bts)
{
if (bts->fn_stats.avg_count == 0)
return 0;
@@ -729,7 +940,7 @@ int32_t bts_get_avg_fn_advance(struct gsm_bts *bts)
static void l1sap_update_fnstats(struct gsm_bts *bts, uint32_t rts_fn)
{
- int32_t delta = (rts_fn + GSM_HYPERFRAME - bts->gsm_time.fn) % GSM_HYPERFRAME;
+ int32_t delta = GSM_TDMA_FN_SUB(rts_fn, bts->gsm_time.fn);
if (delta < bts->fn_stats.min)
bts->fn_stats.min = delta;
@@ -746,6 +957,100 @@ static void l1sap_update_fnstats(struct gsm_bts *bts, uint32_t rts_fn)
}
}
+/* Common dequeueing function */
+static inline struct msgb *lapdm_phsap_dequeue_msg(struct lapdm_entity *le, uint32_t fn)
+{
+ struct osmo_phsap_prim pp;
+ if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
+ return NULL;
+ return pp.oph.msg;
+}
+
+/* Special dequeueing function with FACCH repetition (3GPP TS 44.006, section 10) */
+static inline struct msgb *lapdm_phsap_dequeue_msg_facch(struct gsm_lchan *lchan, struct lapdm_entity *le, uint32_t fn)
+{
+ struct osmo_phsap_prim pp;
+ struct msgb *msg;
+
+ /* Note: The repeated version of the FACCH block must be scheduled 8 or 9 bursts after the original
+ * transmission. see 3GPP TS 44.006, section 10.2 for a more detailed explaination. */
+ if (lchan->rep_acch.dl_facch[0].msg && GSM_TDMA_FN_SUB(fn, lchan->rep_acch.dl_facch[0].fn) >= 8) {
+ /* Re-use stored FACCH message buffer from SLOT #0 for repetition. */
+ msg = lchan->rep_acch.dl_facch[0].msg;
+ lchan->rep_acch.dl_facch[0].msg = NULL;
+ } else if (lchan->rep_acch.dl_facch[1].msg && GSM_TDMA_FN_SUB(fn, lchan->rep_acch.dl_facch[1].fn) >= 8) {
+ /* Re-use stored FACCH message buffer from SLOT #1 for repetition. */
+ msg = lchan->rep_acch.dl_facch[1].msg;
+ lchan->rep_acch.dl_facch[1].msg = NULL;
+ } else {
+ /* Fetch new FACCH from queue ... */
+ if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
+ return NULL;
+ msg = pp.oph.msg;
+
+ /* Check if the LAPDm frame is a command frame,
+ * see also: 3GPP TS 04.06 section 3.2 and 3.3.2.
+ * If the MS explicitly indicated that repeated ACCH is
+ * supported, than all FACCH frames may be repeated
+ * see also: 3GPP TS 44.006, section 10.3). */
+ if (!(lchan->rep_acch_cap.dl_facch_all || msg->data[0] & 0x02))
+ return msg;
+
+ /* ... and store the message buffer for repetition. */
+ if (lchan->rep_acch.dl_facch[0].msg == NULL) {
+ lchan->rep_acch.dl_facch[0].msg = msgb_copy(msg, "rep_facch_0");
+ lchan->rep_acch.dl_facch[0].fn = fn;
+ } else if (lchan->rep_acch.dl_facch[1].msg == NULL) {
+ lchan->rep_acch.dl_facch[1].msg = msgb_copy(msg, "rep_facch_1");
+ lchan->rep_acch.dl_facch[1].fn = fn;
+ } else {
+ /* By definition 3GPP TS 05.02 does not allow more than two (for TCH/H only one) FACCH blocks
+ * to be transmitted simultaniously. */
+ OSMO_ASSERT(false);
+ }
+ }
+
+ return msg;
+}
+
+/* Special dequeueing function with SACCH repetition (3GPP TS 44.006, section 11) */
+static inline struct msgb *lapdm_phsap_dequeue_msg_sacch(struct gsm_lchan *lchan, struct lapdm_entity *le, uint32_t fn)
+{
+ struct osmo_phsap_prim pp;
+ struct msgb *msg;
+ uint8_t sapi;
+
+ /* Note: When the MS disables SACCH repetition, we still must collect
+ * possible candidates in order to have one ready in case the MS enables
+ * SACCH repetition. */
+
+ if (lchan->rep_acch.dl_sacch_msg) {
+ if (lchan->meas.l1_info.srr_sro == 0) {
+ /* Toss previous repetition candidate */
+ msgb_free(lchan->rep_acch.dl_sacch_msg);
+ lchan->rep_acch.dl_sacch_msg = NULL;
+ } else {
+ /* Use previous repetition candidate */
+ msg = lchan->rep_acch.dl_sacch_msg;
+ lchan->rep_acch.dl_sacch_msg = NULL;
+ return msg;
+ }
+ }
+
+ /* Fetch new repetition candidate from queue */
+ if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
+ return NULL;
+ msg = pp.oph.msg;
+ sapi = (msg->data[0] >> 2) & 0x07;
+
+ /* Only LAPDm frames for SAPI 0 may become a repetition
+ * candidate. */
+ if (sapi == 0)
+ lchan->rep_acch.dl_sacch_msg = msgb_copy(msg, "rep_sacch");
+
+ return msg;
+}
+
/* PH-RTS-IND prim received from bts model */
static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind)
@@ -756,12 +1061,12 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
uint8_t chan_nr, link_id;
uint8_t tn;
uint32_t fn;
- uint8_t *p, *si;
+ uint8_t *p = NULL;
+ uint8_t *si;
struct lapdm_entity *le;
- struct osmo_phsap_prim pp;
+ struct msgb *pp_msg;
bool dtxd_facch = false;
int rc;
- int is_ag_res;
chan_nr = rts_ind->chan_nr;
link_id = rts_ind->link_id;
@@ -793,10 +1098,10 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
} else {
/* forward RTS.ind to PCU */
if (L1SAP_IS_PTCCH(rts_ind->fn)) {
- pcu_tx_rts_req(&trx->ts[tn], 1, fn, 1 /* ARFCN */,
+ pcu_tx_rts_req(&trx->ts[tn], 1, fn, trx->arfcn,
L1SAP_FN2PTCCHBLOCK(fn));
} else {
- pcu_tx_rts_req(&trx->ts[tn], 0, fn, 0 /* ARFCN */,
+ pcu_tx_rts_req(&trx->ts[tn], 0, fn, trx->arfcn,
L1SAP_FN2MACBLOCK(fn));
}
/* return early, PCU takes care of rest */
@@ -820,19 +1125,45 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
rsl_chan_nr_str(chan_nr));
return 0;
}
+ if (lchan->pending_rel_ind_msg) {
+ LOGPLCGT(lchan, &g_time, DRSL, LOGL_INFO, "Forward RLL RELease INDication to the BSC\n");
+ abis_bts_rsl_sendmsg(lchan->pending_rel_ind_msg);
+ lchan->pending_rel_ind_msg = NULL;
+ }
if (L1SAP_IS_LINK_SACCH(link_id)) {
p = msgb_put(msg, GSM_MACBLOCK_LEN);
/* L1-header, if not set/modified by layer 1 */
p[0] = lchan->ms_power_ctrl.current;
- p[1] = lchan->rqd_ta;
+ if (lchan->rep_acch.ul_sacch_active)
+ p[0] |= 0x40; /* See also: 3GPP TS 44.004, section 7.1 */
+ p[1] = lchan->ta_ctrl.current;
le = &lchan->lapdm_ch.lapdm_acch;
+ if (lchan->rep_acch_cap.dl_sacch) {
+ /* Check if MS requests SACCH repetition and update state accordingly */
+ if (lchan->meas.l1_info.srr_sro) {
+ if (lchan->rep_acch.dl_sacch_active == false)
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-SACCH repetition: inactive => active\n");
+ lchan->rep_acch.dl_sacch_active = true;
+ } else {
+ if (lchan->rep_acch.dl_sacch_active == true)
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-SACCH repetition: active => inactive\n");
+ lchan->rep_acch.dl_sacch_active = false;
+ }
+ pp_msg = lapdm_phsap_dequeue_msg_sacch(lchan, le, fn);
+ } else {
+ pp_msg = lapdm_phsap_dequeue_msg(le, fn);
+ }
} else {
if (lchan->ts->trx->bts->dtxd)
dtxd_facch = true;
le = &lchan->lapdm_ch.lapdm_dcch;
+ if (lchan->rep_acch.dl_facch_active && lchan->rsl_cmode != RSL_CMOD_SPD_SIGN)
+ pp_msg = lapdm_phsap_dequeue_msg_facch(lchan, le, fn);
+ else
+ pp_msg = lapdm_phsap_dequeue_msg(le, fn);
+ lchan->tch.dtx_fr_hr_efr.dl_facch_stealing = (pp_msg != NULL);
}
- rc = lapdm_phsap_dequeue_prim(le, &pp);
- if (rc < 0) {
+ if (!pp_msg) {
if (L1SAP_IS_LINK_SACCH(link_id)) {
/* No SACCH data from LAPDM pending, send SACCH filling */
uint8_t *si = lchan_sacch_get(lchan);
@@ -841,6 +1172,10 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
memcpy(p + 2, si, GSM_MACBLOCK_LEN - 2);
} else
memcpy(p + 2, fill_frame, GSM_MACBLOCK_LEN - 2);
+ } else if (vgcs_is_uplink_free(lchan)) {
+ /* If UPLINK FREE message is stored, send it with every DCCH frame. */
+ p = msgb_put(msg, GSM_MACBLOCK_LEN);
+ vgcs_uplink_free_get(lchan, p);
} else if (L1SAP_IS_CHAN_SDCCH4(chan_nr) || L1SAP_IS_CHAN_SDCCH8(chan_nr) ||
(lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && !lchan->ts->trx->bts->dtxd)) {
/*
@@ -857,21 +1192,28 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
} else {
/* The +2 is empty space where the DSP inserts the L1 hdr */
if (L1SAP_IS_LINK_SACCH(link_id))
- memcpy(p + 2, pp.oph.msg->data + 2, GSM_MACBLOCK_LEN - 2);
+ memcpy(p + 2, pp_msg->data + 2, GSM_MACBLOCK_LEN - 2);
else {
p = msgb_put(msg, GSM_MACBLOCK_LEN);
- memcpy(p, pp.oph.msg->data, GSM_MACBLOCK_LEN);
+ memcpy(p, pp_msg->data, GSM_MACBLOCK_LEN);
/* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */
- check_for_ciph_cmd(pp.oph.msg, lchan, chan_nr);
+ check_for_ciph_cmd(pp_msg, lchan, chan_nr);
if (dtxd_facch)
dtx_dispatch(lchan, E_FACCH);
+ if (rsl_chan_rt_is_vgcs(lchan->rsl_chan_rt)) {
+ /* Check for UPLINK FREE message and store. */
+ if (pp_msg->data[0] == GSM48_MT_RR_SH_UL_FREE << 2)
+ vgcs_uplink_free_set(lchan, pp_msg->data);
+ /* Keep UPLINK FREE message when sending short header messages. */
+ else if ((pp_msg->data[0] & 0x03) != 0x00)
+ vgcs_uplink_free_reset(lchan);
+ }
}
- msgb_free(pp.oph.msg);
+ msgb_free(pp_msg);
}
} else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) {
p = msgb_put(msg, GSM_MACBLOCK_LEN);
- is_ag_res = is_ccch_for_agch(trx, fn);
- rc = bts_ccch_copy_msg(trx->bts, p, &g_time, is_ag_res);
+ rc = bts_ccch_copy_msg(trx->bts, p, &g_time, get_ccch_msgt(trx, fn));
if (rc <= 0)
memcpy(p, fill_frame, GSM_MACBLOCK_LEN);
}
@@ -884,48 +1226,270 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
return 1;
}
-static bool rtppayload_is_octet_aligned(const uint8_t *rtp_pl, uint8_t payload_len)
-{
- /*
- * Logic: If 1st bit padding is not zero, packet is either:
- * - bandwidth-efficient AMR payload.
- * - malformed packet.
- * However, Bandwidth-efficient AMR 4,75 frame last in payload(F=0, FT=0)
- * with 4th,5ht,6th AMR payload to 0 matches padding==0.
- * Furthermore, both AMR 4,75 bw-efficient and octet alignment are 14 bytes long (AMR 4,75 encodes 95b):
- * bw-efficient: 95b, + 4b hdr + 6b ToC = 105b, + padding = 112b = 14B.
- * octet-aligned: 1B hdr + 1B ToC + 95b = 111b, + padding = 112b = 14B.
- * We cannot use other fields to match since they are inside the AMR
- * payload bits which are unknown.
- * As a result, this function may return false positive (true) for some AMR
- * 4,75 AMR frames, but given the length, CMR and FT read is the same as a
- * consequence, the damage in here is harmless other than being unable to
- * decode the audio at the other side.
- */
- #define AMR_PADDING1(rtp_pl) (rtp_pl[0] & 0x0f)
- #define AMR_PADDING2(rtp_pl) (rtp_pl[1] & 0x03)
+/* The following static functions are helpers for l1sap_tch_rts_ind(),
+ * used only for FR/HR/EFR speech modes. For these speech TCH modes,
+ * if our incoming RTP stream includes SID frames, we need to apply
+ * the following transformations to the downlink frame stream we actually
+ * transmit:
+ *
+ * - We need to cache the last received SID and retransmit it in
+ * SACCH-aligned frame positions, or if the SACCH-aligned frame
+ * position was stolen by FACCH, then right after that FACCH.
+ *
+ * - That cached SID needs to be aged and expired, in accord with
+ * TS 28.062 section C.3.2.1.1 paragraph 5 - the paragraph concerning
+ * expiration of cached downlink SID.
+ *
+ * - In all other frame positions, extraneous SID frames need to be
+ * dropped - we send an empty payload to the BTS model, causing it
+ * to transmit an induced BFI condition on the air (fake DTXd),
+ * or perhaps real DTXd (actually turning off Tx) in the future.
+ */
- if(payload_len < 2 || AMR_PADDING1(rtp_pl) || AMR_PADDING2(rtp_pl))
+/*! \brief Check if the given FN of TCH-RTS-IND corresponds to a mandatory
+ * SID position for non-AMR codecs that follow SACCH alignment.
+ * \param[in] lchan Logical channel on which we check scheduling
+ * \param[in] fn Frame Number for which we check scheduling
+ * \returns true if this FN is a mandatory SID position, false otherwise
+ */
+static inline bool fr_hr_efr_sid_position(struct gsm_lchan *lchan, uint32_t fn)
+{
+ /* See GSM 05.08 section 8.3 for frame numbers - but we are
+ * specifically looking for FNs corresponding to the beginning
+ * of the complete SID frame to be transmitted, rather than all FNs
+ * where we have to put out a non-suppressed burst. */
+ switch (lchan->type) {
+ case GSM_LCHAN_TCH_F:
+ return fn % 104 == 52;
+ case GSM_LCHAN_TCH_H:
+ switch (lchan->nr) {
+ case 0:
+ return fn % 104 == 0 || fn % 104 == 52;
+ case 1:
+ return fn % 104 == 14 || fn % 104 == 66;
+ default:
+ return false;
+ }
+ default:
return false;
+ }
+}
+/*! \brief This helper function implements DTXd input processing for FR/HR/EFR:
+ * we got an RTP input frame, now we need to check if it is SID or not,
+ * and update our DL SID reshaper state accordingly.
+ * \param[in] lchan Logical channel structure of the TCH we work with
+ * \param[in] resp_msg The input frame from RTP
+ * \param[out] sid_result Output flag indicating if the received frame is SID
+ * \returns true if the frame in resp_msg is good, false otherwise
+ */
+static bool fr_hr_efr_dtxd_input(struct gsm_lchan *lchan, struct msgb *resp_msg,
+ bool *sid_result)
+{
+ enum osmo_gsm631_sid_class sidc;
+ bool is_sid;
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (lchan->type == GSM_LCHAN_TCH_F) {
+ sidc = osmo_fr_sid_classify(msgb_l2(resp_msg));
+ switch (sidc) {
+ case OSMO_GSM631_SID_CLASS_SPEECH:
+ is_sid = false;
+ break;
+ case OSMO_GSM631_SID_CLASS_INVALID:
+ /* TS 28.062 section C.3.2.1.1: invalid SIDs
+ * from call leg A UL are treated like BFIs.
+ * Drop this frame and act as if we got nothing
+ * at all from RTP for this FN. */
+ return false;
+ case OSMO_GSM631_SID_CLASS_VALID:
+ is_sid = true;
+ /* The SID code word may have a one bit error -
+ * rejuvenate it. */
+ osmo_fr_sid_reset(msgb_l2(resp_msg));
+ break;
+ default:
+ /* SID classification per GSM 06.31 section
+ * 6.1.1 has only 3 possible outcomes. */
+ OSMO_ASSERT(0);
+ }
+ } else {
+ /* The same kind of classification as we do in
+ * osmo_{fr,efr}_sid_classify() is impossible for HR:
+ * the equivalent ternary SID classification per
+ * GSM 06.41 can only be done in the UL-handling BTS,
+ * directly coupled to the GSM 05.03 channel decoder,
+ * and cannot be reconstructed downstream from frame
+ * payload bits. The only kind of SID we can detect
+ * here is the perfect, error-free kind. However,
+ * if we received RFC 5993 payload and the sender
+ * told us it is valid SID, honor that indication
+ * and rejuvenate the SID codeword. */
+ if (rtpmsg_is_rfc5993_sid(resp_msg)) {
+ is_sid = true;
+ osmo_hr_sid_reset(msgb_l2(resp_msg));
+ } else {
+ is_sid = osmo_hr_check_sid(msgb_l2(resp_msg),
+ msgb_l2len(resp_msg));
+ }
+ }
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ /* same logic as for FRv1 */
+ sidc = osmo_efr_sid_classify(msgb_l2(resp_msg));
+ switch (sidc) {
+ case OSMO_GSM631_SID_CLASS_SPEECH:
+ is_sid = false;
+ break;
+ case OSMO_GSM631_SID_CLASS_INVALID:
+ return false;
+ case OSMO_GSM631_SID_CLASS_VALID:
+ is_sid = true;
+ osmo_efr_sid_reset(msgb_l2(resp_msg));
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ break;
+ default:
+ /* This static function should never be called except for
+ * V1 and EFR speech modes. */
+ OSMO_ASSERT(0);
+ }
+ *sid_result = is_sid;
+ lchan->tch.dtx_fr_hr_efr.last_rtp_input_was_sid = is_sid;
+ if (is_sid) {
+ uint8_t copy_len;
+
+ copy_len = OSMO_MIN(msgb_l2len(resp_msg),
+ ARRAY_SIZE(lchan->tch.dtx_fr_hr_efr.last_sid));
+ memcpy(lchan->tch.dtx_fr_hr_efr.last_sid,
+ msgb_l2(resp_msg), copy_len);
+ lchan->tch.dtx_fr_hr_efr.last_sid_len = copy_len;
+ lchan->tch.dtx_fr_hr_efr.last_sid_age = 0;
+ } else {
+ /* We got a speech frame, not SID - therefore, the state flag
+ * of "we already transmitted a SID" needs to be cleared,
+ * so that the very first SID that follows this talkspurt
+ * will get transmitted right away, without waiting for
+ * the next mandatory SID position. */
+ lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted = false;
+ }
return true;
}
-static bool rtppayload_is_valid(struct gsm_lchan *lchan, struct msgb *resp_msg)
+/*! \brief This helper function implements DTXd output processing for FR/HR/EFR:
+ * here we update our state to deal with cached SID aging, mandatory-Tx
+ * frame positions and FACCH stealing, and we make the desired output
+ * transformations of either regurgitating a cached SID or vice-versa,
+ * dropping a SID we received from RTP.
+ * \param[in] lchan Logical channel structure of the TCH we work with
+ * \param[in] fn Frame Number for which we are preparing DL
+ * \param[in] current_input_is_sid Self-explanatory
+ * \param[in] resp_msg_p Pointer to l1sap_tch_rts_ind() internal variable
+ * \param[in] resp_l1sap_p ditto
+ * \param[in] empty_l1sap_p ditto
+ *
+ * This function gets called with pointers to l1sap_tch_rts_ind() internal
+ * variables and cannot be properly understood on its own, without
+ * understanding the parent function first. This situation is unfortunate,
+ * but it was the only way to factor the present logic out of
+ * l1sap_tch_rts_ind() main body.
+ */
+static void fr_hr_efr_dtxd_output(struct gsm_lchan *lchan, uint32_t fn,
+ bool current_input_is_sid,
+ struct msgb **resp_msg_p,
+ struct osmo_phsap_prim **resp_l1sap_p,
+ struct osmo_phsap_prim *empty_l1sap_p)
{
- /* Avoid sending bw-efficient AMR to lower layers, most bts models
- * don't support it. */
- if(lchan->tch_mode == GSM48_CMODE_SPEECH_AMR &&
- !rtppayload_is_octet_aligned(resp_msg->data, resp_msg->len)) {
- LOGPLCHAN(lchan, DL1P, LOGL_NOTICE,
- "RTP->L1: Dropping unexpected AMR encoding (bw-efficient?) %s\n",
- osmo_hexdump(resp_msg->data, resp_msg->len));
- return false;
+ struct msgb *resp_msg = *resp_msg_p;
+ bool sid_in_hand = current_input_is_sid;
+
+ /* Are we at a mandatory-Tx frame position? If so, clear the state flag
+ * of "we already transmitted a SID in this window" - as of right now,
+ * a SID has _not_ been transmitted in the present window yet, and if
+ * we are in a DTX pause, we do need to transmit a SID update as soon
+ * as we are able to, FACCH permitting. */
+ if (fr_hr_efr_sid_position(lchan, fn))
+ lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted = false;
+
+ /* The next stanza implements logic that was originally meant to reside
+ * in the TFO block in TRAUs: if the source feeding us RTP is in a DTXu
+ * pause (resp_msg == NULL, meaning we got nothing from RTP) *and* the
+ * most recent RTP input we did get was a SID, and that SID hasn't
+ * expired, then we need to replicate that SID. */
+ if (!resp_msg && lchan->tch.dtx_fr_hr_efr.last_rtp_input_was_sid &&
+ lchan->tch.dtx_fr_hr_efr.last_sid_age < 47) {
+ /* Whatever we do further below, any time another 20 ms window
+ * has passed since the last SID was received in RTP, we have
+ * to age that cached SID. */
+ lchan->tch.dtx_fr_hr_efr.last_sid_age++;
+
+ /* The following conditional checking dl_sid_transmitted flag
+ * is peculiar to our sans-E1 architecture. In the original
+ * T1/E1 Abis architecture the TFO-enabled TRAU would repeat
+ * the cached SID from call leg A into *every* 20 ms frame in
+ * its Abis output, and then the BTS would select which ones
+ * it should transmit per the rules of GSM 06.31/06.81 section
+ * 5.1.2. But in our architecture it would be silly and
+ * wasteful to allocate and fill an msgb for this cached SID
+ * only to toss it later in the same function - hence the
+ * logic of section 5.1.2 is absorbed into the decision right
+ * here to proceed with cached SID regurgitation or not,
+ * in the form of the following conditional. */
+ if (!lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted)
+ resp_msg = l1sap_msgb_alloc(lchan->tch.dtx_fr_hr_efr.last_sid_len);
+ if (resp_msg) {
+ resp_msg->l2h = msgb_put(resp_msg,
+ lchan->tch.dtx_fr_hr_efr.last_sid_len);
+ memcpy(resp_msg->l2h, lchan->tch.dtx_fr_hr_efr.last_sid,
+ lchan->tch.dtx_fr_hr_efr.last_sid_len);
+ *resp_msg_p = resp_msg;
+ *resp_l1sap_p = msgb_l1sap_prim(resp_msg);
+ sid_in_hand = true;
+ }
+ } else if (resp_msg && sid_in_hand) {
+ /* This "else if" leg implements the logic of section 5.1.2
+ * for cases when a SID is already present in the RTP input,
+ * as indicated by (resp_msg != NULL) and sid_in_hand being
+ * true. Because we are in the "else" clause of the big "if"
+ * above, this path executes only when the SID has come from
+ * RTP in _this_ frame, rather than regurgitated from cache.
+ * But be it fresh or cached, the rules of section 5.1.2 still
+ * apply, and if we've already transmitted a SID in the current
+ * window, then we need to suppress further SIDs and send
+ * an empty payload to the BTS model, causing the latter
+ * to transmit an induced BFI condition on the air. This
+ * strange-seeming behavior is needed so that the spec-compliant
+ * Rx DTX handler in the MS will produce the expected output,
+ * same as if the GSM network were the old-fashioned kind with
+ * Abis TRAUs and TFO. */
+ if (lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted) {
+ msgb_free(resp_msg);
+ resp_msg = NULL;
+ *resp_msg_p = NULL;
+ *resp_l1sap_p = empty_l1sap_p;
+ }
}
- return true;
+
+ /* The following conditional answers this question: are we actually
+ * transmitting a SID frame on the air right now, at this frame number?
+ * If we are certain the BTS model is going to transmit this SID,
+ * we set the state flag so we won't be transmitting any more SIDs
+ * until we either hit the next mandatory-Tx position or get another
+ * little talkspurt followed by new SID. The check for FACCH stealing
+ * is included because if the BTS model is going to transmit FACCH in
+ * the current FN, then we are not actually transmitting SID right now,
+ * and we still need to transmit a SID ASAP, as soon as the TCH becomes
+ * becomes free from FACCH activity. GSM 06.31/06.81 section 5.1.2
+ * does mention that if the mandatory-Tx frame position is taken up
+ * by FACCH, then we need to send SID in the following frame. */
+ if (resp_msg && sid_in_hand && !lchan->tch.dtx_fr_hr_efr.dl_facch_stealing)
+ lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted = true;
}
-/* TCH-RTS-IND prim recevied from bts model */
+/* TCH-RTS-IND prim received from bts model */
static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind)
{
@@ -935,19 +1499,19 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
struct gsm_lchan *lchan;
uint8_t chan_nr, marker = 0;
uint32_t fn;
- int rc;
+ bool is_fr_hr_efr_sid = false;
chan_nr = rts_ind->chan_nr;
fn = rts_ind->fn;
gsm_fn2gsmtime(&g_time, fn);
- DEBUGPGT(DL1P, &g_time, "Rx TCH-RTS.ind chan_nr=%s\n", rsl_chan_nr_str(chan_nr));
-
lchan = get_active_lchan_by_chan_nr(trx, chan_nr);
if (!lchan) {
LOGPGT(DL1P, LOGL_ERROR, &g_time, "No lchan for PH-RTS.ind (chan_nr=%s)\n", rsl_chan_nr_str(chan_nr));
return 0;
+ } else {
+ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH-RTS.ind\n");
}
if (!lchan->loopback && lchan->abis_ip.rtp_socket) {
@@ -961,13 +1525,9 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION;
}
/* get a msgb from the dl_tx_queue */
- resp_msg = msgb_dequeue(&lchan->dl_tch_queue);
+ resp_msg = msgb_dequeue_count(&lchan->dl_tch_queue, &lchan->dl_tch_queue_len);
if (!resp_msg) {
- DEBUGPGT(DL1P, &g_time, "%s DL TCH Tx queue underrun\n", gsm_lchan_name(lchan));
- resp_l1sap = &empty_l1sap;
- } else if(!rtppayload_is_valid(lchan, resp_msg)) {
- msgb_free(resp_msg);
- resp_msg = NULL;
+ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "DL TCH Tx queue underrun\n");
resp_l1sap = &empty_l1sap;
} else {
/* Obtain RTP header Marker bit from control buffer */
@@ -977,16 +1537,27 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
msgb_push(resp_msg, sizeof(*resp_l1sap));
resp_msg->l1h = resp_msg->data;
resp_l1sap = msgb_l1sap_prim(resp_msg);
+
+ /* FR/HR/EFR SID or non-SID input handling */
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1 ||
+ lchan->tch_mode == GSM48_CMODE_SPEECH_EFR) {
+ bool drop;
+
+ drop = !fr_hr_efr_dtxd_input(lchan, resp_msg,
+ &is_fr_hr_efr_sid);
+ if (OSMO_UNLIKELY(drop)) {
+ msgb_free(resp_msg);
+ resp_msg = NULL;
+ resp_l1sap = &empty_l1sap;
+ }
+ }
}
- /* check for pending REL_IND */
- if (lchan->pending_rel_ind_msg) {
- LOGPGT(DRSL, LOGL_INFO, &g_time, "%s Forward REL_IND to L3\n", gsm_lchan_name(lchan));
- /* Forward it to L3 */
- rc = abis_bts_rsl_sendmsg(lchan->pending_rel_ind_msg);
- lchan->pending_rel_ind_msg = NULL;
- if (rc < 0)
- return rc;
+ /* FR/HR/EFR DTXd output stage */
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1 ||
+ lchan->tch_mode == GSM48_CMODE_SPEECH_EFR) {
+ fr_hr_efr_dtxd_output(lchan, fn, is_fr_hr_efr_sid, &resp_msg,
+ &resp_l1sap, &empty_l1sap);
}
memset(resp_l1sap, 0, sizeof(*resp_l1sap));
@@ -996,48 +1567,67 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
resp_l1sap->u.tch.fn = fn;
resp_l1sap->u.tch.marker = marker;
- DEBUGPGT(DL1P, &g_time, "Tx TCH.req chan_nr=%s\n", rsl_chan_nr_str(chan_nr));
+ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Tx TCH.req\n");
l1sap_down(trx, resp_l1sap);
return 0;
}
+/* Reset link timeout to current value. */
+void radio_link_timeout_reset(struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ lchan->s = bts->radio_link_timeout.current;
+}
+
/* process radio link timeout counter S. Follows TS 05.08 Section 5.2
* "MS Procedure" as the "BSS Procedure [...] shall be determined by the
* network operator." */
-static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame)
+static void radio_link_timeout(struct gsm_lchan *lchan, bool bad_frame)
{
struct gsm_bts *bts = lchan->ts->trx->bts;
+ /* Bypass radio link timeout on VGCS/VBS channels: There is no
+ * uplink SACCH on these when talker is not active. */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt) && lchan->asci.talker_active != VGCS_TALKER_ACTIVE)
+ return;
+
/* Bypass radio link timeout if set to -1 */
- if (bts->radio_link_timeout < 0)
+ if (bts->radio_link_timeout.current < 0)
return;
/* if link loss criterion already reached */
if (lchan->s == 0) {
- DEBUGP(DMEAS, "%s radio link counter S already 0.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
+ "radio link timeout counter S is already 0\n");
return;
}
if (bad_frame) {
- /* count down radio link counter S */
- lchan->s--;
- DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n",
- gsm_lchan_name(lchan), lchan->s);
- if (lchan->s == 0)
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
+ "decreasing radio link timeout counter S=%d -> %d\n",
+ lchan->s, lchan->s - 1);
+ lchan->s--; /* count down radio link counter S */
+ if (lchan->s == 0) {
+ LOGPLCHAN(lchan, DMEAS, LOGL_NOTICE,
+ "radio link timeout counter S reached zero, "
+ "dropping connection\n");
rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
+ }
return;
}
- if (lchan->s < bts->radio_link_timeout) {
+ if (lchan->s < bts->radio_link_timeout.current) {
/* count up radio link counter S */
- lchan->s += 2;
- if (lchan->s > bts->radio_link_timeout)
- lchan->s = bts->radio_link_timeout;
- DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n",
- gsm_lchan_name(lchan), lchan->s);
+ int s = lchan->s + 2;
+ if (s > bts->radio_link_timeout.current)
+ s = bts->radio_link_timeout.current;
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
+ "increasing radio link timeout counter S=%d -> %d\n",
+ lchan->s, s);
+ lchan->s = s;
}
}
@@ -1074,6 +1664,59 @@ int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
return check_for_first_ciphrd(lchan, data, len);
}
+/* Decide if repeated UL-SACCH should be applied or not. If the BER level, of
+ * the received SACCH blocks rises above a certain threshold UL-SACCH
+ * repetition is enabled */
+static void repeated_ul_sacch_active_decision(struct gsm_lchan *lchan,
+ uint16_t ber10k)
+{
+ uint16_t upper = 0;
+ uint16_t lower = 0;
+ bool prev_repeated_ul_sacch_active = lchan->rep_acch.ul_sacch_active;
+
+ /* This is an optimization so that we exit as quickly as possible if
+ * there are no uplink SACCH repetition capabilities present.
+ * However If the repeated UL-SACCH capabilities vanish for whatever
+ * reason, we must be sure that UL-SACCH repetition is disabled. */
+ if (!lchan->rep_acch_cap.ul_sacch) {
+ lchan->rep_acch.ul_sacch_active = false;
+ goto out;
+ }
+
+ /* Threshold disabled (repetition is always on) */
+ if (lchan->rep_acch_cap.rxqual == 0) {
+ lchan->rep_acch.ul_sacch_active = true;
+ goto out;
+ }
+
+ /* convert from RXQUAL value to ber10k value.
+ * see also GSM 05.08, section 8.2.4 (first table, without frame */
+ static const uint16_t ber10k_by_rxqual_upper[] =
+ { 0, 20, 40, 80, 160, 320, 640, 1280 };
+ static const uint16_t ber10k_by_rxqual_lower[] =
+ { 0, 0, 0, 20, 40, 80, 160, 320 };
+ /* Note: The values in the upper vector are taken from the left side
+ * of the table in GSM 05.08, section 8.2.4. The lower vector is just
+ * the upper vector shifted by 2. */
+
+ upper = ber10k_by_rxqual_upper[lchan->rep_acch_cap.rxqual];
+ lower = ber10k_by_rxqual_lower[lchan->rep_acch_cap.rxqual];
+
+ /* If upper/rxqual == 0, then repeated UL-SACCH is always on */
+ if (ber10k >= upper)
+ lchan->rep_acch.ul_sacch_active = true;
+ else if (ber10k <= lower)
+ lchan->rep_acch.ul_sacch_active = false;
+
+out:
+ if (lchan->rep_acch.ul_sacch_active == prev_repeated_ul_sacch_active)
+ return;
+ if (lchan->rep_acch.ul_sacch_active)
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "UL-SACCH repetition: inactive => active\n");
+ else
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "UL-SACCH repetition: active => inactive\n");
+}
+
/* DATA received from bts model */
static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct ph_data_param *data_ind)
@@ -1087,10 +1730,8 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
uint8_t chan_nr, link_id;
uint8_t tn;
uint32_t fn;
- int8_t rssi;
enum osmo_ph_pres_info_type pr_info = data_ind->pdch_presence_info;
- rssi = data_ind->rssi;
chan_nr = data_ind->chan_nr;
link_id = data_ind->link_id;
fn = data_ind->fn;
@@ -1105,36 +1746,33 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
lchan = get_lchan_by_chan_nr(trx, chan_nr);
if (!lchan)
LOGPGT(DL1P, LOGL_ERROR, &g_time, "No lchan for chan_nr=%s\n", rsl_chan_nr_str(chan_nr));
- if (lchan && lchan->loopback && !L1SAP_IS_PTCCH(fn)) {
+ if (lchan && lchan->loopback) {
/* we are in loopback mode (for BER testing)
* mode and need to enqeue the frame to be
* returned in downlink */
- queue_limit_to(gsm_lchan_name(lchan), &lchan->dl_tch_queue, 1);
- msgb_enqueue(&lchan->dl_tch_queue, msg);
+ lchan_dl_tch_queue_enqueue(lchan, msg, 1);
/* Return 1 to signal that we're still using msg
* and it should not be freed */
return 1;
}
- /* don't send bad frames to PCU */
- if (len == 0)
- return -EINVAL;
+ /* There can be no DATA.ind on PTCCH/U (rather RACH.ind instead), but some
+ * BTS models with buggy implementation may still be sending them to us. */
if (L1SAP_IS_PTCCH(fn)) {
- pcu_tx_data_ind(&trx->ts[tn], PCU_IF_SAPI_PTCCH, fn,
- 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn),
- data, len, rssi, data_ind->ber10k,
- data_ind->ta_offs_256bits/64,
- data_ind->lqual_cb);
- } else {
- /* drop incomplete UL block */
- if (pr_info != PRES_INFO_BOTH)
- return 0;
- /* PDTCH / PACCH frame handling */
- pcu_tx_data_ind(&trx->ts[tn], PCU_IF_SAPI_PDTCH, fn, 0 /* ARFCN */,
- L1SAP_FN2MACBLOCK(fn), data, len, rssi, data_ind->ber10k,
- data_ind->ta_offs_256bits/64, data_ind->lqual_cb);
+ LOGPGT(DL1P, LOGL_NOTICE, &g_time, "There can be no DATA.ind on PTCCH/U. "
+ "This is probably a bug of the BTS model you're using, please fix!\n");
+ return -EINVAL;
}
+
+ /* Drop all data from incomplete UL block */
+ if (pr_info != PRES_INFO_BOTH)
+ len = 0;
+
+ /* PDTCH / PACCH frame handling */
+ pcu_tx_data_ind(&trx->ts[tn], PCU_IF_SAPI_PDTCH, fn, trx->arfcn,
+ L1SAP_FN2MACBLOCK(fn), data, len, data_ind->rssi, data_ind->ber10k,
+ data_ind->ta_offs_256bits/64, data_ind->lqual_cb);
return 0;
}
@@ -1144,10 +1782,37 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
return 0;
}
+ /* The ph_data_param contained in the l1sap primitive may contain
+ * measurement data. If this data is present, forward it for
+ * processing */
+ if (bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB))
+ process_l1sap_meas_data(lchan, l1sap, PRIM_PH_DATA);
+
+ if (L1SAP_IS_LINK_SACCH(link_id)) {
+ repeated_ul_sacch_active_decision(lchan, data_ind->ber10k);
+
+ /* Radio Link Timeout counter */
+ if (len == 0) {
+ LOGPLCGT(lchan, &g_time, DL1P, LOGL_INFO, "Lost SACCH block\n");
+ radio_link_timeout(lchan, true);
+ } else {
+ radio_link_timeout(lchan, false);
+ }
+
+ /* Trigger the measurement reporting/processing logic */
+ lchan_meas_handle_sacch(lchan, msg);
+ }
+
+ if (L1SAP_IS_LINK_SACCH(link_id))
+ le = &lchan->lapdm_ch.lapdm_acch;
+ else
+ le = &lchan->lapdm_ch.lapdm_dcch;
+
/* bad frame */
if (len == 0) {
- if (L1SAP_IS_LINK_SACCH(link_id))
- radio_link_timeout(lchan, 1);
+ /* Notify current receive FN to lapdm. */
+ lapdm_t200_fn(le, fn);
+
return -EINVAL;
}
@@ -1155,39 +1820,221 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
if (lchan->ho.active == HANDOVER_WAIT_FRAME)
handover_frame(lchan);
- if (L1SAP_IS_LINK_SACCH(link_id)) {
- radio_link_timeout(lchan, 0);
- le = &lchan->lapdm_ch.lapdm_acch;
- /* save the SACCH L1 header in the lchan struct for RSL MEAS RES */
- if (len < 2) {
- LOGPGT(DL1P, LOGL_NOTICE, &g_time, "SACCH with size %u<2 !?!\n", len);
- return -EINVAL;
- }
- /* Some brilliant engineer decided that the ordering of
- * fields on the Um interface is different from the
- * order of fields in RLS. See TS 04.04 (Chapter 7.2)
- * vs. TS 08.58 (Chapter 9.3.10). */
- lchan->meas.l1_info[0] = data[0] << 3;
- lchan->meas.l1_info[0] |= ((data[0] >> 5) & 1) << 2;
- lchan->meas.l1_info[1] = data[1];
- lchan->meas.flags |= LC_UL_M_F_L1_VALID;
-
- lchan_ms_pwr_ctrl(lchan, data[0] & 0x1f, data_ind->rssi);
- } else
- le = &lchan->lapdm_ch.lapdm_dcch;
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
+ /* report first valid received frame to VGCS talker process */
+ if (lchan->asci.talker_active == VGCS_TALKER_WAIT_FRAME)
+ vgcs_talker_frame(lchan);
+ /* Do not forward any message that is received on the uplink to LAPD while
+ * the uplink is not active. If the MS did not recognize (fast enough) that
+ * the uplink is free, it may continue to transmit LAPD messages. A
+ * response by LAPD to these messages is not desired and not required. If
+ * LAPD would respond, it would cause stopping transmission of UPLINK FREE
+ * messages. No MS could access the uplink anymore.
+ */
+ if (lchan->asci.talker_active != VGCS_TALKER_ACTIVE)
+ return 0;
+ }
if (check_for_first_ciphrd(lchan, data, len))
l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0);
/* SDCCH, SACCH and FACCH all go to LAPDm */
- msgb_pull(msg, (msg->l2h - msg->data));
- msg->l1h = NULL;
+ msgb_pull_to_l2(msg);
lapdm_phsap_up(&l1sap->oph, le);
+ /* Notify current receive FN to lapdm. */
+ lapdm_t200_fn(le, fn);
+
/* don't free, because we forwarded data */
return 1;
}
+/* process one MAC block of unpacked bits of a non-transparent CSD channel */
+static void gsmtap_csd_rlp_process(struct gsm_lchan *lchan, bool is_uplink,
+ const struct ph_tch_param *tch_ind,
+ const uint8_t *data, unsigned int data_len)
+{
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+ struct gsmtap_inst *inst = trx->bts->gsmtap.inst;
+ struct osmo_rlp_frame_decoded rlpf;
+ pbit_t *rlp_buf;
+ uint16_t arfcn;
+ int byte_len;
+
+ if (!inst || !trx->bts->gsmtap.rlp)
+ return;
+
+ if (lchan->csd_mode != LCHAN_CSD_M_NT)
+ return;
+
+ if (is_uplink)
+ rlp_buf = lchan->tch.csd.rlp_buf_ul;
+ else
+ rlp_buf = lchan->tch.csd.rlp_buf_dl;
+
+ /* TCH/F 9.6: 4x60bit block => 240bit RLP frame
+ * TCH/F 4.8: 2x 2x60bit blocks starting at B0/B2/B4 => 240bit RLP frame
+ * TCH/H 4.8: 4x60bit block => 240bit RLP frame
+ * TCH/F 2.4: 2x36bit blocks => transparent only
+ * TCH/H 2.4: 4x36bit blocks => transparent only
+ * TCH/F 14.4: 2x 290 bit block (starting with M1=0) => 576-bit RLP frame
+ */
+
+ if (lchan->type == GSM_LCHAN_TCH_F && lchan->tch_mode == GSM48_CMODE_DATA_6k0) {
+ /* in this mode we have 120bit MAC blocks; two of them need to be concatenated
+ * to render a 240-bit RLP frame. The fist block is present in B0/B2/B4.
+ * The E7 bit is used to indicate the Frame MF0a */
+ OSMO_ASSERT(data_len == 120);
+ ubit_t e7 = data[4*7+3];
+ if (e7 == 0) {
+ osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1);
+ return;
+ } else {
+ osmo_ubit2pbit_ext(rlp_buf, 120, data, 0, data_len, 1);
+ byte_len = 240/8;
+ }
+ } else if (lchan->type == GSM_LCHAN_TCH_F && lchan->tch_mode == GSM48_CMODE_DATA_14k5) {
+ /* in this mode we have 290bit MAC blocks containing M1, M2 and 288 data bits;
+ * two of them need to be concatenated to render a
+ * 576-bit RLP frame. The start of a RLP frame is
+ * denoted by a block with M1-bit set to 0. */
+ OSMO_ASSERT(data_len == 290);
+ ubit_t m1 = data[0];
+ if (m1 == 0) {
+ osmo_ubit2pbit_ext(rlp_buf, 0, data, 2, data_len, 1);
+ return;
+ } else {
+ osmo_ubit2pbit_ext(rlp_buf, 288, data, 2, data_len, 1);
+ byte_len = 576/8;
+ }
+ } else {
+ byte_len = osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1);
+ }
+
+ if (trx->bts->gsmtap.rlp_skip_null) {
+ int rc = osmo_rlp_decode(&rlpf, 0, rlp_buf, byte_len);
+ if (rc == 0 && rlpf.ftype == OSMO_RLP_FT_U && rlpf.u_ftype == OSMO_RLP_U_FT_NULL)
+ return;
+ }
+
+ arfcn = trx->arfcn;
+ if (is_uplink)
+ arfcn |= GSMTAP_ARFCN_F_UPLINK;
+
+ gsmtap_send_ex(inst, GSMTAP_TYPE_GSM_RLP, arfcn, lchan->ts->nr,
+ lchan->type == GSM_LCHAN_TCH_H ? GSMTAP_CHANNEL_VOICE_H : GSMTAP_CHANNEL_VOICE_F,
+ lchan->nr, tch_ind->fn, tch_ind->rssi, 0, rlp_buf, byte_len);
+
+}
+
+static void send_ul_rtp_packet_data(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind,
+ const uint8_t *data, uint16_t data_len)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ uint8_t rtp_pl[RFC4040_RTP_PLEN];
+ int rc;
+
+ gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len);
+
+ rc = csd_v110_rtp_encode(lchan, &rtp_pl[0], data, data_len);
+ if (rc < 0)
+ return;
+
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_TOTAL);
+ if (lchan->rtp_tx_marker)
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_MARKER);
+
+ osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
+ &rtp_pl[0], sizeof(rtp_pl),
+ fn_ms_adj(tch_ind->fn, lchan),
+ lchan->rtp_tx_marker);
+ /* Only clear the marker bit once we have sent a RTP packet with it */
+ lchan->rtp_tx_marker = false;
+}
+
+/* a helper function for the logic in l1sap_tch_ind() */
+static void send_ul_rtp_packet_speech(struct gsm_lchan *lchan, uint32_t fn,
+ const uint8_t *rtp_pl, uint16_t rtp_pl_len)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ if (lchan->abis_ip.osmux.use) {
+ lchan_osmux_send_frame(lchan, rtp_pl, rtp_pl_len,
+ fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
+ } else if (lchan->abis_ip.rtp_socket) {
+ osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
+ rtp_pl, rtp_pl_len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_TOTAL);
+ if (lchan->rtp_tx_marker)
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_MARKER);
+ }
+ /* Only clear the marker bit once we have sent a RTP packet with it */
+ lchan->rtp_tx_marker = false;
+}
+
+/* a helper function for emitting HR1 UL in RFC 5993 format */
+static void send_rtp_rfc5993(struct gsm_lchan *lchan, uint32_t fn,
+ struct msgb *msg)
+{
+ uint8_t toc;
+
+ OSMO_ASSERT(msg->len == GSM_HR_BYTES);
+ /* FIXME: implement proper SID classification per GSM 06.41 section
+ * 6.1.1; see OS#6036. Until then, detect error-free SID frames
+ * using our existing osmo_hr_check_sid() function. */
+ if (osmo_hr_check_sid(msg->data, msg->len))
+ toc = 0x20;
+ else
+ toc = 0x00;
+ msgb_push_u8(msg, toc);
+ send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len);
+}
+
+/* A helper function for l1sap_tch_ind(): handling BFI
+ *
+ * Please note that we pass the msgb to this function, even though it is
+ * currently not used. This msgb passing is a provision for adding
+ * support for TRAU-UL-like RTP payload formats like TW-TS-001 that allow
+ * indicating BFI along with deemed-bad frame data bits, just like
+ * GSM 08.60 and 08.61 TRAU-UL frames.
+ */
+static void tch_ul_bfi_handler(struct gsm_lchan *lchan,
+ const struct gsm_time *g_time, struct msgb *msg)
+{
+ uint32_t fn = g_time->fn;
+ uint8_t ecu_out[GSM_FR_BYTES];
+ int rc;
+
+ /* Are we applying an ECU to this uplink, and are we in a state
+ * (not DTX pause) where we emit ECU output? */
+ if (lchan->ecu_state && !osmo_ecu_is_dtx_pause(lchan->ecu_state)) {
+ rc = osmo_ecu_frame_out(lchan->ecu_state, ecu_out);
+ /* did it actually give us some output? */
+ if (rc > 0) {
+ /* yes, send it out in RTP */
+ send_ul_rtp_packet_speech(lchan, fn, ecu_out, rc);
+ return;
+ }
+ }
+
+ /* Are we in rtp continuous-streaming special mode? If so, send out
+ * a BFI packet as zero-length RTP payload. */
+ if (lchan->ts->trx->bts->rtp_nogaps_mode) {
+ send_ul_rtp_packet_speech(lchan, fn, NULL, 0);
+ return;
+ }
+
+ /* Most classic form of BFI handling: generate an intentional gap
+ * in the outgoing RTP stream. */
+ LOGPLCGT(lchan, g_time, DRTP, LOGL_DEBUG,
+ "Skipping RTP frame with lost payload\n");
+ if (lchan->abis_ip.osmux.use)
+ lchan_osmux_skipped_frame(lchan, fn_ms_adj(fn, lchan));
+ else if (lchan->abis_ip.rtp_socket)
+ osmo_rtp_skipped_frame(lchan->abis_ip.rtp_socket, fn_ms_adj(fn, lchan));
+ lchan->rtp_tx_marker = true;
+}
+
/* TCH received from bts model */
static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
struct ph_tch_param *tch_ind)
@@ -1204,42 +2051,62 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
gsm_fn2gsmtime(&g_time, fn);
- LOGPGT(DL1P, LOGL_INFO, &g_time, "Rx TCH.ind chan_nr=%s\n", rsl_chan_nr_str(chan_nr));
-
lchan = get_active_lchan_by_chan_nr(trx, chan_nr);
if (!lchan) {
LOGPGT(DL1P, LOGL_ERROR, &g_time, "No lchan for TCH.ind (chan_nr=%s)\n", rsl_chan_nr_str(chan_nr));
return 0;
+ } else {
+ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH.ind\n");
}
- msgb_pull(msg, sizeof(*l1sap));
+ /* Notify current receive FN to lapdm.
+ * TCH frames may be indicated before FACCH frames are indicated. To prevent T200 timeout before FACCH is
+ * received, subtract one frame number, so that timeout is processed next time after FACCH is received.
+ */
+ lapdm_t200_fn(&lchan->lapdm_ch.lapdm_dcch, GSM_TDMA_FN_SUB(fn, 1));
+
+ /* The ph_tch_param contained in the l1sap primitive may contain
+ * measurement data. If this data is present, forward it for
+ * processing */
+ if (bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB))
+ process_l1sap_meas_data(lchan, l1sap, PRIM_TCH);
+
+ msgb_pull_to_l2(msg);
/* Low level layers always call us when TCH content is expected, even if
* the content is not available due to decoding issues. Content not
* available is expected as empty payload. We also check if quality is
* good enough. */
if (msg->len && tch_ind->lqual_cb >= bts->min_qual_norm) {
+ /* feed the good frame to the ECU, if we are applying one */
+ if (lchan->ecu_state)
+ osmo_ecu_frame_in(lchan->ecu_state, false, msg->data, msg->len);
/* hand msg to RTP code for transmission */
- if (lchan->abis_ip.rtp_socket)
- osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket,
- msg->data, msg->len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker);
+ switch (lchan->rsl_cmode) {
+ case RSL_CMOD_SPD_SPEECH:
+ if (bts->emit_hr_rfc5993 && lchan->type == GSM_LCHAN_TCH_H &&
+ lchan->tch_mode == GSM48_CMODE_SPEECH_V1)
+ send_rtp_rfc5993(lchan, fn, msg);
+ else
+ send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len);
+ break;
+ case RSL_CMOD_SPD_DATA:
+ send_ul_rtp_packet_data(lchan, tch_ind, msg->data, msg->len);
+ break;
+ case RSL_CMOD_SPD_SIGN:
+ return 0; /* drop stale TCH.ind */
+ default: /* shall not happen */
+ OSMO_ASSERT(0);
+ }
/* if loopback is enabled, also queue received RTP data */
if (lchan->loopback) {
- /* make sure the queue doesn't get too long */
- queue_limit_to(gsm_lchan_name(lchan), &lchan->dl_tch_queue, 1);
- /* add new frame to queue */
- msgb_enqueue(&lchan->dl_tch_queue, msg);
+ /* add new frame to queue, make sure the queue doesn't get too long */
+ lchan_dl_tch_queue_enqueue(lchan, msg, 1);
/* Return 1 to signal that we're still using msg and it should not be freed */
return 1;
}
- /* Only clear the marker bit once we have sent a RTP packet with it */
- lchan->rtp_tx_marker = false;
} else {
- DEBUGPGT(DRTP, &g_time, "Skipping RTP frame with lost payload (chan_nr=0x%02x)\n",
- chan_nr);
- if (lchan->abis_ip.rtp_socket)
- osmo_rtp_skipped_frame(lchan->abis_ip.rtp_socket, fn_ms_adj(fn, lchan));
- lchan->rtp_tx_marker = true;
+ tch_ul_bfi_handler(lchan, &g_time, msg);
}
lchan->tch.last_fn = fn;
@@ -1248,14 +2115,15 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
#define RACH_MIN_TOA256 -2 * 256
-static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts *bts)
+static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts *bts,
+ const char *chan_name)
{
int16_t toa256 = rach_ind->acc_delay_256bits;
/* Check for RACH exceeding BER threshold (ghost RACH) */
if (rach_ind->ber10k > bts->max_ber10k_rach) {
- LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring RACH request: "
- "BER10k(%u) > BER10k_MAX(%u)\n",
+ LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
+ "BER10k(%u) > BER10k_MAX(%u)\n", chan_name,
rach_ind->ber10k, bts->max_ber10k_rach);
return false;
}
@@ -1266,16 +2134,16 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
* according to maximal allowed Timing Advance value.
*/
if (toa256 < RACH_MIN_TOA256 || toa256 > bts->max_ta * 256) {
- LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring RACH request: "
- "ToA(%d) exceeds the allowed range (%d..%d)\n",
+ LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
+ "ToA(%d) exceeds the allowed range (%d..%d)\n", chan_name,
toa256, RACH_MIN_TOA256, bts->max_ta * 256);
return false;
}
/* Link quality defined by C/I (Carrier-to-Interference ratio) */
if (rach_ind->lqual_cb < bts->min_qual_rach) {
- LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring RACH request: "
- "link quality (%d) below the minimum (%d)\n",
+ LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
+ "link quality (%d) below the minimum (%d)\n", chan_name,
rach_ind->lqual_cb, bts->min_qual_rach);
return false;
}
@@ -1283,23 +2151,58 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
return true;
}
-/* Special case where handover RACH is detected */
-static int l1sap_handover_rach(struct gsm_bts_trx *trx,
- struct osmo_phsap_prim *l1sap, struct ph_rach_ind_param *rach_ind)
+/* Special case where RACH on DCCH uplink is detected */
+static int l1sap_dcch_rach(struct gsm_bts_trx *trx, struct ph_rach_ind_param *rach_ind)
{
+ struct gsm_lchan *lchan;
+
/* Filter out noise / interference / ghosts */
- if (!rach_pass_filter(rach_ind, trx->bts)) {
+ if (!rach_pass_filter(rach_ind, trx->bts, "DCCH")) {
rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_DROP);
return 0;
}
- handover_rach(get_lchan_by_chan_nr(trx, rach_ind->chan_nr),
- rach_ind->ra, rach_ind->acc_delay);
+ lchan = get_lchan_by_chan_nr(trx, rach_ind->chan_nr);
+ /* Differentiate + dispatch hand-over and VGCS RACH */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
+ rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_VGCS);
+ vgcs_rach(lchan, rach_ind->ra, rach_ind->acc_delay, rach_ind->fn);
+ } else {
+ rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_HO);
+ handover_rach(lchan, rach_ind->ra, rach_ind->acc_delay);
+ }
/* must return 0, so in case of msg at l1sap, it will be freed */
return 0;
}
+/* Special case for Access Bursts on PDTCH/U or PTCCH/U */
+static int l1sap_pdch_rach(struct gsm_bts_trx *trx, struct ph_rach_ind_param *rach_ind)
+{
+ /* Filter out noise / interference / ghosts */
+ if (!rach_pass_filter(rach_ind, trx->bts, "PDCH"))
+ return -EAGAIN;
+
+ /* PTCCH/U (Packet Timing Advance Control Channel) */
+ if (L1SAP_IS_PTCCH(rach_ind->fn)) {
+ LOGPFN(DL1P, LOGL_DEBUG, rach_ind->fn,
+ /* TODO: calculate and print Timing Advance Index */
+ "Access Burst for continuous Timing Advance control (toa256=%d)\n",
+ rach_ind->acc_delay_256bits);
+
+ /* QTA: Timing Advance in units of 1/4 of a symbol */
+ pcu_tx_rach_ind(trx->bts->nr, trx->nr, rach_ind->chan_nr & 0x07,
+ rach_ind->acc_delay_256bits >> 6,
+ rach_ind->ra, rach_ind->fn, rach_ind->is_11bit,
+ rach_ind->burst_type, PCU_IF_SAPI_PTCCH);
+ return 0;
+ } else { /* The MS may acknowledge DL data by 4 consequent Access Bursts */
+ LOGPFN(DL1P, LOGL_NOTICE, rach_ind->fn,
+ "Access Bursts on PDTCH/U are not (yet) supported\n");
+ return -ENOTSUP;
+ }
+}
+
/* RACH received from bts model */
static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct ph_rach_ind_param *rach_ind)
@@ -1309,10 +2212,16 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
DEBUGPFN(DL1P, rach_ind->fn, "Rx PH-RA.ind\n");
- /* check for handover access burst on dedicated channels */
- if (!L1SAP_IS_CHAN_RACH(rach_ind->chan_nr)) {
- rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_HO);
- return l1sap_handover_rach(trx, l1sap, rach_ind);
+ /* Check the origin of an Access Burst */
+ switch (rach_ind->chan_nr & 0xf8) {
+ case RSL_CHAN_RACH:
+ /* CS or PS RACH, to be handled in this function */
+ break;
+ case RSL_CHAN_OSMO_PDCH:
+ /* TODO: do we need to count Access Bursts on PDCH? */
+ return l1sap_pdch_rach(trx, rach_ind);
+ default:
+ return l1sap_dcch_rach(trx, rach_ind);
}
rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_RCVD);
@@ -1322,7 +2231,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
bts->load.rach.busy++;
/* Filter out noise / interference / ghosts */
- if (!rach_pass_filter(rach_ind, bts)) {
+ if (!rach_pass_filter(rach_ind, bts, "CCCH")) {
rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_DROP);
return 0;
}
@@ -1344,9 +2253,11 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
LOGPFN(DL1P, LOGL_INFO, rach_ind->fn, "RACH for packet access (toa=%d, ra=%d)\n",
rach_ind->acc_delay, rach_ind->ra);
- pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2,
- rach_ind->ra, rach_ind->fn,
- rach_ind->is_11bit, rach_ind->burst_type);
+ /* QTA: Timing Advance in units of 1/4 of a symbol */
+ pcu_tx_rach_ind(bts->nr, trx->nr, rach_ind->chan_nr & 0x07,
+ rach_ind->acc_delay_256bits >> 6,
+ rach_ind->ra, rach_ind->fn, rach_ind->is_11bit,
+ rach_ind->burst_type, PCU_IF_SAPI_RACH);
return 0;
}
@@ -1412,6 +2323,9 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
/* any L1 prim sent to bts model */
static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
+ l1sap_log_ctx_sapi = get_common_sapi_by_trx_prim(trx, l1sap);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+
if (OSMO_PRIM_HDR(&l1sap->oph) ==
OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST))
to_gsmtap(trx, l1sap);
@@ -1440,8 +2354,12 @@ int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
l1sap->u.data.chan_nr = RSL_CHAN_OSMO_PDCH | ts->nr;
l1sap->u.data.link_id = 0x00;
l1sap->u.data.fn = fn;
- msg->l2h = msgb_put(msg, len);
- memcpy(msg->l2h, data, len);
+ if (len) {
+ msg->l2h = msgb_put(msg, len);
+ memcpy(msg->l2h, data, len);
+ } else {
+ msg->l2h = NULL; /* Idle block */
+ }
return l1sap_down(ts->trx, l1sap);
}
@@ -1452,19 +2370,59 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
uint32_t timestamp, bool marker)
{
struct gsm_lchan *lchan = rs->priv;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
struct msgb *msg;
- struct osmo_phsap_prim *l1sap;
+ bool rfc5993_sid = false;
+
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_TOTAL);
+ if (marker)
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_MARKER);
/* if we're in loopback mode, we don't accept frames from the
* RTP socket anymore */
- if (lchan->loopback)
+ if (lchan->loopback) {
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_DROP_LOOPBACK);
return;
+ }
- msg = l1sap_msgb_alloc(rtp_pl_len);
+ /* initial preen */
+ switch (rtp_payload_input_preen(lchan, rtp_pl, rtp_pl_len, &rfc5993_sid)) {
+ case PL_DECISION_DROP:
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_DROP_PREEN);
+ return;
+ case PL_DECISION_ACCEPT:
+ break;
+ case PL_DECISION_STRIP_HDR_OCTET:
+ rtp_pl++;
+ rtp_pl_len--;
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ msg = l1sap_msgb_alloc(512);
if (!msg)
return;
- memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len);
- msgb_pull(msg, sizeof(*l1sap));
+
+ if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA) {
+ int rc = csd_v110_rtp_decode(lchan, msg->tail,
+ rtp_pl, rtp_pl_len);
+ if (rc > 0) {
+ /* 'fake' tch_ind containing all-zero so gsmtap code can be shared
+ * between UL and DL */
+ static const struct ph_tch_param fake_tch_ind = {};
+ gsmtap_csd_rlp_process(lchan, false, &fake_tch_ind, msg->tail, rc);
+ msgb_put(msg, rc);
+ } else {
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_DROP_V110_DEC);
+ msgb_free(msg);
+ return;
+ }
+ } else {
+ memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len);
+ }
+
+ msgb_pull(msg, sizeof(struct osmo_phsap_prim));
/* Store RTP header Marker bit in control buffer */
rtpmsg_marker_bit(msg) = marker;
@@ -1472,11 +2430,11 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
rtpmsg_seq(msg) = seq_number;
/* Store RTP header Timestamp in control buffer */
rtpmsg_ts(msg) = timestamp;
+ /* Store RFC 5993 SID flag likewise */
+ rtpmsg_is_rfc5993_sid(msg) = rfc5993_sid;
/* make sure the queue doesn't get too long */
- queue_limit_to(gsm_lchan_name(lchan), &lchan->dl_tch_queue, 1);
-
- msgb_enqueue(&lchan->dl_tch_queue, msg);
+ lchan_dl_tch_queue_enqueue(lchan, msg, 1);
}
static int l1sap_chan_act_dact_modify(struct gsm_bts_trx *trx, uint8_t chan_nr,
@@ -1494,53 +2452,50 @@ static int l1sap_chan_act_dact_modify(struct gsm_bts_trx *trx, uint8_t chan_nr,
return l1sap_down(trx, &l1sap);
}
-int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp)
+int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr)
{
struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr);
- struct gsm48_chan_desc *cd;
int rc;
- LOGPLCHAN(lchan, DL1C, LOGL_INFO, "activating channel chan_nr=%s trx=%d\n",
- rsl_chan_nr_str(chan_nr), trx->nr);
-
- /* osmo-pcu calls this without a valid 'tp' parameter, so we
- * need to make sure ew don't crash here */
- if (tp && TLVP_PRESENT(tp, GSM48_IE_CHANDESC_2) &&
- TLVP_LEN(tp, GSM48_IE_CHANDESC_2) >= sizeof(*cd)) {
- cd = (struct gsm48_chan_desc *)
- TLVP_VAL(tp, GSM48_IE_CHANDESC_2);
-
- /* our L1 only supports one global TSC for all channels
- * one one TRX, so we need to make sure not to activate
- * channels with a different TSC!! */
- if (cd->h0.tsc != (lchan->ts->trx->bts->bsic & 7)) {
- LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "lchan TSC %u != BSIC-TSC %u\n",
- cd->h0.tsc, lchan->ts->trx->bts->bsic & 7);
- return -RSL_ERR_SERV_OPT_UNIMPL;
- }
+ if (lchan->state == LCHAN_S_ACTIVE) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate already active channel %s\n",
+ rsl_chan_nr_str(chan_nr));
+ return -1;
}
- lchan->sacch_deact = 0;
- lchan->s = lchan->ts->trx->bts->radio_link_timeout;
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Activating channel %s\n", rsl_chan_nr_str(chan_nr));
+
+ radio_link_timeout_reset(lchan);
rc = l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_ACTIVATE, 0);
if (rc)
return -RSL_ERR_EQUIPMENT_FAIL;
+ /* Is it TCH? If it is, attempt to allocate an Error Concealment Unit
+ * instance, if available, unless it is disabled by vty config. */
+ if (lchan_is_tch(lchan) && trx->bts->use_ul_ecu)
+ lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
+ else
+ lchan->ecu_state = NULL;
+
/* Init DTX DL FSM if necessary */
- if (trx->bts->dtxd && lchan->type != GSM_LCHAN_SDCCH) {
- char name[32];
- snprintf(name, sizeof(name), "bts%u-trx%u-ts%u-ss%u", lchan->ts->trx->bts->nr,
- lchan->ts->trx->nr, lchan->ts->nr, lchan->nr);
+ if (trx->bts->dtxd && lchan_is_tch(lchan)) {
lchan->tch.dtx.dl_amr_fsm = osmo_fsm_inst_alloc(&dtx_dl_amr_fsm,
tall_bts_ctx,
lchan,
LOGL_DEBUG,
- name);
+ NULL);
if (!lchan->tch.dtx.dl_amr_fsm) {
l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0);
return -RSL_ERR_EQUIPMENT_FAIL;
}
+
+ rc = osmo_fsm_inst_update_id_f(lchan->tch.dtx.dl_amr_fsm,
+ "bts%u-trx%u-ts%u-ss%u%s",
+ trx->bts->nr, trx->nr,
+ lchan->ts->nr, lchan->nr,
+ lchan->ts->vamos.is_shadow ? "-shadow" : "");
+ OSMO_ASSERT(rc == 0);
}
return 0;
}
@@ -1548,14 +2503,31 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *
int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr)
{
struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr);
- LOGPLCHAN(lchan, DL1C, LOGL_INFO, "deactivating channel chan_nr=%s trx=%d\n",
- rsl_chan_nr_str(chan_nr), trx->nr);
+
+ if (lchan->state == LCHAN_S_NONE) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to deactivate already deactivated channel %s\n",
+ rsl_chan_nr_str(chan_nr));
+ return -1;
+ }
+
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Deactivating channel %s\n",
+ rsl_chan_nr_str(chan_nr));
if (lchan->tch.dtx.dl_amr_fsm) {
osmo_fsm_inst_free(lchan->tch.dtx.dl_amr_fsm);
lchan->tch.dtx.dl_amr_fsm = NULL;
}
+ /* clear ECU state (if any) */
+ if (lchan->ecu_state) {
+ osmo_ecu_destroy(lchan->ecu_state);
+ lchan->ecu_state = NULL;
+ }
+
+ /* reset CSD RLP buffers to avoid any user plane data leaking from
+ * one previous lchan into a later one */
+ memset(&lchan->tch.csd, 0, sizeof(lchan->tch.csd));
+
return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE,
0);
}
@@ -1564,10 +2536,8 @@ int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr)
{
struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr);
- LOGPLCHAN(lchan, DL1C, LOGL_INFO, "deactivating sacch chan_nr=%s trx=%d\n",
- rsl_chan_nr_str(chan_nr), trx->nr);
-
- lchan->sacch_deact = 1;
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Deactivating SACCH on channel %s\n",
+ rsl_chan_nr_str(chan_nr));
return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE,
1);
@@ -1575,8 +2545,46 @@ int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr)
int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr)
{
- LOGP(DL1C, LOGL_INFO, "modifying channel chan_nr=%s trx=%d\n",
- rsl_chan_nr_str(chan_nr), trx->nr);
+ struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr);
+
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Modifying channel %s\n",
+ rsl_chan_nr_str(chan_nr));
+
+ /* Is it TCH? If it is and we are applying internal uplink ECUs,
+ * the new channel mode calls for a different ECU. Any changes
+ * in vty config (enabling or disabling this ECU application)
+ * will also take effect upon channel modification. */
+ if (lchan_is_tch(lchan)) {
+ if (lchan->ecu_state)
+ osmo_ecu_destroy(lchan->ecu_state);
+ if (trx->bts->use_ul_ecu)
+ lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
+ else
+ lchan->ecu_state = NULL;
+ }
return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0);
}
+
+int l1sap_uplink_access(struct gsm_lchan *lchan, bool active)
+{
+ uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ struct osmo_phsap_prim l1sap;
+
+ if (lchan->state != LCHAN_S_ACTIVE && !rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Channel %s is not an active ASCI type channel.\n",
+ rsl_chan_nr_str(chan_nr));
+ return -EINVAL;
+ }
+
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s uplink access detection on channel %s\n",
+ (active) ? "Activating" : "Deactivating", rsl_chan_nr_str(chan_nr));
+
+
+ memset(&l1sap, 0, sizeof(l1sap));
+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_REQUEST, NULL);
+ l1sap.u.info.type = (active) ? PRIM_INFO_ACT_UL_ACC : PRIM_INFO_DEACT_UL_ACC;
+ l1sap.u.info.u.ulacc_req.chan_nr = chan_nr;
+
+ return l1sap_down(lchan->ts->trx, &l1sap);
+}
diff --git a/src/common/lchan.c b/src/common/lchan.c
index 9e98166d..5b41a158 100644
--- a/src/common/lchan.c
+++ b/src/common/lchan.c
@@ -12,38 +12,654 @@
* 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.
+ * GNU Affero 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 "btsconfig.h" /* for PACKAGE_VERSION */
+
#include <osmocom/core/logging.h>
+
+#include <osmocom/trau/osmo_ortp.h>
+
#include <osmo-bts/logging.h>
-#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/lchan.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/handover.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/asci.h>
+#include <errno.h>
+
+static const struct value_string lchan_s_names[] = {
+ { LCHAN_S_NONE, "NONE" },
+ { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
+ { LCHAN_S_ACTIVE, "ACTIVE" },
+ { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
+ { LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
+ { LCHAN_S_BROKEN, "BROKEN UNUSABLE" },
+ { 0, NULL }
+};
+
+const struct value_string lchan_ciph_state_names[] = {
+ { LCHAN_CIPH_NONE, "NONE" },
+ { LCHAN_CIPH_RX_REQ, "RX_REQ" },
+ { LCHAN_CIPH_RX_CONF, "RX_CONF" },
+ { LCHAN_CIPH_RXTX_REQ, "RXTX_REQ" },
+ { LCHAN_CIPH_RX_CONF_TX_REQ, "RX_CONF_TX_REQ" },
+ { LCHAN_CIPH_RXTX_CONF, "RXTX_CONF" },
+ { 0, NULL }
+};
+
+/* prepare the per-SAPI T200 arrays for a given lchan */
+static int t200_by_lchan(uint32_t *t200_fn_dcch, uint32_t *t200_fn_acch, struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_SDCCH];
+ t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_SDCCH_SAPI3];
+ t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_SDCCH];
+ t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_SDCCH];
+ break;
+ case GSM_LCHAN_TCH_F:
+ t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_F];
+ t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_F];
+ t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
+ t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
+ break;
+ case GSM_LCHAN_TCH_H:
+ t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_H];
+ t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_H];
+ t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
+ t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
+ break;
+ default:
+ /* Channels such as CCCH don't use lapdm DL, and hence no T200 is needed */
+ return -1;
+ }
+
+ /* Add time of two extra messages frames. */
+ if (lchan->rep_acch_cap.dl_facch_all && lchan_is_tch(lchan)) {
+ t200_fn_acch[DL_SAPI0] += 104 * 2;
+ t200_fn_acch[DL_SAPI3] += 104 * 2;
+ }
+
+ return 0;
+}
+
+static void early_rr_ia_delay_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ if (!lchan->early_rr_ia) {
+ /* The IA message has disappeared since the timer was started. */
+ return;
+ }
+
+ if (lchan->state != LCHAN_S_ACTIVE) {
+ /* Release has happened since the timer was started. */
+ msgb_free(lchan->early_rr_ia);
+ lchan->early_rr_ia = NULL;
+ return;
+ }
+
+ /* Activation is done, send the RR IA now. Put RR IA msg into the AGCH queue of the BTS. */
+ if (bts_agch_enqueue(bts, lchan->early_rr_ia) < 0) {
+ /* if there is no space in the queue: send DELETE IND */
+ rsl_tx_delete_ind(bts, lchan->early_rr_ia->data, lchan->early_rr_ia->len);
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_AGCH_DELETED);
+ msgb_free(lchan->early_rr_ia);
+ }
+ lchan->early_rr_ia = NULL;
+}
+
+void gsm_lchan_init(struct gsm_lchan *lchan, struct gsm_bts_trx_ts *ts, unsigned int lchan_nr)
+{
+ lchan->ts = ts;
+ lchan->nr = lchan_nr;
+ lchan->type = GSM_LCHAN_NONE;
+ gsm_lchan_name_update(lchan);
+
+ osmo_timer_setup(&lchan->early_rr_ia_delay, early_rr_ia_delay_cb, lchan);
+
+ INIT_LLIST_HEAD(&lchan->sapi_cmds);
+ INIT_LLIST_HEAD(&lchan->dl_tch_queue);
+ lchan->dl_tch_queue_len = 0;
+}
+
+void gsm_lchan_name_update(struct gsm_lchan *lchan)
+{
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+ const struct gsm_bts_trx *trx = ts->trx;
+ char *name;
+
+ name = talloc_asprintf(trx, "(" GSM_TS_NAME_FMT ",ss=%u)",
+ GSM_TS_NAME_ARGS(ts), lchan->nr);
+ if (lchan->name != NULL)
+ talloc_free(lchan->name);
+ lchan->name = name;
+}
+
+int lchan_init_lapdm(struct gsm_lchan *lchan)
+{
+ struct lapdm_channel *lc = &lchan->lapdm_ch;
+ uint32_t t200_fn_dcch[_NR_DL_SAPI], t200_fn_acch[_NR_DL_SAPI];
+
+ if (t200_by_lchan(t200_fn_dcch, t200_fn_acch, lchan) == 0) {
+ LOGPLCHAN(lchan, DLLAPD, LOGL_DEBUG,
+ "Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in frames)\n",
+ t200_fn_dcch[DL_SAPI0], t200_fn_dcch[DL_SAPI3],
+ t200_fn_acch[DL_SAPI0], t200_fn_acch[DL_SAPI3]);
+ lapdm_channel_init3(lc, LAPDM_MODE_BTS, NULL, NULL, lchan->type, gsm_lchan_name(lchan));
+ lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY | LAPDM_ENT_F_RTS);
+ lapdm_channel_set_l1(lc, NULL, lchan);
+ lapdm_channel_set_t200_fn(lc, t200_fn_dcch, t200_fn_acch);
+ }
+ /* We still need to set Rx callback to receive RACH requests: */
+ lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);
+
+ return 0;
+}
+
+static int dyn_ts_pdch_release(struct gsm_lchan *lchan)
+{
+ struct gsm_bts_trx_ts *ts = lchan->ts;
+
+ if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
+ LOGP(DRSL, LOGL_ERROR, "%s: PDCH release requested but already"
+ " in switchover\n", gsm_ts_and_pchan_name(ts));
+ return -EINVAL;
+ }
+
+ /*
+ * Indicate PDCH Disconnect in dyn_pdch.want, let pcu_tx_info_ind()
+ * pick it up and wait for PCU to disable the channel.
+ */
+ ts->dyn.pchan_want = GSM_PCHAN_NONE;
+
+ if (!pcu_connected()) {
+ /* PCU not connected yet. Just record the new type and done,
+ * the PCU will pick it up once connected. */
+ ts->dyn.pchan_is = GSM_PCHAN_NONE;
+ return 1;
+ }
+
+ return pcu_tx_info_ind();
+}
+
+void gsm_lchan_release(struct gsm_lchan *lchan, enum lchan_rel_act_kind rel_kind)
+{
+ int rc;
+
+ if (lchan->abis_ip.rtp_socket) {
+ rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
+ osmo_rtp_socket_log_stats(lchan->abis_ip.rtp_socket, DRTP, LOGL_INFO,
+ "Closing RTP socket on Channel Release ");
+ lchan_rtp_socket_free(lchan);
+ } else if (lchan->abis_ip.osmux.use) {
+ lchan_osmux_release(lchan);
+ }
+ /* reset all Abis related config: */
+ memset(&lchan->abis_ip, 0, sizeof(lchan->abis_ip));
+
+ /* FIXME: right now we allow creating the rtp_socket even if chan is not
+ * activated... Once we check for that, we can move this check at the
+ * start of the function */
+ if (lchan->state == LCHAN_S_NONE)
+ return;
+
+ /* release handover, listener and talker states */
+ handover_reset(lchan);
+ vgcs_talker_reset(lchan, false);
+ vgcs_listener_reset(lchan);
+ vgcs_uplink_free_reset(lchan);
+
+ lchan->rel_act_kind = rel_kind;
+
+ /* Dynamic channel in PDCH mode is released via PCU */
+ if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN
+ && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) {
+ rc = dyn_ts_pdch_release(lchan);
+ if (rc == 1) {
+ /* If the PCU is not connected, continue to rel ack right away. */
+ lchan->rel_act_kind = LCHAN_REL_ACT_PCU;
+ rsl_tx_rf_rel_ack(lchan);
+ return;
+ }
+ /* Waiting for PDCH release */
+ return;
+ }
+
+ l1sap_chan_rel(lchan->ts->trx, gsm_lchan2chan_nr(lchan));
+}
+
+int lchan_deactivate(struct gsm_lchan *lchan)
+{
+ OSMO_ASSERT(lchan);
+
+ lchan->ciph_state = 0;
+ return bts_model_lchan_deactivate(lchan);
+}
+
+const char *gsm_lchans_name(enum gsm_lchan_state s)
+{
+ return get_value_string(lchan_s_names, s);
+}
+
+/* obtain the next to-be transmitted dowlink SACCH frame (L2 hdr + L3); returns pointer to lchan->si buffer */
+uint8_t *lchan_sacch_get(struct gsm_lchan *lchan)
+{
+ uint32_t tmp, i;
+
+ for (i = 0; i < _MAX_SYSINFO_TYPE; i++) {
+ tmp = (lchan->si.last + 1 + i) % _MAX_SYSINFO_TYPE;
+ if (!(lchan->si.valid & (1 << tmp)))
+ continue;
+ lchan->si.last = tmp;
+ return GSM_LCHAN_SI(lchan, tmp);
+ }
+ LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "SACCH no SI available\n");
+ return NULL;
+}
void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state)
{
- DEBUGP(DL1C, "%s state %s -> %s\n",
- gsm_lchan_name(lchan),
- gsm_lchans_name(lchan->state),
- gsm_lchans_name(state));
+ if (lchan->state == state)
+ return;
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "state %s -> %s\n",
+ gsm_lchans_name(lchan->state), gsm_lchans_name(state));
lchan->state = state;
+
+ switch (lchan->state) {
+ case LCHAN_S_ACT_REQ:
+ /* Early Immediate Assignment: Activation is requested, keep the
+ * early IA until active. This allows the BSC to send the IA
+ * even before a dynamic timeslot is done switching to a
+ * different pchan kind (experimental). */
+ break;
+ case LCHAN_S_ACTIVE:
+ lchan_init_lapdm(lchan);
+ if (lchan->early_rr_ia) {
+ /* Early Immediate Assignment: Activation is done, send
+ * the RR IA now. Delay a bit more to give Um time to
+ * let the lchan light up for the MS */
+ osmo_timer_del(&lchan->early_rr_ia_delay);
+ osmo_timer_schedule(&lchan->early_rr_ia_delay, 0,
+ osmo_tdef_get(abis_T_defs, -15, OSMO_TDEF_US, -1));
+ }
+ break;
+ case LCHAN_S_NONE:
+ lapdm_channel_exit(&lchan->lapdm_ch);
+ /* Also ensure that there are no leftovers from repeated FACCH or
+ * repeated SACCH that might cause memory leakage. */
+ msgb_free(lchan->rep_acch.dl_facch[0].msg);
+ msgb_free(lchan->rep_acch.dl_facch[1].msg);
+ lchan->rep_acch.dl_facch[0].msg = NULL;
+ lchan->rep_acch.dl_facch[1].msg = NULL;
+ msgb_free(lchan->rep_acch.dl_sacch_msg);
+ lchan->rep_acch.dl_sacch_msg = NULL;
+ /* free() pending messages */
+ msgb_free(lchan->pending_rel_ind_msg);
+ lchan->pending_rel_ind_msg = NULL;
+ msgb_free(lchan->pending_chan_activ);
+ lchan->pending_chan_activ = NULL;
+ /* fall through */
+ default:
+ if (lchan->early_rr_ia) {
+ /* Early Immediate Assignment: Transition to any other
+ * state means whatever IA the BSC has sent shall now
+ * not be relevant anymore. */
+ osmo_timer_del(&lchan->early_rr_ia_delay);
+ msgb_free(lchan->early_rr_ia);
+ lchan->early_rr_ia = NULL;
+ }
+ break;
+ }
}
-bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
+/* See 3GPP TS 44.018 Table 10.5.2.5.1 "Channel Description information element" */
+static uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
+ uint8_t ts_nr, uint8_t lchan_nr)
{
- switch (ts->pchan) {
+ uint8_t cbits, chan_nr;
+
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
+ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
+
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ OSMO_ASSERT(lchan_nr == 0);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs;
+ break;
case GSM_PCHAN_PDCH:
- return true;
+ OSMO_ASSERT(lchan_nr == 0);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH;
+ break;
+ case GSM_PCHAN_TCH_H:
+ OSMO_ASSERT(lchan_nr < 2);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(lchan_nr);
+ break;
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ /*
+ * As a special hack for BCCH, lchan_nr == 4 may be passed
+ * here. This should never be sent in an RSL message.
+ * See osmo-bts-xxx/oml.c:opstart_compl().
+ */
+ if (lchan_nr == CCCH_LCHAN)
+ cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
+ else {
+ OSMO_ASSERT(lchan_nr < 4);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(lchan_nr);
+ }
+ break;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ OSMO_ASSERT(lchan_nr < 8);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(lchan_nr);
+ break;
+ case GSM_PCHAN_CCCH:
+ cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
+ break;
+ case GSM_PCHAN_NONE:
+ LOGP(DRSL, LOGL_ERROR, "ts=%u,ss=%u Physical channel %s not expected!\n",
+ ts_nr, lchan_nr, gsm_pchan_name(pchan));
+ cbits = 0x00; /* Reserved */
+ break;
+ default:
+ LOGP(DRSL, LOGL_ERROR, "ts=%u,ss=%u Physical channel %s (0x%02x) not expected!\n",
+ ts_nr, lchan_nr, gsm_pchan_name(pchan), (int)pchan);
+ OSMO_ASSERT(0);
+ break;
+ }
+
+ chan_nr = (cbits << 3) | (ts_nr & 0x7);
+
+ return chan_nr;
+}
+
+static uint8_t _gsm_lchan2chan_nr(const struct gsm_lchan *lchan, bool rsl)
+{
+ uint8_t chan_nr;
+
+ switch (lchan->ts->pchan) {
+ case GSM_PCHAN_OSMO_DYN:
+ /* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
+ * nonstandard value reflecting PDCH for Osmocom style dyn TS. */
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, lchan->ts->dyn.pchan_is);
+ break;
case GSM_PCHAN_TCH_F_PDCH:
- return (ts->flags & TS_F_PDCH_ACTIVE)
- && !(ts->flags & TS_F_PDCH_PENDING_MASK);
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- return ts->dyn.pchan_is == GSM_PCHAN_PDCH
- && ts->dyn.pchan_want == ts->dyn.pchan_is;
+ /* For ip.access style dyn TS, on RSL we want to use the chan_nr as if it was TCH/F.
+ * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
+ if (rsl)
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ else if (~lchan->ts->flags & TS_F_PDCH_ACTIVE)
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ else
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_PDCH);
+ break;
+ default:
+ chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
+ break;
+ }
+
+ /* VAMOS: if this lchan belongs to a shadow timeslot, we must reflect
+ * this in the channel number. Convert it to Osmocom specific value. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
+ return chan_nr;
+}
+
+uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
+{
+ return _gsm_lchan2chan_nr(lchan, false);
+}
+
+uint8_t gsm_lchan2chan_nr_rsl(const struct gsm_lchan *lchan)
+{
+ return _gsm_lchan2chan_nr(lchan, true);
+}
+
+uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
+ enum gsm_phys_chan_config as_pchan)
+{
+ if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN
+ && as_pchan == GSM_PCHAN_PDCH)
+ return RSL_CHAN_OSMO_PDCH | (lchan->ts->nr & ~RSL_CHAN_NR_MASK);
+ return gsm_pchan2chan_nr(as_pchan, lchan->ts->nr, lchan->nr);
+}
+
+/* Called by the model specific code every 104 TDMA frames (SACCH period) */
+void gsm_lchan_interf_meas_push(struct gsm_lchan *lchan, int dbm)
+{
+ const uint8_t meas_num = lchan->meas.interf_meas_num;
+
+ if (meas_num >= ARRAY_SIZE(lchan->meas.interf_meas_dbm)) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Not enough room "
+ "to store interference report (%ddBm)\n", dbm);
+ return;
+ }
+
+ lchan->meas.interf_meas_dbm[meas_num] = dbm;
+ lchan->meas.interf_meas_num++;
+}
+
+/* Called by the higher layers every Intave * 104 TDMA frames */
+void gsm_lchan_interf_meas_calc_avg(struct gsm_lchan *lchan)
+{
+ const uint8_t meas_num = lchan->meas.interf_meas_num;
+ const struct gsm_bts *bts = lchan->ts->trx->bts;
+ int b, meas_avg, meas_sum = 0;
+
+ /* There must be at least one sample */
+ OSMO_ASSERT(meas_num > 0);
+
+ /* Calculate the sum of all collected samples (in -x dBm) */
+ while (lchan->meas.interf_meas_num) {
+ uint8_t i = --lchan->meas.interf_meas_num;
+ meas_sum += lchan->meas.interf_meas_dbm[i];
+ }
+
+ /* Calculate the average of all collected samples */
+ meas_avg = meas_sum / (int) meas_num;
+
+ /* 3GPP TS 48.008 defines 5 interference bands, and 6 interference level
+ * boundaries (0, X1, ... X5). It's not clear how to handle values
+ * exceeding the outer boundaries (0 or X5), because bands 0 and 6 do
+ * not exist (sigh). Let's map such values to closest bands 1 and 5. */
+ if (bts->interference.boundary[0] < bts->interference.boundary[5]) {
+ /* Ascending order (band=1 indicates lowest interference) */
+ for (b = 1; b < ARRAY_SIZE(bts->interference.boundary) - 1; b++) {
+ if (meas_avg < bts->interference.boundary[b])
+ break; /* Current 'b' is the band value */
+ }
+ } else {
+ /* Descending order (band=1 indicates highest interference) */
+ for (b = 1; b < ARRAY_SIZE(bts->interference.boundary) - 1; b++) {
+ if (meas_avg >= bts->interference.boundary[b])
+ break; /* Current 'b' is the band value */
+ }
+ }
+
+ LOGPLCHAN(lchan, DL1C, LOGL_DEBUG,
+ "Interference AVG: %ddBm (band %d, samples %u)\n",
+ meas_avg, b, meas_num);
+
+ lchan->meas.interf_meas_avg_dbm = meas_avg;
+ lchan->meas.interf_band = b;
+}
+
+/* determine the ECU codec constant for the codec used by given lchan */
+int lchan2ecu_codec(const struct gsm_lchan *lchan)
+{
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (ts_pchan(ts) == GSM_PCHAN_TCH_H)
+ return OSMO_ECU_CODEC_HR;
+ else
+ return OSMO_ECU_CODEC_FR;
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ return OSMO_ECU_CODEC_EFR;
+ case GSM48_CMODE_SPEECH_AMR:
+ return OSMO_ECU_CODEC_AMR;
default:
- return false;
+ return -1;
+ }
+}
+
+static int bind_rtp(struct gsm_bts *bts, struct osmo_rtp_socket *rs, const char *ip)
+{
+ int rc;
+ unsigned int i;
+ unsigned int tries;
+
+ tries = (bts->rtp_port_range_end - bts->rtp_port_range_start) / 2;
+ for (i = 0; i < tries; i++) {
+
+ if (bts->rtp_port_range_next >= bts->rtp_port_range_end)
+ bts->rtp_port_range_next = bts->rtp_port_range_start;
+
+ rc = osmo_rtp_socket_bind(rs, ip, bts->rtp_port_range_next);
+
+ bts->rtp_port_range_next += 2;
+
+ if (rc != 0)
+ continue;
+
+ if (bts->rtp_ip_dscp != -1) {
+ if (osmo_rtp_socket_set_dscp(rs, bts->rtp_ip_dscp))
+ LOGP(DRSL, LOGL_ERROR, "failed to set DSCP=%d: %s\n",
+ bts->rtp_ip_dscp, strerror(errno));
+ }
+ if (bts->rtp_priority != -1) {
+ if (osmo_rtp_socket_set_priority(rs, bts->rtp_priority))
+ LOGP(DRSL, LOGL_ERROR, "failed to set socket priority %d: %s\n",
+ bts->rtp_priority, strerror(errno));
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+int lchan_rtp_socket_create(struct gsm_lchan *lchan, const char *bind_ip)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ char cname[256+4];
+ int rc;
+
+ if (lchan->abis_ip.rtp_socket) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC CRCX, "
+ "but we already have socket!\n");
+ return -EALREADY;
+ }
+
+ /* FIXME: select default value depending on speech_mode */
+ //if (!payload_type)
+ lchan->tch.last_fn = LCHAN_FN_DUMMY;
+ lchan->abis_ip.rtp_socket = osmo_rtp_socket_create(lchan->ts->trx,
+ OSMO_RTP_F_POLL);
+
+ if (!lchan->abis_ip.rtp_socket) {
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC Failed to create RTP/RTCP sockets\n");
+ oml_tx_failure_event_rep(&lchan->ts->trx->mo,
+ NM_SEVER_MINOR, OSMO_EVT_CRIT_RTP_TOUT,
+ "%s IPAC Failed to create RTP/RTCP sockets",
+ gsm_lchan_name(lchan));
+ return -ENOTCONN;
+ }
+
+ rc = osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket,
+ bts->rtp_jitter_adaptive ?
+ OSMO_RTP_P_JIT_ADAP :
+ OSMO_RTP_P_JITBUF,
+ bts->rtp_jitter_buf_ms);
+ if (rc < 0)
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR,
+ "IPAC Failed to set RTP socket parameters: %s\n", strerror(-rc));
+ else
+ LOGPLCHAN(lchan, DRTP, LOGL_INFO, "IPAC set RTP socket parameters: %d\n", rc);
+
+ lchan->abis_ip.rtp_socket->priv = lchan;
+ lchan->abis_ip.rtp_socket->rx_cb = &l1sap_rtp_rx_cb;
+
+ rc = bind_rtp(bts, lchan->abis_ip.rtp_socket, bind_ip);
+ if (rc < 0) {
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC Failed to bind RTP/RTCP sockets\n");
+ oml_tx_failure_event_rep(&lchan->ts->trx->mo,
+ NM_SEVER_MINOR, OSMO_EVT_CRIT_RTP_TOUT,
+ "%s IPAC Failed to bind RTP/RTCP sockets",
+ gsm_lchan_name(lchan));
+ lchan_rtp_socket_free(lchan);
+ return -EBADFD;
+ }
+
+ /* Ensure RTCP SDES contains some useful information */
+ snprintf(cname, sizeof(cname), "bts@%s", bind_ip);
+ osmo_rtp_set_source_desc(lchan->abis_ip.rtp_socket, cname,
+ gsm_lchan_name(lchan), NULL, NULL,
+ gsm_trx_unit_id(lchan->ts->trx),
+ "OsmoBTS-" PACKAGE_VERSION, NULL);
+ /* FIXME: multiplex connection, BSC proxy */
+ return 0;
+}
+
+
+int lchan_rtp_socket_connect(struct gsm_lchan *lchan, const struct in_addr *ia, uint16_t connect_port)
+{
+ int bound_port = 0;
+ int rc;
+
+ rc = osmo_rtp_socket_connect(lchan->abis_ip.rtp_socket,
+ inet_ntoa(*ia), connect_port);
+ if (rc < 0) {
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "Failed to connect RTP/RTCP sockets\n");
+ return -ECONNREFUSED;
+ }
+ /* save IP address and port number */
+ lchan->abis_ip.connect_ip = ntohl(ia->s_addr);
+ lchan->abis_ip.connect_port = connect_port;
+
+ rc = osmo_rtp_get_bound_ip_port(lchan->abis_ip.rtp_socket,
+ &lchan->abis_ip.bound_ip,
+ &bound_port);
+ if (rc < 0)
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC cannot obtain locally bound IP/port: %d\n", rc);
+ lchan->abis_ip.bound_port = bound_port;
+ return 0;
+}
+
+void lchan_rtp_socket_free(struct gsm_lchan *lchan)
+{
+ osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
+ lchan->abis_ip.rtp_socket = NULL;
+ msgb_queue_free(&lchan->dl_tch_queue);
+ lchan->dl_tch_queue_len = 0;
+}
+
+/*! limit number of queue entries to %u; drops any surplus messages */
+void lchan_dl_tch_queue_enqueue(struct gsm_lchan *lchan, struct msgb *msg, unsigned int limit)
+{
+ if (lchan->dl_tch_queue_len > limit) {
+ unsigned int excess = lchan->dl_tch_queue_len - limit;
+ LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "freeing %d queued frames\n", excess);
+ rate_ctr_add2(lchan->ts->trx->bts->ctrs, BTS_CTR_RTP_RX_DROP_OVERFLOW, excess);
+ }
+ while (lchan->dl_tch_queue_len > limit) {
+ struct msgb *tmp = msgb_dequeue_count(&lchan->dl_tch_queue, &lchan->dl_tch_queue_len);
+ msgb_free(tmp);
}
+ msgb_enqueue_count(&lchan->dl_tch_queue, msg, &lchan->dl_tch_queue_len);
}
diff --git a/src/common/load_indication.c b/src/common/load_indication.c
index fa4745b1..c0d6efb1 100644
--- a/src/common/load_indication.c
+++ b/src/common/load_indication.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -27,6 +27,7 @@
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/paging.h>
+#include <osmo-bts/bts.h>
static void reset_load_counters(struct gsm_bts *bts)
{
@@ -40,6 +41,10 @@ static void load_timer_cb(void *data)
struct gsm_bts *bts = data;
unsigned int pch_percent, rach_percent;
+ /* It makes no sense to send Load Indication if CCCH is still disabled...*/
+ if (bts->c0->ts[0].mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ goto retry_later;
+
/* compute percentages */
if (bts->load.ccch.pch_total == 0)
pch_percent = 0;
@@ -52,7 +57,7 @@ static void load_timer_cb(void *data)
uint16_t buffer_space = paging_buffer_space(bts->paging_state);
rsl_tx_ccch_load_ind_pch(bts, buffer_space);
} else {
- /* This is an extenstion of TS 08.58. We don't only
+ /* This is an extension of TS 08.58. We don't only
* send load indications if the load is above threshold,
* but we also explicitly indicate that we are below
* threshold by using the magic value 0xffff */
@@ -72,6 +77,7 @@ static void load_timer_cb(void *data)
bts->load.rach.access);
}
+retry_later:
reset_load_counters(bts);
/* re-schedule the timer */
@@ -93,3 +99,8 @@ void load_timer_stop(struct gsm_bts *bts)
{
osmo_timer_del(&bts->load.ccch.timer);
}
+
+bool load_timer_is_running(const struct gsm_bts *bts)
+{
+ return osmo_timer_pending(&bts->load.ccch.timer);
+}
diff --git a/src/common/logging.c b/src/common/logging.c
index 3315a019..15c126a2 100644
--- a/src/common/logging.c
+++ b/src/common/logging.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -35,13 +35,13 @@ static struct log_info_cat bts_log_info_cat[] = {
.name = "DRSL",
.description = "A-bis Radio Siganlling Link (RSL)",
.color = "\033[1;35m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DOML] = {
.name = "DOML",
.description = "A-bis Network Management / O&M (NM/OML)",
.color = "\033[1;36m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DRLL] = {
.name = "DRLL",
@@ -64,34 +64,23 @@ static struct log_info_cat bts_log_info_cat[] = {
.name = "DPAG",
.description = "Paging Subsystem",
.color = "\033[1;38m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DL1C] = {
.name = "DL1C",
.description = "Layer 1 Control (MPH)",
- .loglevel = LOGL_INFO,
+ .loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DL1P] = {
.name = "DL1P",
.description = "Layer 1 Primitives (PH)",
- .loglevel = LOGL_INFO,
+ .loglevel = LOGL_NOTICE,
.enabled = 0,
},
[DDSP] = {
.name = "DDSP",
.description = "DSP Trace Messages",
- .loglevel = LOGL_DEBUG,
- .enabled = 1,
- },
- [DABIS] = {
- .name = "DABIS",
- .description = "A-bis Intput Subsystem",
- .enabled = 1, .loglevel = LOGL_NOTICE,
- },
- [DRTP] = {
- .name = "DRTP",
- .description = "Realtime Transfer Protocol",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
@@ -116,35 +105,50 @@ static struct log_info_cat bts_log_info_cat[] = {
[DLOOP] = {
.name = "DLOOP",
.description = "Control loops",
- .color = "\033[0;34m",
+ .color = "\033[0;94m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
-#if 0
- [DNS] = {
- .name = "DNS",
- .description = "GPRS Network Service (NS)",
- .enabled = 1, .loglevel = LOGL_INFO,
- },
- [DBSSGP] = {
- .name = "DBSSGP",
- .description = "GPRS BSS Gateway Protocol (BSSGP)",
- .enabled = 1, .loglevel = LOGL_DEBUG,
- },
- [DLLC] = {
- .name = "DLLC",
- .description = "GPRS Logical Link Control Protocol (LLC)",
- .enabled = 1, .loglevel = LOGL_DEBUG,
- },
-#endif
- [DSUM] = {
- .name = "DSUM",
- .description = "DSUM",
+ [DABIS] = {
+ .name = "DABIS",
+ .description = "A-bis Intput Subsystem",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DRTP] = {
+ .name = "DRTP",
+ .description = "Realtime Transfer Protocol",
+ .loglevel = LOGL_NOTICE,
+ .enabled = 1,
+ },
+ [DOSMUX] = {
+ .name = "DOSMUX",
+ .description = "Osmux (Osmocom RTP multiplexing)",
+ .loglevel = LOGL_NOTICE,
+ .enabled = 1,
+ },
+ [DASCI] = {
+ .name = "DASCI",
+ .description = "ASCI (Advanced Speech Call Items: VGCS/VBS)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
+
};
+static int osmo_bts_filter_fn(const struct log_context *ctx, struct log_target *tgt)
+{
+ uint8_t *sapi = ctx->ctx[LOG_CTX_L1_SAPI];
+ uint16_t *sapi_mask = tgt->filter_data[LOG_FLT_L1_SAPI];
+
+ if ((tgt->filter_map & (1 << LOG_FLT_L1_SAPI)) != 0
+ && sapi_mask && sapi
+ && (*sapi_mask & (1 << *sapi)) != 0)
+ return 1;
+
+ return 0;
+}
+
const struct log_info bts_log_info = {
+ .filter_fn = osmo_bts_filter_fn,
.cat = bts_log_info_cat,
.num_cat = ARRAY_SIZE(bts_log_info_cat),
};
diff --git a/src/common/main.c b/src/common/main.c
index 6d8088ca..e57885a6 100644
--- a/src/common/main.c
+++ b/src/common/main.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -38,6 +38,9 @@
#include <osmocom/core/application.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
+#include <osmocom/vty/stats.h>
+#include <osmocom/vty/misc.h>
+#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/gsmtap.h>
@@ -46,6 +49,7 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/vty.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/bts_model.h>
@@ -56,30 +60,62 @@
#include <osmocom/ctrl/control_vty.h>
#include <osmo-bts/oml.h>
-int quit = 0;
+static int quit = 0;
static const char *config_file = "osmo-bts.cfg";
static int daemonize = 0;
static int rt_prio = -1;
static char *gsmtap_ip = 0;
extern int g_vty_port_num;
+static bool vty_test_mode = false;
static void print_help()
{
printf( "Some useful options:\n"
- " -h --help this text\n"
- " -d --debug MASK Enable debugging (e.g. -d DRSL:DOML:DLAPDM)\n"
- " -D --daemonize For the process into a background daemon\n"
- " -c --config-file Specify the filename of the config file\n"
- " -s --disable-color Don't use colors in stderr log output\n"
- " -T --timestamp Prefix every log line with a timestamp\n"
- " -V --version Print version information and exit\n"
- " -e --log-level Set a global log-level\n"
- " -r --realtime PRIO Use SCHED_RR with the specified priority\n"
- " -i --gsmtap-ip The destination IP used for GSMTAP.\n"
+ " -h --help this text\n"
+ " -d --debug MASK Enable debugging (e.g. -d DRSL:DOML:DLAPDM)\n"
+ " -D --daemonize For the process into a background daemon\n"
+ " -c --config-file Specify the filename of the config file\n"
+ " -s --disable-color Don't use colors in stderr log output\n"
+ " -T --timestamp Prefix every log line with a timestamp\n"
+ " -V --version Print version information and exit\n"
+ " -e --log-level Set a global log-level\n"
+ "\nVTY reference generation:\n"
+ " --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
+ " --vty-ref-xml Generate the VTY reference XML output and exit.\n"
+ "\nRegression testing:\n"
+ " --vty-test VTY test mode. Do not connect to BSC, do not exit.\n"
);
bts_model_print_help();
}
+static void handle_long_options(const char *prog_name, const int long_option)
+{
+ static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
+
+ switch (long_option) {
+ case 1:
+ vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
+ if (vty_ref_mode < 0) {
+ fprintf(stderr, "%s: Unknown VTY reference generation "
+ "mode '%s'\n", prog_name, optarg);
+ exit(2);
+ }
+ break;
+ case 2:
+ fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
+ get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
+ get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
+ vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
+ exit(0);
+ case 3:
+ vty_test_mode = true;
+ break;
+ default:
+ fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
+ exit(2);
+ }
+}
+
/* FIXME: finally get some option parsing code into libosmocore */
static void handle_options(int argc, char **argv)
{
@@ -94,6 +130,7 @@ static void handle_options(int argc, char **argv)
while (1) {
int option_idx = 0, c;
+ static int long_option = 0;
static const struct option long_options[] = {
/* FIXME: all those are generic Osmocom app options */
{ "help", 0, 0, 'h' },
@@ -108,6 +145,9 @@ static void handle_options(int argc, char **argv)
{ "gsmtap-ip", 1, 0, 'i' },
{ "trx-num", 1, 0, 't' },
{ "realtime", 1, 0, 'r' },
+ { "vty-ref-mode", 1, &long_option, 1 },
+ { "vty-ref-xml", 0, &long_option, 2 },
+ { "vty-test", 0, &long_option, 3 },
{ 0, 0, 0, 0 }
};
@@ -121,6 +161,9 @@ static void handle_options(int argc, char **argv)
print_help();
exit(0);
break;
+ case 0:
+ handle_long_options(argv[0], long_option);
+ break;
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
@@ -145,13 +188,17 @@ static void handle_options(int argc, char **argv)
break;
case 'r':
rt_prio = atoi(optarg);
+ fprintf(stderr, "Command line argument '-r' is deprecated, use VTY "
+ "cpu-sched node setting 'policy rr %d' instead.\n", rt_prio);
break;
case 'i':
gsmtap_ip = optarg;
+ fprintf(stderr, "Command line argument '-i' is deprecated, use VTY "
+ "parameter 'gsmtap-remote-host %s' instead.\n", gsmtap_ip);
break;
case 't':
- fprintf(stderr, "Parameter -t is deprecated and does nothing, "
- "TRX num is calculated from VTY\n");
+ fprintf(stderr, "Command line argument '-t' is deprecated and does nothing, "
+ "TRX number is calculated from the VTY automatically.\n");
break;
case '?':
case 1:
@@ -173,24 +220,35 @@ static void handle_options(int argc, char **argv)
}
}
-static struct gsm_bts *bts;
+/* FIXME: remove this once we add multi-BTS support */
+struct gsm_bts *g_bts = NULL;
-static void signal_handler(int signal)
+static void signal_handler(int signum)
{
- fprintf(stderr, "signal %u received\n", signal);
+ fprintf(stderr, "signal %u received\n", signum);
- switch (signal) {
+ switch (signum) {
case SIGINT:
case SIGTERM:
if (!quit) {
- oml_tx_failure_event_rep(&bts->mo,
+ oml_tx_failure_event_rep(&g_bts->mo,
NM_SEVER_CRITICAL, OSMO_EVT_CRIT_PROC_STOP,
"BTS: SIGINT received -> shutdown");
- bts_shutdown(bts, "SIGINT");
+ bts_shutdown_ext(g_bts, "SIGINT", true, false);
}
quit++;
break;
case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report and
+ * then run default SIGABRT handler, who will generate coredump
+ * and abort the process. abort() should do this for us after we
+ * return, but program wouldn't exit if an external SIGABRT is
+ * received.
+ */
+ talloc_report_full(tall_bts_ctx, stderr);
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ break;
case SIGUSR1:
case SIGUSR2:
talloc_report_full(tall_bts_ctx, stderr);
@@ -200,33 +258,11 @@ static void signal_handler(int signal)
}
}
-static int write_pid_file(char *procname)
-{
- FILE *outf;
- char tmp[PATH_MAX+1];
-
- snprintf(tmp, sizeof(tmp)-1, "/var/run/%s.pid", procname);
- tmp[PATH_MAX-1] = '\0';
-
- outf = fopen(tmp, "w");
- if (!outf)
- return -1;
-
- fprintf(outf, "%d\n", getpid());
-
- fclose(outf);
-
- return 0;
-}
-
int bts_main(int argc, char **argv)
{
struct gsm_bts_trx *trx;
- struct e1inp_line *line;
int rc;
- printf("((*))\n |\n / \\ OsmoBTS\n");
-
/* Track the use of talloc NULL memory contexts */
talloc_enable_null_tracking();
@@ -238,18 +274,36 @@ int bts_main(int argc, char **argv)
osmo_stats_init(tall_bts_ctx);
vty_init(&bts_vty_info);
ctrl_vty_init(tall_bts_ctx);
+ osmo_cpu_sched_vty_init(tall_bts_ctx);
rate_ctr_init(tall_bts_ctx);
+ logging_vty_add_cmds();
+ osmo_talloc_vty_add_cmds();
+ osmo_stats_vty_add_cmds();
+ osmo_fsm_vty_add_cmds();
+
+ bts_vty_init(tall_bts_ctx);
+ e1inp_vty_init();
+
+ logging_vty_add_deprecated_subsys(tall_bts_ctx, "sum");
+
handle_options(argc, argv);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
- if (!bts) {
- fprintf(stderr, "Failed to create BTS structure\n");
+ fprintf(stderr, "((*))\n |\n / \\ OsmoBTS\n");
+ if (vty_test_mode)
+ fprintf(stderr, "--- VTY test mode: not connecting to BSC, not exiting ---\n");
+
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm) {
+ fprintf(stderr, "Failed to create BTS Site Manager structure\n");
exit(1);
}
- e1inp_vty_init();
- bts_vty_init(bts);
+ g_bts = gsm_bts_alloc(g_bts_sm, 0);
+ if (!g_bts) {
+ fprintf(stderr, "Failed to create BTS structure\n");
+ exit(1);
+ }
/* enable realtime priority for us */
if (rt_prio != -1) {
@@ -265,21 +319,12 @@ int bts_main(int argc, char **argv)
}
}
- if (gsmtap_ip) {
- gsmtap = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 1);
- if (!gsmtap) {
- fprintf(stderr, "Failed during gsmtap_init()\n");
- exit(1);
- }
- gsmtap_source_add_sink(gsmtap);
- }
-
- if (bts_init(bts) < 0) {
+ if (bts_init(g_bts) < 0) {
fprintf(stderr, "unable to open bts\n");
exit(1);
}
- abis_init(bts);
+ abis_init(g_bts);
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
@@ -293,48 +338,78 @@ int bts_main(int argc, char **argv)
exit(1);
}
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (!trx->role_bts.l1h) {
+ llist_for_each_entry(trx, &g_bts->trx_list, list) {
+ if (!trx->pinst) {
fprintf(stderr, "TRX %u has no associated PHY instance\n",
trx->nr);
exit(1);
}
}
- write_pid_file("osmo-bts");
+ /* Accept a GSMTAP host from VTY config, but a commandline option overrides that. */
+ if (gsmtap_ip != NULL) {
+ if (g_bts->gsmtap.remote_host != NULL) {
+ LOGP(DLGLOBAL, LOGL_NOTICE,
+ "Command line argument '-i %s' overrides "
+ "'gsmtap-remote-host %s' from the config file\n",
+ gsmtap_ip, g_bts->gsmtap.remote_host);
+ talloc_free(g_bts->gsmtap.remote_host);
+ }
+ g_bts->gsmtap.remote_host = talloc_strdup(g_bts, gsmtap_ip);
+ }
- bts_controlif_setup(bts, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_BTS);
+ /* TODO: move this to gsm_bts_alloc() */
+ if (g_bts->gsmtap.remote_host != NULL) {
+ LOGP(DLGLOBAL, LOGL_NOTICE,
+ "Setting up GSMTAP Um forwarding '%s->'%s:%u'\n",
+ g_bts->gsmtap.local_host, g_bts->gsmtap.remote_host, GSMTAP_UDP_PORT);
+ g_bts->gsmtap.inst = gsmtap_source_init2(g_bts->gsmtap.local_host, 0,
+ g_bts->gsmtap.remote_host, GSMTAP_UDP_PORT, 1);
+ if (g_bts->gsmtap.inst == NULL) {
+ fprintf(stderr, "Failed during gsmtap_source_init2()\n");
+ exit(1);
+ }
+ gsmtap_source_add_sink(g_bts->gsmtap.inst);
+ }
- rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(),
- g_vty_port_num);
+ bts_controlif_setup(g_bts, OSMO_CTRL_PORT_BTS);
+
+ rc = telnet_init_default(tall_bts_ctx, NULL, g_vty_port_num);
if (rc < 0) {
fprintf(stderr, "Error initializing telnet\n");
exit(1);
}
- if (pcu_sock_init(bts->pcu.sock_path)) {
+ if (pcu_sock_init(g_bts->pcu.sock_path, g_bts->pcu.sock_wqueue_len_max)) {
fprintf(stderr, "PCU L1 socket failed\n");
exit(1);
}
signal(SIGINT, &signal_handler);
signal(SIGTERM, &signal_handler);
- //signal(SIGABRT, &signal_handler);
+ signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
osmo_init_ignore_signals();
- if (!bts->bsc_oml_host) {
- fprintf(stderr, "Cannot start BTS without knowing BSC OML IP\n");
+ if (bts_osmux_open(g_bts) < 0) {
+ fprintf(stderr, "Osmux setup failed\n");
exit(1);
}
- line = abis_open(bts, bts->bsc_oml_host, "sysmoBTS");
- if (!line) {
- fprintf(stderr, "unable to connect to BSC\n");
- exit(2);
+ if (vty_test_mode) {
+ /* Just select-loop without connecting to the BSC, don't exit. This allows running tests on the VTY
+ * telnet port. */
+ while (!quit) {
+ log_reset_context();
+ osmo_select_main(0);
+ }
+ return EXIT_SUCCESS;
}
+ if (abis_open(g_bts, "osmo-bts") != 0)
+ exit(1);
+
rc = phy_links_open();
if (rc < 0) {
fprintf(stderr, "unable to open PHY link(s)\n");
diff --git a/src/common/measurement.c b/src/common/measurement.c
index c2001dae..19bff714 100644
--- a/src/common/measurement.c
+++ b/src/common/measurement.c
@@ -2,19 +2,40 @@
#include <stdint.h>
#include <errno.h>
-#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/endian.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_44_004.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/measurement.h>
#include <osmo-bts/scheduler.h>
#include <osmo-bts/rsl.h>
+#include <osmo-bts/power_control.h>
+#include <osmo-bts/ta_control.h>
+
+/* Active TDMA frame subset for TCH/H in DTX mode (see 3GPP TS 45.008 Section 8.3).
+ * This mapping is used to determine if a L2 block starting at the given TDMA FN
+ * belongs to the SUB set and thus shall always be transmitted in DTX mode. */
+static const uint8_t ts45008_dtx_tchh_speech_fn_map[104] = {
+ /* TCH/H(0): 0, 2, 4, 6, 52, 54, 56, 58 */
+ [0] = 1, /* block { 0, 2, 4, 6} */
+ [52] = 1, /* block {52, 54, 56, 58} */
+ /* TCH/H(1): 14, 16, 18, 20, 66, 68, 70, 72 */
+ [14] = 1, /* block {14, 16, 18, 20} */
+ [66] = 1, /* block {66, 68, 70, 72} */
+};
-/* Tables as per TS 45.008 Section 8.3 */
-static const uint8_t ts45008_83_tch_f[] = { 52, 53, 54, 55, 56, 57, 58, 59 };
-static const uint8_t ts45008_83_tch_hs0[] = { 0, 2, 4, 6, 52, 54, 56, 58 };
-static const uint8_t ts45008_83_tch_hs1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
+static const uint8_t ts45008_dtx_tchh_data_fn_map[104] = {
+ /* UL TCH/H(0): 52, 54, 56, 58, 60, 62, 65, 67, 69, 71 */
+ [52] = 1, /* block {52, 54, 56, 58, 60, 62} */
+ [60] = 1, /* block {60, 62, 65, 67, 69, 71} */
+ /* UL TCH/H(1): 70, 72, 74, 76, 79, 81, 83, 85, 87, 89 */
+ [70] = 1, /* block {70, 72, 74, 76, 79, 81} */
+ [79] = 1, /* block {79, 81, 83, 85, 87, 89} */
+};
/* In cases where we less measurements than we expect we must assume that we
* just did not receive the block because it was lost due to bad channel
@@ -23,88 +44,74 @@ static const uint8_t ts45008_83_tch_hs1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
* the missing measurements */
#define MEASUREMENT_DUMMY_BER 10000 /* 100% BER */
#define MEASUREMENT_DUMMY_IRSSI 109 /* noise floor in -dBm */
-static const struct bts_ul_meas measurement_dummy = (struct bts_ul_meas) {
+static const struct bts_ul_meas measurement_dummy = {
.ber10k = MEASUREMENT_DUMMY_BER,
.ta_offs_256bits = 0,
- .c_i = 0,
+ .ci_cb = 0,
.is_sub = 0,
.inv_rssi = MEASUREMENT_DUMMY_IRSSI
};
-/* find out if an array contains a given key as element */
-#define ARRAY_CONTAINS(arr, val) array_contains(arr, ARRAY_SIZE(arr), val)
-static bool array_contains(const uint8_t *arr, unsigned int len, uint8_t val) {
- int i;
- for (i = 0; i < len; i++) {
- if (arr[i] == val)
- return true;
- }
- return false;
-}
-
/* Decide if a given frame number is part of the "-SUB" measurements (true) or not (false)
* (this function is only used internally, it is public to call it from unit-tests) */
-bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn, bool is_amr_sid_update)
+bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn)
{
uint32_t fn104 = fn % 104;
/* See TS 45.008 Sections 8.3 and 8.4 for a detailed descriptions of the rules
- * implemented here. We only implement the logic for Voice, not CSD */
+ * implemented here. We implement the logic for both speech and data (CSD). */
+
+ /* AMR is special, SID frames may be scheduled dynamically at any time */
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
+ return false;
switch (lchan->type) {
case GSM_LCHAN_TCH_F:
switch (lchan->tch_mode) {
- case GSM48_CMODE_SIGN:
+ case GSM48_CMODE_SIGN: /* TCH/F sign: DTX *is* permitted */
case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_V1_VAMOS:
case GSM48_CMODE_SPEECH_EFR:
- if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
- return true;
- if (ARRAY_CONTAINS(ts45008_83_tch_f, fn104))
- return true;
- break;
- case GSM48_CMODE_SPEECH_AMR:
- if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
- return true;
- if (is_amr_sid_update)
+ case GSM48_CMODE_SPEECH_V2_VAMOS:
+ /* Active TDMA frame subset for TCH/F: 52, 53, 54, 55, 56, 57, 58, 59.
+ * There is only one *complete* block in this subset starting at FN=52.
+ * Incomplete blocks {... 52, 53, 54, 55} and {56, 57, 58, 59 ...}
+ * contain only 50% of the useful bits (partial SID) and thus ~50% BER. */
+ if (fn104 == 52)
return true;
break;
+ case GSM48_CMODE_DATA_12k0: /* TCH/F9.6 */
+ case GSM48_CMODE_DATA_6k0: /* TCH/F4.8 */
+ /* FIXME: The RXQUAL_SUB (not RXLEV!) report shall include measurements on
+ * the TDMA frames given in the table of subclause 8.3 only if L2 fill frames
+ * have been received as FACCH/F frames at the corresponding frame positions. */
default:
- LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
- gsm_lchan_name(lchan), lchan->tch_mode);
+ if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
+ return fn104 == 52;
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_ERROR, "Unsupported lchan->tch_mode %u\n", lchan->tch_mode);
break;
}
break;
case GSM_LCHAN_TCH_H:
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_V1:
- if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
- return true;
- switch (lchan->nr) {
- case 0:
- if (ARRAY_CONTAINS(ts45008_83_tch_hs0, fn104))
- return true;
- break;
- case 1:
- if (ARRAY_CONTAINS(ts45008_83_tch_hs1, fn104))
- return true;
- break;
- default:
- OSMO_ASSERT(0);
- }
- break;
- case GSM48_CMODE_SPEECH_AMR:
- if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
- return true;
- if (is_amr_sid_update)
+ case GSM48_CMODE_SPEECH_V1_VAMOS:
+ if (ts45008_dtx_tchh_speech_fn_map[fn104])
return true;
break;
case GSM48_CMODE_SIGN:
/* No DTX allowed; SUB=FULL, therefore measurements at all frame numbers are
* SUB */
return true;
+ case GSM48_CMODE_DATA_6k0: /* TCH/H4.8 */
+ case GSM48_CMODE_DATA_3k6: /* TCH/H2.4 */
+ /* FIXME: The RXQUAL_SUB (not RXLEV!) report shall include measurements on
+ * the TDMA frames given in the table of subclause 8.3 only if L2 fill frames
+ * have been received as FACCH/H frames at the corresponding frame positions. */
default:
- LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
- gsm_lchan_name(lchan), lchan->tch_mode);
+ if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
+ return ts45008_dtx_tchh_data_fn_map[fn104] == 1;
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_ERROR, "Unsupported lchan->tch_mode %u\n", lchan->tch_mode);
break;
}
break;
@@ -250,11 +257,6 @@ int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn)
int rc = 0;
enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
- if (lchan->ts->nr >= 8)
- return -EINVAL;
- if (pchan >= _GSM_PCHAN_MAX)
- return -EINVAL;
-
switch (pchan) {
case GSM_PCHAN_TCH_F:
fn_mod = translate_tch_meas_rep_fn104(fn % 104);
@@ -288,9 +290,8 @@ int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn)
}
if (rc == 1) {
- DEBUGP(DMEAS,
- "%s meas period end fn:%u, fn_mod:%i, status:%d, pchan:%s\n",
- gsm_lchan_name(lchan), fn, fn_mod, rc, gsm_pchan_name(pchan));
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_DEBUG, "meas period end fn_mod:%d, status:%d, pchan:%s\n", fn_mod,
+ rc, gsm_pchan_name(pchan));
}
return rc;
@@ -305,50 +306,51 @@ static uint8_t modulus_by_lchan(struct gsm_lchan *lchan)
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
return 104;
- break;
case GSM_PCHAN_SDCCH8_SACCH8C:
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
case GSM_PCHAN_CCCH_SDCCH4:
case GSM_PCHAN_CCCH_SDCCH4_CBCH:
return 102;
- break;
default:
/* Invalid */
return 1;
- break;
}
}
/* receive a L1 uplink measurement from L1 (this function is only used
* internally, it is public to call it from unit-tests) */
-int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn)
+int lchan_new_ul_meas(struct gsm_lchan *lchan,
+ const struct bts_ul_meas *ulm,
+ uint32_t fn)
{
uint32_t fn_mod = fn % modulus_by_lchan(lchan);
+ struct bts_ul_meas *dest;
if (lchan->state != LCHAN_S_ACTIVE) {
- LOGPFN(DMEAS, LOGL_NOTICE, fn,
- "%s measurement during state: %s, num_ul_meas=%d, fn_mod=%u\n",
- gsm_lchan_name(lchan), gsm_lchans_name(lchan->state),
- lchan->meas.num_ul_meas, fn_mod);
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_NOTICE,
+ "measurement during state: %s, num_ul_meas=%d, fn_mod=%u\n",
+ gsm_lchans_name(lchan->state), lchan->meas.num_ul_meas, fn_mod);
}
if (lchan->meas.num_ul_meas >= ARRAY_SIZE(lchan->meas.uplink)) {
- LOGPFN(DMEAS, LOGL_NOTICE, fn,
- "%s no space for uplink measurement, num_ul_meas=%d, fn_mod=%u\n",
- gsm_lchan_name(lchan), lchan->meas.num_ul_meas, fn_mod);
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_NOTICE,
+ "no space for uplink measurement, num_ul_meas=%d, fn_mod=%u\n", lchan->meas.num_ul_meas,
+ fn_mod);
return -ENOSPC;
}
+ dest = &lchan->meas.uplink[lchan->meas.num_ul_meas++];
+ memcpy(dest, ulm, sizeof(*ulm));
+
/* We expect the lower layers to mark AMR SID_UPDATE frames already as such.
- * In this function, we only deal with the comon logic as per the TS 45.008 tables */
+ * In this function, we only deal with the common logic as per the TS 45.008 tables */
if (!ulm->is_sub)
- ulm->is_sub = ts45008_83_is_sub(lchan, fn, false);
+ dest->is_sub = ts45008_83_is_sub(lchan, fn);
- DEBUGPFN(DMEAS, fn, "%s adding measurement (is_sub=%u), num_ul_meas=%d, fn_mod=%u\n",
- gsm_lchan_name(lchan), ulm->is_sub, lchan->meas.num_ul_meas, fn_mod);
-
- memcpy(&lchan->meas.uplink[lchan->meas.num_ul_meas++], ulm,
- sizeof(*ulm));
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_DEBUG,
+ "adding a %s measurement (ber10k=%u, ta_offs=%d, ci_cB=%d, rssi=-%u), num_ul_meas=%d, fn_mod=%u\n",
+ dest->is_sub ? "SUB" : "FULL", ulm->ber10k, ulm->ta_offs_256bits, ulm->ci_cb, ulm->inv_rssi,
+ lchan->meas.num_ul_meas, fn_mod);
lchan->meas.last_fn = fn;
@@ -398,11 +400,16 @@ static unsigned int lchan_meas_num_expected(const struct gsm_lchan *lchan)
switch (pchan) {
case GSM_PCHAN_TCH_F:
- /* 24 for TCH + 1 for SACCH */
+ /* 24 blocks for TCH + 1 for SACCH */
return 25;
case GSM_PCHAN_TCH_H:
- /* 24 half-blocks for TCH + 1 for SACCH */
- return 25;
+ if (lchan->tch_mode == GSM48_CMODE_SIGN) {
+ /* 12 blocks for TCH + 1 for SACCH */
+ return 13;
+ } else {
+ /* 24 blocks for TCH + 1 for SACCH */
+ return 25;
+ }
case GSM_PCHAN_SDCCH8_SACCH8C:
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
/* 2 for SDCCH + 1 for SACCH */
@@ -417,23 +424,51 @@ static unsigned int lchan_meas_num_expected(const struct gsm_lchan *lchan)
}
/* In DTX a subset of blocks must always be transmitted
- * See also: GSM 05.08, chapter 8.3 Aspects of discontinuous transmission (DTX) */
-static unsigned int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
+ * See also: GSM 05.08, chapter 8.3 Aspects of discontinuous transmission (DTX)
+ * Return value N: (N < 0) -- at least N SUB frames expected;
+ * (N > 0) -- exactly N SUB frames expected;
+ * (N == 0) - unknown channel type/mode? */
+static int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
{
enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
- /* AMR is using a more elaborated model with a dymanic amount of
- * DTX blocks so this function is not applicable to determine the
- * amount of expected SUB Measurements when AMR is used */
- OSMO_ASSERT(lchan->tch_mode != GSM48_CMODE_SPEECH_AMR)
-
switch (pchan) {
case GSM_PCHAN_TCH_F:
- /* 1 block SDCCH, 2 blocks TCH */
- return 3;
+ if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
+ return 1 + 1; /* 1 x SACCH + 1 x FACCH */
+ /* else: signalling or speech */
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SIGN: /* TCH/F sign: DTX *is* permitted */
+ case GSM48_CMODE_SPEECH_V1: /* TCH/FS */
+ case GSM48_CMODE_SPEECH_V1_VAMOS:
+ case GSM48_CMODE_SPEECH_EFR: /* TCH/EFS */
+ case GSM48_CMODE_SPEECH_V2_VAMOS:
+ return 1 + 1; /* 1 x SACCH + 1 x TCH */
+ case GSM48_CMODE_SPEECH_AMR: /* TCH/AFS */
+ case GSM48_CMODE_SPEECH_V3_VAMOS:
+ case GSM48_CMODE_SPEECH_V4: /* O-TCH/WFS */
+ case GSM48_CMODE_SPEECH_V5: /* TCH/WFS */
+ case GSM48_CMODE_SPEECH_V5_VAMOS:
+ default:
+ return -1; /* at least 1 x SACCH + M x TCH (variable) */
+ }
case GSM_PCHAN_TCH_H:
- /* 1 block SDCCH, 4 half-blocks TCH */
- return 5;
+ if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
+ return 1 + 2; /* 1 x SACCH + 2 x FACCH */
+ /* else: signalling or speech */
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SIGN: /* TCH/H sign: DTX *is not* permitted */
+ return 1 + 12; /* 1 x SACCH + 12 x TCH */
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_V1_VAMOS:
+ return 1 + 2; /* 1 x SACCH + 2 x TCH */
+ case GSM48_CMODE_SPEECH_AMR: /* TCH/AHS */
+ case GSM48_CMODE_SPEECH_V3_VAMOS:
+ case GSM48_CMODE_SPEECH_V4: /* O-TCH/WHS */
+ case GSM48_CMODE_SPEECH_V6: /* O-TCH/AHS */
+ default:
+ return -1; /* at least 1 x SACCH + M x TCH (variable) */
+ }
case GSM_PCHAN_SDCCH8_SACCH8C:
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
/* no DTX here, all blocks must be present! */
@@ -471,7 +506,7 @@ static void lchan_meas_compute_extended(struct gsm_lchan *lchan)
/* each measurement is an int32_t, so the squared difference value must fit in 32bits */
/* the sum of the squared values (each up to 32bit) can very easily exceed 32 bits */
- u_int64_t sq_diff_sum = 0;
+ uint64_t sq_diff_sum = 0;
/* In case we do not have any measurement values collected there is no
* computation possible. We just skip the whole computation here, the
@@ -542,13 +577,15 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
struct gsm_meas_rep_unidir *mru;
uint32_t ber_full_sum = 0;
uint32_t irssi_full_sum = 0;
+ int32_t ci_full_sum = 0;
uint32_t ber_sub_sum = 0;
uint32_t irssi_sub_sum = 0;
+ int32_t ci_sub_sum = 0;
int32_t ta256b_sum = 0;
unsigned int num_meas_sub = 0;
unsigned int num_meas_sub_actual = 0;
unsigned int num_meas_sub_subst = 0;
- unsigned int num_meas_sub_expect;
+ int num_meas_sub_expect;
unsigned int num_ul_meas;
unsigned int num_ul_meas_actual = 0;
unsigned int num_ul_meas_subst = 0;
@@ -560,33 +597,25 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
if (!is_meas_complete(lchan, fn))
return 0;
- LOGP(DMEAS, LOGL_DEBUG, "%s Calculating measurement results for physical channel:%s\n",
- gsm_lchan_name(lchan), gsm_pchan_name(ts_pchan(lchan->ts)));
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG, "Calculating measurement results "
+ "for physical channel: %s\n", gsm_pchan_name(ts_pchan(lchan->ts)));
/* Note: Some phys will send no measurement indication at all
* when a block is lost. Also in DTX mode blocks are left out
* intentionally to save energy. It is not necessarly an error
* when we get less measurements as we expect. */
num_ul_meas_expect = lchan_meas_num_expected(lchan);
-
- if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR)
- num_meas_sub_expect = lchan_meas_sub_num_expected(lchan);
- else {
- /* FIXME: the amount of SUB Measurements is a dynamic parameter
- * in AMR and can not be determined by using a lookup table.
- * See also: OS#2978 */
- num_meas_sub_expect = 0;
- }
+ num_meas_sub_expect = lchan_meas_sub_num_expected(lchan);
if (lchan->meas.num_ul_meas > num_ul_meas_expect)
num_ul_meas_excess = lchan->meas.num_ul_meas - num_ul_meas_expect;
num_ul_meas = num_ul_meas_expect;
- LOGP(DMEAS, LOGL_DEBUG, "%s received %u UL measurements, expected %u\n", gsm_lchan_name(lchan),
- lchan->meas.num_ul_meas, num_ul_meas_expect);
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG, "Received %u UL measurements, expected %u\n",
+ lchan->meas.num_ul_meas, num_ul_meas_expect);
if (num_ul_meas_excess)
- LOGP(DMEAS, LOGL_DEBUG, "%s received %u excess UL measurements\n", gsm_lchan_name(lchan),
- num_ul_meas_excess);
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG, "Received %u excess UL measurements\n",
+ num_ul_meas_excess);
/* Measurement computation step 1: add up */
for (i = 0; i < num_ul_meas; i++) {
@@ -610,18 +639,24 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
m = &lchan->meas.uplink[i + num_ul_meas_excess];
if (m->is_sub) {
irssi_sub_sum += m->inv_rssi;
+ ci_sub_sum += m->ci_cb;
num_meas_sub_actual++;
is_sub = true;
}
irssi_full_sum += m->inv_rssi;
ta256b_sum += m->ta_offs_256bits;
+ ci_full_sum += m->ci_cb;
num_ul_meas_actual++;
} else {
m = &measurement_dummy;
- if (num_ul_meas_expect - i <= num_meas_sub_expect - num_meas_sub) {
- num_meas_sub_subst++;
- is_sub = true;
+
+ /* only if we know the exact number of SUB measurements */
+ if (num_meas_sub_expect >= 0) {
+ if (num_meas_sub < num_meas_sub_expect) {
+ num_meas_sub_subst++;
+ is_sub = true;
+ }
}
num_ul_meas_subst++;
@@ -634,50 +669,71 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
}
}
- LOGP(DMEAS, LOGL_DEBUG, "%s received UL measurements contain %u SUB measurements, expected %u\n",
- gsm_lchan_name(lchan), num_meas_sub_actual, num_meas_sub_expect);
- LOGP(DMEAS, LOGL_DEBUG, "%s replaced %u measurements with dummy values, from which %u were SUB measurements\n",
- gsm_lchan_name(lchan), num_ul_meas_subst, num_meas_sub_subst);
-
- if (num_meas_sub != num_meas_sub_expect) {
- LOGP(DMEAS, LOGL_ERROR, "%s Incorrect number of SUB measurements detected! (%u vs exp %u)\n",
- gsm_lchan_name(lchan), num_meas_sub, num_meas_sub_expect);
- /* Normally the logic above should make sure that there is
- * always the exact amount of SUB measurements taken into
- * account. If not then the logic that decides tags the received
- * measurements as is_sub works incorrectly. Since the logic
- * above only adds missing measurements during the calculation
- * it can not remove excess SUB measurements or add missing SUB
- * measurements when there is no more room in the interval. */
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG, "Replaced %u measurements with dummy values, "
+ "from which %u were SUB measurements\n", num_ul_meas_subst, num_meas_sub_subst);
+
+ /* Normally the logic above should make sure that there is
+ * always the exact amount of SUB measurements taken into
+ * account. If not then the logic that decides tags the received
+ * measurements as is_sub works incorrectly. Since the logic
+ * above only adds missing measurements during the calculation
+ * it can not remove excess SUB measurements or add missing SUB
+ * measurements when there is no more room in the interval. */
+ if (num_meas_sub_expect < 0) {
+ num_meas_sub_expect = -num_meas_sub_expect;
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
+ "Received UL measurements contain %u SUB measurements, expected at least %d\n",
+ num_meas_sub_actual, num_meas_sub_expect);
+ if (OSMO_UNLIKELY(num_meas_sub < num_meas_sub_expect)) {
+ LOGPLCHAN(lchan, DMEAS, LOGL_ERROR,
+ "Incorrect number of SUB measurements detected! "
+ "(%u vs exp >=%d)\n", num_meas_sub, num_meas_sub_expect);
+ }
+ } else {
+ LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
+ "Received UL measurements contain %u SUB measurements, expected %d\n",
+ num_meas_sub_actual, num_meas_sub_expect);
+ if (OSMO_UNLIKELY(num_meas_sub != num_meas_sub_expect)) {
+ LOGPLCHAN(lchan, DMEAS, LOGL_ERROR,
+ "Incorrect number of SUB measurements detected! "
+ "(%u vs exp %d)\n", num_meas_sub, num_meas_sub_expect);
+ }
}
/* Measurement computation step 2: divide */
ber_full_sum = ber_full_sum / num_ul_meas;
if (!irssi_full_sum)
- ber_full_sum = MEASUREMENT_DUMMY_IRSSI;
+ irssi_full_sum = MEASUREMENT_DUMMY_IRSSI;
else
irssi_full_sum = irssi_full_sum / num_ul_meas_actual;
- if (!num_ul_meas_actual)
+ if (!num_ul_meas_actual) {
ta256b_sum = lchan->meas.ms_toa256;
- else
- ta256b_sum = ta256b_sum / num_ul_meas_actual;
+ ci_full_sum = lchan->meas.ul_ci_cb_full;
+ } else {
+ ta256b_sum = ta256b_sum / (signed)num_ul_meas_actual;
+ ci_full_sum = ci_full_sum / (signed)num_ul_meas_actual;
+ }
if (!num_meas_sub)
ber_sub_sum = MEASUREMENT_DUMMY_BER;
else
ber_sub_sum = ber_sub_sum / num_meas_sub;
- if (!num_meas_sub_actual)
+ if (!num_meas_sub_actual) {
irssi_sub_sum = MEASUREMENT_DUMMY_IRSSI;
- else
+ ci_sub_sum = lchan->meas.ul_ci_cb_sub;
+ } else {
irssi_sub_sum = irssi_sub_sum / num_meas_sub_actual;
+ ci_sub_sum = ci_sub_sum / (signed)num_meas_sub_actual;
+ }
- LOGP(DMEAS, LOGL_INFO, "%s Computed TA256(% 4d) BER-FULL(%2u.%02u%%), RSSI-FULL(-%3udBm), "
- "BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm)\n", gsm_lchan_name(lchan),
- ta256b_sum, ber_full_sum / 100,
- ber_full_sum % 100, irssi_full_sum, ber_sub_sum / 100, ber_sub_sum % 100, irssi_sub_sum);
+ LOGPLCHAN(lchan, DMEAS, LOGL_INFO,
+ "Computed TA256(% 4d), BER-FULL(%2u.%02u%%), RSSI-FULL(-%3udBm), C/I-FULL(% 4d cB), "
+ "BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm), C/I-SUB(% 4d cB)\n",
+ ta256b_sum, ber_full_sum / 100, ber_full_sum % 100, irssi_full_sum, ci_full_sum,
+ ber_sub_sum / 100, ber_sub_sum % 100, irssi_sub_sum, ci_sub_sum);
/* store results */
mru = &lchan->meas.ul_res;
@@ -686,11 +742,15 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
mru->full.rx_qual = ber10k_to_rxqual(ber_full_sum);
mru->sub.rx_qual = ber10k_to_rxqual(ber_sub_sum);
lchan->meas.ms_toa256 = ta256b_sum;
+ lchan->meas.ul_ci_cb_full = ci_full_sum;
+ lchan->meas.ul_ci_cb_sub = ci_sub_sum;
- LOGP(DMEAS, LOGL_INFO, "%s UL MEAS RXLEV_FULL(%u), RXLEV_SUB(%u),"
- "RXQUAL_FULL(%u), RXQUAL_SUB(%u), num_meas_sub(%u), num_ul_meas(%u) \n",
- gsm_lchan_name(lchan),
- mru->full.rx_lev, mru->sub.rx_lev, mru->full.rx_qual, mru->sub.rx_qual, num_meas_sub, num_ul_meas_expect);
+ LOGPLCHAN(lchan, DMEAS, LOGL_INFO,
+ "UL MEAS RXLEV_FULL(%u), RXLEV_SUB(%u), RXQUAL_FULL(%u), RXQUAL_SUB(%u), "
+ "num_meas_sub(%u), num_ul_meas(%u)\n",
+ mru->full.rx_lev, mru->sub.rx_lev,
+ mru->full.rx_qual, mru->sub.rx_qual,
+ num_meas_sub, num_ul_meas_expect);
lchan->meas.flags |= LC_UL_M_F_RES_VALID;
@@ -698,7 +758,7 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
lchan->meas.num_ul_meas = 0;
- /* return 1 to indicte that the computation has been done and the next
+ /* return 1 to indicate that the computation has been done and the next
* interval begins. */
return 1;
}
@@ -707,7 +767,9 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
* l1sap.c every time a measurement indication is received. It collects the
* measurement samples and automatically detects the end of the measurement
* interval. */
-int lchan_meas_process_measurement(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn)
+int lchan_meas_process_measurement(struct gsm_lchan *lchan,
+ const struct bts_ul_meas *ulm,
+ uint32_t fn)
{
lchan_new_ul_meas(lchan, ulm, fn);
return lchan_meas_check_compute(lchan, fn);
@@ -721,3 +783,230 @@ void lchan_meas_reset(struct gsm_lchan *lchan)
memset(&lchan->meas, 0, sizeof(lchan->meas));
lchan->meas.last_fn = LCHAN_FN_DUMMY;
}
+
+static inline uint8_t ms_to2rsl(const struct gsm_lchan *lchan, uint8_t ta)
+{
+ return (lchan->ms_t_offs >= 0) ? lchan->ms_t_offs : (lchan->p_offs - ta);
+}
+
+static inline bool ms_to_valid(const struct gsm_lchan *lchan)
+{
+ return (lchan->ms_t_offs >= 0) || (lchan->p_offs >= 0);
+}
+
+/* Decide if repeated FACCH should be applied or not. If RXQUAL level, that the
+ * MS reports is high enough, FACCH repetition is not needed. */
+static void repeated_dl_facch_active_decision(struct gsm_lchan *lchan,
+ const struct gsm48_meas_res *meas_res)
+{
+ uint8_t upper;
+ uint8_t lower;
+ uint8_t rxqual;
+ bool prev_repeated_dl_facch_active = lchan->rep_acch.dl_facch_active;
+
+ /* This is an optimization so that we exit as quickly as possible if
+ * there are no FACCH repetition capabilities present. However If the
+ * repeated FACCH capabilities vanish for whatever reason, we must be
+ * sure that FACCH repetition is disabled. */
+ if (!lchan->rep_acch_cap.dl_facch_cmd
+ && !lchan->rep_acch_cap.dl_facch_all) {
+ lchan->rep_acch.dl_facch_active = false;
+ goto out;
+ }
+
+ /* Threshold disabled (always on) */
+ if (lchan->rep_acch_cap.rxqual == 0) {
+ lchan->rep_acch.dl_facch_active = true;
+ goto out;
+ }
+
+ /* When the MS sets the SRR bit in the UL-SACCH L1 header
+ * (repeated SACCH requested) then it makes sense to enable
+ * FACCH repetition too. */
+ if (lchan->meas.l1_info.srr_sro) {
+ lchan->rep_acch.dl_facch_active = true;
+ goto out;
+ }
+
+ /* Parse MS measurement results */
+ if (meas_res == NULL)
+ goto out;
+ if (!gsm48_meas_res_is_valid(meas_res))
+ goto out;
+
+ /* If the RXQUAL level at the MS drops under a certain threshold
+ * we enable FACCH repetition. */
+ upper = lchan->rep_acch_cap.rxqual;
+ if (upper > 2)
+ lower = lchan->rep_acch_cap.rxqual - 2;
+ else
+ lower = 0;
+
+ /* When downlink DTX is applied, use RXQUAL-SUB, otherwise use
+ * RXQUAL-FULL. */
+ if (meas_res->dtx_used)
+ rxqual = meas_res->rxqual_sub;
+ else
+ rxqual = meas_res->rxqual_full;
+
+ if (rxqual >= upper)
+ lchan->rep_acch.dl_facch_active = true;
+ else if (rxqual <= lower)
+ lchan->rep_acch.dl_facch_active = false;
+
+out:
+ if (lchan->rep_acch.dl_facch_active == prev_repeated_dl_facch_active)
+ return;
+ if (lchan->rep_acch.dl_facch_active)
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-FACCH repetition: inactive => active\n");
+ else
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-FACCH repetition: active => inactive\n");
+}
+
+static void acch_overpower_active_decision(struct gsm_lchan *lchan,
+ const struct gsm48_meas_res *meas_res)
+{
+ const bool old = lchan->top_acch_active;
+ uint8_t upper, lower, rxqual;
+
+ /* ACCH overpower is not allowed => nothing to do */
+ if (lchan->top_acch_cap.overpower_db == 0)
+ return;
+ /* RxQual threshold is disabled => overpower is always on */
+ if (lchan->top_acch_cap.rxqual == 0)
+ return;
+
+ /* If DTx is active on Downlink, use the '-SUB' */
+ if (meas_res->dtx_used)
+ rxqual = meas_res->rxqual_sub;
+ else /* ... otherwise use the '-FULL' */
+ rxqual = meas_res->rxqual_full;
+
+ upper = lchan->top_acch_cap.rxqual;
+ if (upper > 2)
+ lower = upper - 2;
+ else
+ lower = 0;
+
+ if (rxqual >= upper)
+ lchan->top_acch_active = true;
+ else if (rxqual <= lower)
+ lchan->top_acch_active = false;
+
+ if (lchan->top_acch_active != old) {
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "Temporary ACCH overpower: %s\n",
+ lchan->top_acch_active ? "inactive => active"
+ : "active => inactive");
+ }
+}
+
+static bool data_is_rr_meas_rep(const uint8_t *data)
+{
+ const struct gsm48_hdr *gh = (void *)(data + 5);
+ const uint8_t *lapdm_hdr = (void *)(data + 2);
+
+ /* LAPDm address field: SAPI=0, C/R=0, EA=1 */
+ if (lapdm_hdr[0] != 0x01)
+ return false;
+ /* LAPDm control field: U, func=UI */
+ if (lapdm_hdr[1] != 0x03)
+ return false;
+ /* Protocol discriminator: RR */
+ if (gh->proto_discr != GSM48_PDISC_RR)
+ return false;
+
+ switch (gh->msg_type) {
+ case GSM48_MT_RR_EXT_MEAS_REP:
+ case GSM48_MT_RR_MEAS_REP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Called every time a SACCH block is received from lower layers */
+void lchan_meas_handle_sacch(struct gsm_lchan *lchan, struct msgb *msg)
+{
+ const struct gsm48_meas_res *mr = NULL;
+ const struct gsm48_hdr *gh = NULL;
+ int timing_offset, rc;
+ bool dtxu_used = true; /* safe default assumption */
+ uint8_t ms_pwr;
+ uint8_t ms_ta;
+ int8_t ul_rssi;
+ int16_t ul_ci_cb;
+ uint8_t *l3;
+ unsigned int l3_len;
+
+ if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
+ /* Some brilliant engineer decided that the ordering of
+ * fields on the Um interface is different from the
+ * order of fields in RSL. See 3GPP TS 44.004 (section 7.2)
+ * vs. 3GPP TS 48.058 (section 9.3.10). */
+ const struct gsm_sacch_l1_hdr *l1h = msgb_l2(msg);
+ lchan->meas.l1_info.ms_pwr = l1h->ms_pwr;
+ lchan->meas.l1_info.fpc_epc = l1h->fpc_epc;
+ lchan->meas.l1_info.srr_sro = l1h->srr_sro;
+ lchan->meas.l1_info.ta = l1h->ta;
+ lchan->meas.flags |= LC_UL_M_F_L1_VALID;
+
+ /* Check if this is a Measurement Report */
+ if (data_is_rr_meas_rep(msgb_l2(msg))) {
+ /* Skip both L1 SACCH and LAPDm headers */
+ msg->l3h = (void *)(msg->l2h + 2 + 3);
+ gh = msgb_l3(msg);
+ }
+
+ ms_pwr = lchan->meas.l1_info.ms_pwr;
+ ms_ta = lchan->meas.l1_info.ta;
+ } else {
+ lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;
+ ms_pwr = lchan->ms_power_ctrl.current;
+ ms_ta = lchan->ta_ctrl.current;
+ }
+
+ timing_offset = ms_to_valid(lchan) ? ms_to2rsl(lchan, ms_ta) : -1;
+ l3 = msgb_l3(msg);
+ l3_len = l3 ? msgb_l3len(msg) : 0;
+ rc = rsl_tx_meas_res(lchan, l3, l3_len, timing_offset);
+ if (rc == 0) /* Count successful transmissions */
+ lchan->meas.res_nr++;
+
+ /* Run control loops now that we have all the information: */
+ /* 3GPP TS 45.008 sec 4.2: UL L1 SACCH Header contains TA and
+ * MS_PWR used "for the last burst of the previous SACCH
+ * period". Since MS must use the values provided in DL SACCH
+ * starting at next meas period, the value of the "last burst"
+ * is actually the value used in the entire meas period. Since
+ * it contains info about the previous meas period, we want to
+ * feed the Control Loop with the measurements for the same
+ * period (the previous one), which is stored in lchan->meas(.ul_res):
+ */
+ if (gh && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
+ mr = (const struct gsm48_meas_res *)gh->data;
+ if (gsm48_meas_res_is_valid(mr))
+ dtxu_used = mr->dtx_used;
+ }
+
+ if (dtxu_used) {
+ ul_rssi = rxlev2dbm(lchan->meas.ul_res.sub.rx_lev);
+ ul_ci_cb = lchan->meas.ul_ci_cb_sub;
+ } else {
+ ul_rssi = rxlev2dbm(lchan->meas.ul_res.full.rx_lev);
+ ul_ci_cb = lchan->meas.ul_ci_cb_full;
+ }
+ lchan_ms_ta_ctrl(lchan, ms_ta, lchan->meas.ms_toa256);
+ lchan_ms_pwr_ctrl(lchan, ms_pwr, ul_rssi, ul_ci_cb);
+ if (mr && gsm48_meas_res_is_valid(mr)) {
+ lchan_bs_pwr_ctrl(lchan, mr);
+ acch_overpower_active_decision(lchan, mr);
+ }
+
+ repeated_dl_facch_active_decision(lchan, mr);
+
+ /* Reset state for next iteration */
+ lchan->tch.dtx.dl_active = false;
+ lchan->meas.flags &= ~LC_UL_M_F_OSMO_EXT_VALID;
+ lchan->ms_t_offs = -1;
+ lchan->p_offs = -1;
+}
diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c
index 52b05668..04a0c344 100644
--- a/src/common/msg_utils.c
+++ b/src/common/msg_utils.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -23,6 +23,7 @@
#include <osmo-bts/oml.h>
#include <osmo-bts/amr.h>
#include <osmo-bts/rsl.h>
+#include <osmo-bts/bts.h>
#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
@@ -320,17 +321,17 @@ static inline bool dtx_amr_sid_optional(struct gsm_lchan *lchan, uint32_t fn)
already: we rely here on the order of RTS arrival from L1 - we
expect that PH-DATA.req ALWAYS comes before PH-TCH.req for the
same FN */
- if(lchan->type == GSM_LCHAN_TCH_H) {
+ if (lchan->type == GSM_LCHAN_TCH_H) {
if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY &&
lchan->tch.dtx.fn != LCHAN_FN_WAIT) {
/* FACCH interruption is over */
dtx_dispatch(lchan, E_COMPL);
return false;
- } else if(lchan->tch.dtx.fn == LCHAN_FN_DUMMY) {
+ } else if (lchan->tch.dtx.fn == LCHAN_FN_DUMMY) {
lchan->tch.dtx.fn = LCHAN_FN_WAIT;
} else
lchan->tch.dtx.fn = fn;
- } else if(lchan->type == GSM_LCHAN_TCH_F) {
+ } else if (lchan->type == GSM_LCHAN_TCH_F) {
if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY) {
/* FACCH interruption is over */
dtx_dispatch(lchan, E_COMPL);
@@ -379,15 +380,19 @@ static inline bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn)
static const uint8_t f[] = { 52, 53, 54, 55, 56, 57, 58, 59 },
h0[] = { 0, 2, 4, 6, 52, 54, 56, 58 },
h1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1) {
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
if (lchan->type == GSM_LCHAN_TCH_F)
return fn_chk(f, fn, ARRAY_SIZE(f));
else
return fn_chk(lchan->nr ? h1 : h0, fn,
lchan->nr ? ARRAY_SIZE(h1) :
ARRAY_SIZE(h0));
+ case GSM48_CMODE_SPEECH_EFR:
+ return fn_chk(f, fn, ARRAY_SIZE(f));
+ default:
+ return false;
}
- return false;
}
/*! \brief Check if DTX DL AMR is enabled for a given lchan (it have proper type,
@@ -465,10 +470,6 @@ void dtx_int_signal(struct gsm_lchan *lchan)
*/
uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
{
- /* FIXME: add EFR support */
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_EFR)
- return 0;
-
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
if (dtx_sched_optional(lchan, fn))
return 0;
diff --git a/src/common/nm_bb_transc_fsm.c b/src/common/nm_bb_transc_fsm.c
new file mode 100644
index 00000000..b173102e
--- /dev/null
+++ b/src/common/nm_bb_transc_fsm.c
@@ -0,0 +1,325 @@
+/* NM Radio Carrier FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/phy_link.h>
+
+#define X(s) (1 << (s))
+
+#define nm_bb_transc_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+static void ev_dispatch_children(struct gsm_bts_bb_trx *bb_transc, uint32_t event)
+{
+ struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
+ uint8_t tn;
+
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ osmo_fsm_inst_dispatch(ts->mo.fi, event, NULL);
+ }
+}
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+ /* Reset state: */
+ TALLOC_FREE(bb_transc->mo.nm_attr);
+
+ bb_transc->mo.setattr_success = false;
+ bb_transc->mo.opstart_success = false;
+ oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SW_ACT:
+ oml_mo_tx_sw_act_rep(&bb_transc->mo);
+ nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);
+ ev_dispatch_children(bb_transc, event);
+ return;
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&bb_transc->mo);
+ ev_dispatch_children(bb_transc, event);
+ return;
+ case NM_EV_RSL_UP:
+ return;
+ case NM_EV_RSL_DOWN:
+ return;
+ case NM_EV_PHYLINK_UP:
+ return;
+ case NM_EV_PHYLINK_DOWN:
+ return;
+ case NM_EV_DISABLE:
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+ struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
+ int i;
+
+ bb_transc->mo.setattr_success = false;
+ bb_transc->mo.opstart_success = false;
+ oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+
+ if (prev_state == NM_BBTRANSC_ST_OP_ENABLED) {
+ for (i = 0; i < TRX_NR_TS; i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_BBTRANSC_DISABLED, NULL);
+ }
+ }
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+ struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
+ struct gsm_bts *bts = trx->bts;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ bool phy_state_connected;
+ bool rsl_link_connected;
+ int rc;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&bb_transc->mo);
+ ev_dispatch_children(bb_transc, event);
+ return;
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(trx->bts, setattr_data->msg,
+ &bb_transc->mo, bb_transc);
+ bb_transc->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ return;
+ case NM_EV_RX_OPSTART:
+#if 0
+ /* Disabled because osmo-bsc doesn't send SetAttr on BB_TRANSC object */
+ if (!bb_transc->mo.setattr_success) {
+ oml_mo_opstart_nack(&bb_transc->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+#endif
+ /* Connect RSL link: */
+ if (bts->variant == BTS_OSMO_OMLDUMMY) {
+ LOGPFSML(fi, LOGL_NOTICE, "Not connecting RSL in OML-DUMMY!\n");
+ } else {
+ rc = e1inp_ipa_bts_rsl_connect_n(bts->oml_link->ts->line,
+ bb_transc->rsl.rem_addrstr.ip,
+ bb_transc->rsl.rem_addrstr.port, trx->nr);
+ if (rc < 0) {
+ LOGPFSML(fi, LOGL_NOTICE, "Error connecting IPA RSL: %d\n", rc);
+ oml_mo_opstart_nack(&bb_transc->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ }
+ bts_model_opstart(trx->bts, &bb_transc->mo, bb_transc);
+ return;
+ case NM_EV_OPSTART_ACK:
+ bb_transc->mo.opstart_success = true;
+ oml_mo_opstart_ack(&bb_transc->mo);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ bb_transc->mo.opstart_success = false;
+ oml_mo_opstart_nack(&bb_transc->mo, (int)(intptr_t)data);
+ return;
+ case NM_EV_RSL_UP:
+ break; /* check statechg below */
+ case NM_EV_RSL_DOWN:
+ return;
+ case NM_EV_PHYLINK_UP:
+ break; /* check statechg below */
+ case NM_EV_PHYLINK_DOWN:
+ return;
+ case NM_EV_DISABLE:
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+
+ if (bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;
+ rsl_link_connected = !!trx->bb_transc.rsl.link;
+ } else {
+ phy_state_connected = true;
+ rsl_link_connected = true;
+ }
+
+ /* We so far don't expect any SetAttributes for this NM object */
+ if (rsl_link_connected && phy_state_connected &&
+ bb_transc->mo.opstart_success) {
+ nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_ENABLED);
+ } else {
+ LOGPFSML(fi, LOGL_INFO, "Delay switch to operative state Enabled, wait for:%s%s%s\n",
+ rsl_link_connected ? "" : " rsl",
+ phy_state_connected ? "" : " phy",
+ bb_transc->mo.opstart_success ? "" : " opstart");
+
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+ struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
+ uint8_t tn;
+
+ oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+ /* Mark Dependency TS as Offline (ready to be Opstarted) */
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_BBTRANSC_ENABLED, NULL);
+ }
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case NM_EV_RSL_DOWN:
+ break;
+ case NM_EV_PHYLINK_DOWN:
+ break;
+ case NM_EV_DISABLE:
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);
+}
+
+static void nm_bb_transc_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&bb_transc->mo, -1, -1, NM_STATE_SHUTDOWN);
+
+ /* Propagate event to children: */
+ ev_dispatch_children(bb_transc, event);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ /* Propagate event to children: */
+ ev_dispatch_children(bb_transc, event);
+ nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_bb_transc_fsm_states[] = {
+ [NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_SW_ACT) |
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RSL_UP) |
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_UP) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BBTRANSC_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_BBTRANSC_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK) |
+ X(NM_EV_RSL_UP) |
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_UP) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BBTRANSC_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_BBTRANSC_ST_OP_ENABLED] = {
+ .in_event_mask =
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BBTRANSC_ST_OP_DISABLED_OFFLINE),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_bb_transc_fsm = {
+ .name = "NM_BBTRANSC_OP",
+ .states = nm_bb_transc_fsm_states,
+ .num_states = ARRAY_SIZE(nm_bb_transc_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_bb_transc_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_bb_transc_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_bb_transc_fsm) == 0);
+}
diff --git a/src/common/nm_bts_fsm.c b/src/common/nm_bts_fsm.c
new file mode 100644
index 00000000..36aad733
--- /dev/null
+++ b/src/common/nm_bts_fsm.c
@@ -0,0 +1,230 @@
+/* NM BTS FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/phy_link.h>
+#include <osmo-bts/cbch.h>
+#include <osmo-bts/notification.h>
+
+#define X(s) (1 << (s))
+
+#define nm_bts_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+static void ev_dispatch_children(struct gsm_bts *bts, uint32_t event)
+{
+ struct gsm_bts_trx *trx;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ osmo_fsm_inst_dispatch(trx->mo.fi, event, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, event, NULL);
+ }
+}
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ /* Reset state: */
+ bts->si_valid = 0;
+ bts->bsic_configured = false;
+ bts->bsic = 0xff; /* invalid value */
+ TALLOC_FREE(bts->mo.nm_attr);
+ bts_cbch_reset(bts);
+ bts_asci_notification_reset(bts);
+ if (bts->c0_power_red_db > 0)
+ bts_set_c0_pwr_red(bts, 0);
+
+ bts->mo.setattr_success = false;
+ bts->mo.opstart_success = false;
+ oml_mo_state_chg(&bts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct gsm_bts_trx *trx;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* automatic SW_ACT upon OML link establishment: */
+ oml_mo_tx_sw_act_rep(&bts->mo);
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->bts->variant == BTS_OSMO_OMLDUMMY) /* In OMLDUMMY, phy=NULL */
+ continue;
+ /* During startup, phy_links are already opened, but if we are
+ * re-connecting, phy_link was closed when disconnected from
+ * previous BSC, so let's re-open it.
+ */
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct phy_link *plink = pinst->phy_link;
+ if (phy_link_state_get(plink) == PHY_LINK_SHUTDOWN)
+ bts_model_phy_link_open(plink);
+ }
+
+ nm_bts_fsm_state_chg(fi, NM_BTS_ST_OP_DISABLED_OFFLINE);
+ ev_dispatch_children(bts, event);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ bts->mo.setattr_success = false;
+ bts->mo.opstart_success = false;
+ oml_mo_state_chg(&bts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg, &bts->mo, bts);
+ bts->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!bts->mo.setattr_success) {
+ oml_mo_opstart_nack(&bts->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &bts->mo, bts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ bts->mo.opstart_success = true;
+ oml_mo_opstart_ack(&bts->mo);
+ nm_bts_fsm_state_chg(fi, NM_BTS_ST_OP_ENABLED);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ bts->mo.opstart_success = false;
+ oml_mo_opstart_nack(&bts->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+ oml_mo_state_chg(&bts->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+}
+
+static void nm_bts_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&bts->mo, -1, -1, NM_STATE_SHUTDOWN);
+
+ /* Propagate event to children: */
+ ev_dispatch_children(bts, event);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ /* Propagate event to children: */
+ ev_dispatch_children(bts, event);
+ nm_bts_fsm_state_chg(fi, NM_BTS_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_bts_fsm_states[] = {
+ [NM_BTS_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BTS_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_BTS_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK),
+ .out_state_mask =
+ X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BTS_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_BTS_ST_OP_ENABLED] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_bts_fsm = {
+ .name = "NM_BTS_OP",
+ .states = nm_bts_fsm_states,
+ .num_states = ARRAY_SIZE(nm_bts_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_bts_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_bts_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_bts_fsm) == 0);
+}
diff --git a/src/common/nm_bts_sm_fsm.c b/src/common/nm_bts_sm_fsm.c
new file mode 100644
index 00000000..9ac0edd9
--- /dev/null
+++ b/src/common/nm_bts_sm_fsm.c
@@ -0,0 +1,209 @@
+/* NM BTS Site Manager FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/phy_link.h>
+
+#define X(s) (1 << (s))
+
+#define nm_bts_sm_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+
+static void ev_dispatch_children(struct gsm_bts_sm *site_mgr, uint32_t event)
+{
+ struct gsm_bts *bts;
+ osmo_fsm_inst_dispatch(site_mgr->gprs.nse.mo.fi, event, NULL);
+ llist_for_each_entry(bts, &site_mgr->bts_list, list) {
+ osmo_fsm_inst_dispatch(bts->mo.fi, event, NULL);
+ }
+}
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+ site_mgr->mo.setattr_success = false;
+ site_mgr->mo.opstart_success = false;
+ oml_mo_state_chg(&site_mgr->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* automatic SW_ACT upon OML link establishment: */
+ oml_mo_tx_sw_act_rep(&site_mgr->mo);
+ nm_bts_sm_fsm_state_chg(fi, NM_BTS_SM_ST_OP_DISABLED_OFFLINE);
+ ev_dispatch_children(site_mgr, event);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+ site_mgr->mo.setattr_success = false;
+ site_mgr->mo.opstart_success = false;
+ oml_mo_state_chg(&site_mgr->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ /* No bts_model_apply_oml() needed yet for site_mgr obj yet: */
+ rc = 0;
+ site_mgr->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+#if 0
+ /* Disabled because osmo-bsc doesn't send SetAttr on SITE_MGR object */
+ if (!site_mgr->mo.setattr_success) {
+ oml_mo_opstart_nack(&site_mgr->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+#endif
+ bts_model_opstart(NULL, &site_mgr->mo, site_mgr);
+ break;
+ case NM_EV_OPSTART_ACK:
+ site_mgr->mo.opstart_success = true;
+ oml_mo_opstart_ack(&site_mgr->mo);
+ nm_bts_sm_fsm_state_chg(fi, NM_BTS_SM_ST_OP_ENABLED);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ site_mgr->mo.opstart_success = false;
+ oml_mo_opstart_nack(&site_mgr->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+ oml_mo_state_chg(&site_mgr->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+}
+
+static void nm_bts_sm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&site_mgr->mo, -1, -1, NM_STATE_SHUTDOWN);
+
+ /* Propagate event to children: */
+ ev_dispatch_children(site_mgr, event);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ /* Propagate event to children: */
+ ev_dispatch_children(site_mgr, event);
+ nm_bts_sm_fsm_state_chg(fi, NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_bts_sm_fsm_states[] = {
+ [NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BTS_SM_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_BTS_SM_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK),
+ .out_state_mask =
+ X(NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BTS_SM_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_BTS_SM_ST_OP_ENABLED] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_bts_sm_fsm = {
+ .name = "NM_BTS_SM_OP",
+ .states = nm_bts_sm_fsm_states,
+ .num_states = ARRAY_SIZE(nm_bts_sm_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_bts_sm_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_bts_sm_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_bts_sm_fsm) == 0);
+}
diff --git a/src/common/nm_channel_fsm.c b/src/common/nm_channel_fsm.c
new file mode 100644
index 00000000..d41fcd11
--- /dev/null
+++ b/src/common/nm_channel_fsm.c
@@ -0,0 +1,317 @@
+/* NM Radio Carrier FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+#define X(s) (1 << (s))
+
+#define nm_chan_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+/* Can the TS be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
+static bool ts_can_be_enabled(const struct gsm_bts_trx_ts *ts)
+{
+ return (ts->trx->bb_transc.mo.nm_state.operational == NM_OPSTATE_ENABLED &&
+ (!bts_internal_flag_get(ts->trx->bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER) ||
+ ts->trx->mo.nm_state.operational == NM_OPSTATE_ENABLED));
+}
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ /* Reset state: */
+ gsm_ts_release(ts);
+ if (ts->vamos.peer)
+ gsm_ts_release(ts->vamos.peer);
+ TALLOC_FREE(ts->mo.nm_attr);
+
+ ts->mo.setattr_success = false;
+ ts->mo.opstart_success = false;
+ oml_mo_state_chg(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&ts->mo);
+ return;
+ case NM_EV_SW_ACT:
+ oml_mo_tx_sw_act_rep(&ts->mo);
+ if (ts_can_be_enabled(ts))
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);
+ else
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ ts->mo.opstart_success = false;
+ oml_mo_state_chg(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
+}
+
+static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&ts->mo);
+ return;
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(ts->trx->bts, setattr_data->msg,
+ &ts->mo, ts);
+ ts->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ LOGPFSML(fi, LOGL_NOTICE, "BSC trying to activate TS while still in avail=dependency. "
+ "Allowing it to stay backward-compatible with older osmo-bts versions, but BSC is wrong.\n");
+ if (!ts->mo.setattr_success) {
+ oml_mo_opstart_nack(&ts->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(ts->trx->bts, &ts->mo, ts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ ts->mo.opstart_success = true;
+ oml_mo_opstart_ack(&ts->mo);
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
+ return;
+ case NM_EV_OPSTART_NACK:
+ ts->mo.opstart_success = false;
+ oml_mo_opstart_nack(&ts->mo, (int)(intptr_t)data);
+ return;
+ case NM_EV_BBTRANSC_ENABLED:
+ case NM_EV_RCARRIER_ENABLED:
+ if (ts_can_be_enabled(ts))
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);
+ return;
+ case NM_EV_BBTRANSC_DISABLED:
+ case NM_EV_RCARRIER_DISABLED:
+ /* do nothing, we are simply waiting for (potentially) both to be enabled */
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ ts->mo.opstart_success = false;
+ oml_mo_state_chg(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&ts->mo);
+ return;
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(ts->trx->bts, setattr_data->msg,
+ &ts->mo, ts);
+ ts->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!ts->mo.setattr_success) {
+ oml_mo_opstart_nack(&ts->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(ts->trx->bts, &ts->mo, ts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ ts->mo.opstart_success = true;
+ oml_mo_opstart_ack(&ts->mo);
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
+ return;
+ case NM_EV_OPSTART_NACK:
+ ts->mo.opstart_success = false;
+ oml_mo_opstart_nack(&ts->mo, (int)(intptr_t)data);
+ return;
+ case NM_EV_BBTRANSC_DISABLED:
+ case NM_EV_RCARRIER_DISABLED:
+ if (!ts_can_be_enabled(ts))
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+ oml_mo_state_chg(&ts->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+
+ switch (event) {
+ case NM_EV_BBTRANSC_DISABLED:
+ case NM_EV_RCARRIER_DISABLED:
+ if (!ts_can_be_enabled(ts))
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ case NM_EV_DISABLE:
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void nm_chan_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&ts->mo, -1, -1, NM_STATE_SHUTDOWN);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_chan_fsm_states[] = {
+ [NM_CHAN_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_SW_ACT) |
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_CHAN_ST_OP_DISABLED_DEPENDENCY] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_NACK) | /* backward compatibility, buggy BSC */
+ X(NM_EV_BBTRANSC_ENABLED) |
+ X(NM_EV_RCARRIER_ENABLED) |
+ X(NM_EV_BBTRANSC_DISABLED) |
+ X(NM_EV_RCARRIER_DISABLED),
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
+ .name = "DISABLED_DEPENDENCY",
+ .onenter = st_op_disabled_dependency_on_enter,
+ .action = st_op_disabled_dependency,
+ },
+ [NM_CHAN_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK) |
+ X(NM_EV_BBTRANSC_DISABLED) |
+ X(NM_EV_RCARRIER_DISABLED),
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_ENABLED) |
+ X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_CHAN_ST_OP_ENABLED] = {
+ .in_event_mask =
+ X(NM_EV_BBTRANSC_DISABLED) |
+ X(NM_EV_RCARRIER_DISABLED) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_chan_fsm = {
+ .name = "NM_CHAN_OP",
+ .states = nm_chan_fsm_states,
+ .num_states = ARRAY_SIZE(nm_chan_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_chan_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_chan_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_chan_fsm) == 0);
+}
diff --git a/src/common/nm_common_fsm.c b/src/common/nm_common_fsm.c
new file mode 100644
index 00000000..aa9bda4c
--- /dev/null
+++ b/src/common/nm_common_fsm.c
@@ -0,0 +1,45 @@
+/* NM FSM, common bits */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <osmocom/core/utils.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+
+const struct value_string nm_fsm_event_names[] = {
+ { NM_EV_SW_ACT, "SW_ACT" },
+ { NM_EV_RX_SETATTR, "RX_SETATTR" },
+ { NM_EV_RX_OPSTART, "RX_OPSTART" },
+ { NM_EV_OPSTART_ACK, "OPSTART_ACK" },
+ { NM_EV_OPSTART_NACK, "OPSTART_NACK" },
+ { NM_EV_SHUTDOWN_START, "SHUTDOWN_START" },
+ { NM_EV_SHUTDOWN_FINISH, "SHUTDOWN_FINISH" },
+ { NM_EV_OML_UP, "OML_UP" },
+ { NM_EV_RSL_UP, "RSL_UP" },
+ { NM_EV_RSL_DOWN, "RSL_DOWN" },
+ { NM_EV_PHYLINK_UP, "PHYLINK_UP" },
+ { NM_EV_PHYLINK_DOWN, "PHYLINK_DOWN" },
+ { NM_EV_DISABLE, "DISABLE" },
+ { NM_EV_BBTRANSC_ENABLED, "BBTRANSC_ENABLED" },
+ { NM_EV_BBTRANSC_DISABLED, "BBTRANSC_DISABLED" },
+ { NM_EV_RCARRIER_ENABLED, "RCARRIER_ENABLED" },
+ { NM_EV_RCARRIER_DISABLED, "RCARRIER_DISABLED" },
+ { 0, NULL }
+};
diff --git a/src/common/nm_gprs_cell_fsm.c b/src/common/nm_gprs_cell_fsm.c
new file mode 100644
index 00000000..95f46e31
--- /dev/null
+++ b/src/common/nm_gprs_cell_fsm.c
@@ -0,0 +1,260 @@
+/* NM GPRS Cell FSM */
+
+/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+#define X(s) (1 << (s))
+
+#define nm_gprs_cell_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+/* Can the GPRS Cell be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
+static bool gprs_cell_can_be_enabled(struct gsm_gprs_cell *cell)
+{
+ struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
+ return bts->site_mgr->gprs.nse.mo.nm_state.operational == NM_OPSTATE_ENABLED;
+}
+
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ /* Reset state here: */
+
+ cell->mo.setattr_success = false;
+ cell->mo.opstart_success = false;
+ oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* automatic SW_ACT upon OML link establishment: */
+ oml_mo_tx_sw_act_rep(&cell->mo);
+ if (gprs_cell_can_be_enabled(cell))
+ nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE);
+ else
+ nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ cell->mo.setattr_success = false;
+ cell->mo.opstart_success = false;
+ oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
+}
+
+static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg,
+ &cell->mo, cell);
+ cell->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!cell->mo.setattr_success) {
+ oml_mo_opstart_nack(&cell->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &cell->mo, cell);
+ break;
+ case NM_EV_OPSTART_ACK:
+ cell->mo.opstart_success = true;
+ oml_mo_opstart_ack(&cell->mo);
+ nm_gprs_cell_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
+ return;
+ case NM_EV_OPSTART_NACK:
+ cell->mo.opstart_success = false;
+ oml_mo_opstart_nack(&cell->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ cell->mo.opstart_success = false;
+ oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg, &cell->mo, bts);
+ cell->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!cell->mo.setattr_success) {
+ oml_mo_opstart_nack(&cell->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &cell->mo, bts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ cell->mo.opstart_success = true;
+ oml_mo_opstart_ack(&cell->mo);
+ nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_ENABLED);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ cell->mo.opstart_success = false;
+ oml_mo_opstart_nack(&cell->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+ oml_mo_state_chg(&cell->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+}
+
+static void nm_gprs_cell_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&cell->mo, -1, -1, NM_STATE_SHUTDOWN);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_gprs_cell_fsm_states[] = {
+ [NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY) |
+ X(NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
+ .name = "DISABLED_DEPENDENCY",
+ .onenter = st_op_disabled_dependency_on_enter,
+ .action = st_op_disabled_dependency,
+ },
+ [NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK),
+ .out_state_mask =
+ X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_CELL_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_GPRS_CELL_ST_OP_ENABLED] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_gprs_cell_fsm = {
+ .name = "NM_GPRS_CELL_OP",
+ .states = nm_gprs_cell_fsm_states,
+ .num_states = ARRAY_SIZE(nm_gprs_cell_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_gprs_cell_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_gprs_cell_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_gprs_cell_fsm) == 0);
+}
diff --git a/src/common/nm_gprs_nse_fsm.c b/src/common/nm_gprs_nse_fsm.c
new file mode 100644
index 00000000..2818c868
--- /dev/null
+++ b/src/common/nm_gprs_nse_fsm.c
@@ -0,0 +1,280 @@
+/* NM GPRS NSE FSM */
+
+/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/phy_link.h>
+#include <osmo-bts/cbch.h>
+
+#define X(s) (1 << (s))
+
+#define nm_gprs_nse_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+static void ev_dispatch_children(struct gsm_gprs_nse *nse, uint32_t event)
+{
+ unsigned int i;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
+
+ osmo_fsm_inst_dispatch(bts->gprs.cell.mo.fi, event, NULL);
+ for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
+ struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
+ osmo_fsm_inst_dispatch(nsvc->mo.fi, event, NULL);
+ }
+}
+
+/* Can the NSE be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
+static bool nse_can_be_enabled(struct gsm_gprs_nse *nse)
+{
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
+ return bts->mo.nm_state.operational == NM_OPSTATE_ENABLED;
+}
+
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ /* Reset state here: */
+
+ nse->mo.setattr_success = false;
+ nse->mo.opstart_success = false;
+ oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* automatic SW_ACT upon OML link establishment: */
+ oml_mo_tx_sw_act_rep(&nse->mo);
+ ev_dispatch_children(nse, event);
+ if (nse_can_be_enabled(nse))
+ nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE);
+ else
+ nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ nse->mo.setattr_success = false;
+ nse->mo.opstart_success = false;
+ oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
+}
+
+static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg,
+ &nse->mo, nse);
+ nse->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!nse->mo.setattr_success) {
+ oml_mo_opstart_nack(&nse->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &nse->mo, nse);
+ break;
+ case NM_EV_OPSTART_ACK:
+ nse->mo.opstart_success = true;
+ oml_mo_opstart_ack(&nse->mo);
+ nm_gprs_nse_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
+ return;
+ case NM_EV_OPSTART_NACK:
+ nse->mo.opstart_success = false;
+ oml_mo_opstart_nack(&nse->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ nse->mo.opstart_success = false;
+ oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg, &nse->mo, bts);
+ nse->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!nse->mo.setattr_success) {
+ oml_mo_opstart_nack(&nse->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &nse->mo, bts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ nse->mo.opstart_success = true;
+ oml_mo_opstart_ack(&nse->mo);
+ nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_ENABLED);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ nse->mo.opstart_success = false;
+ oml_mo_opstart_nack(&nse->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+ oml_mo_state_chg(&nse->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+}
+
+static void nm_gprs_nse_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&nse->mo, -1, -1, NM_STATE_SHUTDOWN);
+
+ /* Propagate event to children: */
+ ev_dispatch_children(nse, event);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ /* Propagate event to children: */
+ ev_dispatch_children(nse, event);
+ nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_gprs_nse_fsm_states[] = {
+ [NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY) |
+ X(NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
+ .name = "DISABLED_DEPENDENCY",
+ .onenter = st_op_disabled_dependency_on_enter,
+ .action = st_op_disabled_dependency,
+ },
+ [NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK),
+ .out_state_mask =
+ X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_NSE_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_GPRS_NSE_ST_OP_ENABLED] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_gprs_nse_fsm = {
+ .name = "NM_GPRS_NSE_OP",
+ .states = nm_gprs_nse_fsm_states,
+ .num_states = ARRAY_SIZE(nm_gprs_nse_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_gprs_nse_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_gprs_nse_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_gprs_nse_fsm) == 0);
+}
diff --git a/src/common/nm_gprs_nsvc_fsm.c b/src/common/nm_gprs_nsvc_fsm.c
new file mode 100644
index 00000000..cbfd97af
--- /dev/null
+++ b/src/common/nm_gprs_nsvc_fsm.c
@@ -0,0 +1,259 @@
+/* NM GPRS NSVC FSM */
+
+/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+#define X(s) (1 << (s))
+
+#define nm_gprs_nsvc_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+/* Can the GPRS Cell be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
+static bool gprs_nsvc_can_be_enabled(struct gsm_gprs_nsvc *nsvc)
+{
+ return nsvc->nse->mo.nm_state.operational == NM_OPSTATE_ENABLED;
+}
+
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ /* Reset state here: */
+
+ nsvc->mo.setattr_success = false;
+ nsvc->mo.opstart_success = false;
+ oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* automatic SW_ACT upon OML link establishment: */
+ oml_mo_tx_sw_act_rep(&nsvc->mo);
+ if (gprs_nsvc_can_be_enabled(nsvc))
+ nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE);
+ else
+ nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ nsvc->mo.setattr_success = false;
+ nsvc->mo.opstart_success = false;
+ oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
+}
+
+static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nsvc->nse);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg,
+ &nsvc->mo, nsvc);
+ nsvc->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!nsvc->mo.setattr_success) {
+ oml_mo_opstart_nack(&nsvc->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &nsvc->mo, nsvc);
+ break;
+ case NM_EV_OPSTART_ACK:
+ nsvc->mo.opstart_success = true;
+ oml_mo_opstart_ack(&nsvc->mo);
+ nm_gprs_nsvc_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
+ return;
+ case NM_EV_OPSTART_NACK:
+ nsvc->mo.opstart_success = false;
+ oml_mo_opstart_nack(&nsvc->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ nsvc->mo.opstart_success = false;
+ oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nsvc->nse);
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ int rc;
+
+ switch (event) {
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(bts, setattr_data->msg, &nsvc->mo, bts);
+ nsvc->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break;
+ case NM_EV_RX_OPSTART:
+ if (!nsvc->mo.setattr_success) {
+ oml_mo_opstart_nack(&nsvc->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(bts, &nsvc->mo, bts);
+ break;
+ case NM_EV_OPSTART_ACK:
+ nsvc->mo.opstart_success = true;
+ oml_mo_opstart_ack(&nsvc->mo);
+ nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_ENABLED);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ nsvc->mo.opstart_success = false;
+ oml_mo_opstart_nack(&nsvc->mo, (int)(intptr_t)data);
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+ oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+}
+
+static void nm_gprs_nsvc_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&nsvc->mo, -1, -1, NM_STATE_SHUTDOWN);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_gprs_nsvc_fsm_states[] = {
+ [NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP),
+ .out_state_mask =
+ X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY) |
+ X(NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
+ X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
+ .out_state_mask =
+ X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
+ X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
+ .name = "DISABLED_DEPENDENCY",
+ .onenter = st_op_disabled_dependency_on_enter,
+ .action = st_op_disabled_dependency,
+ },
+ [NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK),
+ .out_state_mask =
+ X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_GPRS_NSVC_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_GPRS_NSVC_ST_OP_ENABLED] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_gprs_nsvc_fsm = {
+ .name = "NM_GPRS_NSVC_OP",
+ .states = nm_gprs_nsvc_fsm_states,
+ .num_states = ARRAY_SIZE(nm_gprs_nsvc_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_gprs_nsvc_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_gprs_nsvc_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_gprs_nsvc_fsm) == 0);
+}
diff --git a/src/common/nm_radio_carrier_fsm.c b/src/common/nm_radio_carrier_fsm.c
new file mode 100644
index 00000000..f9589532
--- /dev/null
+++ b/src/common/nm_radio_carrier_fsm.c
@@ -0,0 +1,285 @@
+/* NM Radio Carrier FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/phy_link.h>
+
+#define X(s) (1 << (s))
+
+#define nm_rcarrier_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+ /* Reset state: */
+ TALLOC_FREE(trx->mo.nm_attr);
+
+ trx->mo.setattr_success = false;
+ trx->mo.opstart_success = false;
+ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
+}
+
+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SW_ACT:
+ oml_mo_tx_sw_act_rep(&trx->mo);
+ nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_OFFLINE);
+ return;
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&trx->mo);
+ return;
+ case NM_EV_RSL_UP:
+ return;
+ case NM_EV_RSL_DOWN:
+ return;
+ case NM_EV_PHYLINK_UP:
+ return;
+ case NM_EV_PHYLINK_DOWN:
+ return;
+ case NM_EV_DISABLE:
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+ unsigned int i;
+
+ trx->mo.setattr_success = false;
+ trx->mo.opstart_success = false;
+ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
+
+ if (prev_state == NM_RCARRIER_ST_OP_ENABLED) {
+ for (i = 0; i < TRX_NR_TS; i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_RCARRIER_DISABLED, NULL);
+ }
+ }
+}
+
+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+ struct nm_fsm_ev_setattr_data *setattr_data;
+ bool phy_state_connected;
+ bool rsl_link_connected;
+ int rc;
+
+ switch (event) {
+ case NM_EV_OML_UP:
+ /* Report current state: */
+ oml_tx_state_changed(&trx->mo);
+ return;
+ case NM_EV_RX_SETATTR:
+ setattr_data = (struct nm_fsm_ev_setattr_data *)data;
+ rc = bts_model_apply_oml(trx->bts, setattr_data->msg,
+ &trx->mo, trx);
+ trx->mo.setattr_success = rc == 0;
+ oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
+ break; /* check statechg below */
+ case NM_EV_RX_OPSTART:
+ if (!trx->mo.setattr_success) {
+ oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);
+ return;
+ }
+ bts_model_opstart(trx->bts, &trx->mo, trx);
+ return;
+ case NM_EV_OPSTART_ACK:
+ trx->mo.opstart_success = true;
+ oml_mo_opstart_ack(&trx->mo);
+ break; /* check statechg below */
+ case NM_EV_OPSTART_NACK:
+ trx->mo.opstart_success = false;
+ oml_mo_opstart_nack(&trx->mo, (int)(intptr_t)data);
+ return;
+ case NM_EV_RSL_UP:
+ break; /* check statechg below */
+ case NM_EV_RSL_DOWN:
+ return;
+ case NM_EV_PHYLINK_UP:
+ break; /* check statechg below */
+ case NM_EV_PHYLINK_DOWN:
+ return;
+ case NM_EV_DISABLE:
+ return;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ if (trx->bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;
+ rsl_link_connected = !!trx->bb_transc.rsl.link;
+ } else {
+ phy_state_connected = true;
+ rsl_link_connected = true;
+ }
+
+ if (rsl_link_connected && phy_state_connected &&
+ trx->mo.setattr_success && trx->mo.opstart_success) {
+ nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_ENABLED);
+ } else {
+ LOGPFSML(fi, LOGL_INFO, "Delay switch to operative state Enabled, wait for:%s%s%s%s\n",
+ rsl_link_connected ? "" : " rsl",
+ phy_state_connected ? "" : " phy",
+ trx->mo.setattr_success ? "" : " setattr",
+ trx->mo.opstart_success ? "" : " opstart");
+
+ }
+}
+
+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+ unsigned int tn;
+
+ oml_mo_state_chg(&trx->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
+ /* Mark Dependency TS as Offline (ready to be Opstarted) */
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_RCARRIER_ENABLED, NULL);
+ }
+}
+
+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case NM_EV_RSL_DOWN:
+ break;
+ case NM_EV_PHYLINK_DOWN:
+ break;
+ case NM_EV_DISABLE:
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_OFFLINE);
+}
+
+static void nm_rcarrier_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;
+
+ switch (event) {
+ case NM_EV_SHUTDOWN_START:
+ /* Announce we start shutting down */
+ oml_mo_state_chg(&trx->mo, -1, -1, NM_STATE_SHUTDOWN);
+ break;
+ case NM_EV_SHUTDOWN_FINISH:
+ nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static struct osmo_fsm_state nm_rcarrier_fsm_states[] = {
+ [NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED] = {
+ .in_event_mask =
+ X(NM_EV_SW_ACT) |
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RSL_UP) |
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_UP) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_RCARRIER_ST_OP_DISABLED_OFFLINE),
+ .name = "DISABLED_NOTINSTALLED",
+ .onenter = st_op_disabled_notinstalled_on_enter,
+ .action = st_op_disabled_notinstalled,
+ },
+ [NM_RCARRIER_ST_OP_DISABLED_OFFLINE] = {
+ .in_event_mask =
+ X(NM_EV_OML_UP) |
+ X(NM_EV_RX_SETATTR) |
+ X(NM_EV_RX_OPSTART) |
+ X(NM_EV_OPSTART_ACK) |
+ X(NM_EV_OPSTART_NACK) |
+ X(NM_EV_RSL_UP) |
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_UP) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_RCARRIER_ST_OP_ENABLED),
+ .name = "DISABLED_OFFLINE",
+ .onenter = st_op_disabled_offline_on_enter,
+ .action = st_op_disabled_offline,
+ },
+ [NM_RCARRIER_ST_OP_ENABLED] = {
+ .in_event_mask =
+ X(NM_EV_RSL_DOWN) |
+ X(NM_EV_PHYLINK_DOWN) |
+ X(NM_EV_DISABLE),
+ .out_state_mask =
+ X(NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_RCARRIER_ST_OP_DISABLED_OFFLINE),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
+ },
+};
+
+struct osmo_fsm nm_rcarrier_fsm = {
+ .name = "NM_RCARRIER_OP",
+ .states = nm_rcarrier_fsm_states,
+ .num_states = ARRAY_SIZE(nm_rcarrier_fsm_states),
+ .event_names = nm_fsm_event_names,
+ .allstate_action = nm_rcarrier_allstate,
+ .allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
+ X(NM_EV_SHUTDOWN_FINISH),
+ .log_subsys = DOML,
+};
+
+static __attribute__((constructor)) void nm_rcarrier_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&nm_rcarrier_fsm) == 0);
+}
diff --git a/src/common/notification.c b/src/common/notification.c
new file mode 100644
index 00000000..9351ec04
--- /dev/null
+++ b/src/common/notification.c
@@ -0,0 +1,256 @@
+/* Maintain and generate ASCI notifications */
+
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Harald Welte
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bitvec.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/notification.h>
+
+static struct asci_notification *bts_asci_notification_find(struct gsm_bts *bts, const uint8_t *group_call_ref)
+{
+ struct asci_notification *n;
+ llist_for_each_entry(n, &bts->asci.notifications, list) {
+ if (!memcmp(n->group_call_ref, group_call_ref, sizeof(n->group_call_ref)))
+ return n;
+ }
+ return NULL;
+}
+
+int bts_asci_notification_add(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
+ uint8_t chan_desc_len, const struct rsl_ie_nch_drx_info *nch_drx_info)
+{
+ struct asci_notification *n;
+
+ if (bts_asci_notification_find(bts, group_call_ref))
+ return -EEXIST;
+
+ n = talloc_zero(bts, struct asci_notification);
+ if (!n)
+ return -ENOMEM;
+
+ memcpy(n->group_call_ref, group_call_ref, sizeof(n->group_call_ref));
+ if (chan_desc && chan_desc_len) {
+ n->chan_desc.present = true;
+ n->chan_desc.len = chan_desc_len;
+ memcpy(&n->chan_desc.value, chan_desc, chan_desc_len);
+ }
+ if (nch_drx_info) {
+ n->nch_drx_info.present = true;
+ n->nch_drx_info.value = *nch_drx_info;
+ }
+
+ LOGP(DASCI, LOGL_INFO, "Added ASCI Notification for group call reference %s\n",
+ osmo_hexdump_nospc(n->group_call_ref, ARRAY_SIZE(n->group_call_ref)));
+
+ /* add at beginning of "queue" to make sure a new call is notified first */
+ llist_add(&n->list, &bts->asci.notifications);
+
+ bts->asci.notification_entries++;
+ bts->asci.notification_count = 0;
+ bts->asci.nln = (bts->asci.nln + 1) % 4;
+
+ return 0;
+}
+
+int bts_asci_notification_del(struct gsm_bts *bts, const uint8_t *group_call_ref)
+{
+ struct asci_notification *n = bts_asci_notification_find(bts, group_call_ref);
+ if (!n)
+ return -ENODEV;
+
+ LOGP(DASCI, LOGL_INFO, "Deleting ASCI Notification for group call reference %s\n",
+ osmo_hexdump_nospc(n->group_call_ref, ARRAY_SIZE(n->group_call_ref)));
+
+ llist_del(&n->list);
+ talloc_free(n);
+
+ bts->asci.notification_entries--;
+ bts->asci.notification_count = 0;
+ bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
+
+ return 0;
+}
+
+int bts_asci_notification_reset(struct gsm_bts *bts)
+{
+ struct asci_notification *n, *n2;
+
+ LOGP(DASCI, LOGL_INFO, "Deleting all %u ASCI Notifications of BTS\n",
+ llist_count(&bts->asci.notifications));
+
+ llist_for_each_entry_safe(n, n2, &bts->asci.notifications, list) {
+ llist_del(&n->list);
+ talloc_free(n);
+ }
+
+ bts->asci.notification_entries = 0;
+ bts->asci.notification_count = 0;
+ bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
+
+ return 0;
+}
+
+const struct asci_notification *bts_asci_notification_get_next(struct gsm_bts *bts)
+{
+ struct asci_notification *n;
+
+ n = llist_first_entry_or_null(&bts->asci.notifications, struct asci_notification, list);
+ if (!n)
+ return NULL;
+
+ /* move to end of list to iterate over them */
+ llist_del(&n->list);
+ llist_add_tail(&n->list, &bts->asci.notifications);
+
+ return n;
+}
+
+
+/*! append a "Group Call Information" CSN.1 structure to the caller-provided bit-vector.
+ * \param[out] bv caller-provided output bit-vector
+ * \param[in] gcr 5-byte group call reference
+ * \param[in] ch_desc optional group channel description (may be NULL)
+ * \param[in] ch_desc_len length of group channel description (in bytes) */
+void append_group_call_information(struct bitvec *bv, const uint8_t *gcr, const uint8_t *ch_desc, uint8_t ch_desc_len)
+{
+ /* spec reference: TS 44.018 Section 9.1.21a */
+
+ /* <Group Call Reference : bit(36)> */
+ struct bitvec *gcr_bv = bitvec_alloc(5*8, NULL);
+ OSMO_ASSERT(gcr_bv);
+ bitvec_unpack(gcr_bv, gcr);
+ for (unsigned int i = 0; i < 36; i++)
+ bitvec_set_bit(bv, bitvec_get_bit_pos(gcr_bv, i));
+
+ /* Group Channel Description */
+ if (ch_desc && ch_desc_len) {
+ struct bitvec *chd_bv = bitvec_alloc(ch_desc_len*8, NULL);
+ OSMO_ASSERT(chd_bv);
+ bitvec_unpack(chd_bv, ch_desc);
+ bitvec_set_bit(bv, 1);
+ /* <Channel Description : bit(24)> */
+ for (unsigned int i = 0; i < ch_desc_len * 8; i++)
+ bitvec_set_bit(bv, bitvec_get_bit_pos(chd_bv, i));
+ bitvec_free(chd_bv);
+ /* FIXME: hopping */
+ bitvec_set_bit(bv, 0);
+ } else {
+ bitvec_set_bit(bv, 0);
+ }
+
+ bitvec_free(gcr_bv);
+}
+
+#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
+
+int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf)
+{
+ struct gsm48_notification_nch *nn = (struct gsm48_notification_nch *) out_buf;
+ const struct asci_notification *notif;
+ unsigned int ro_len;
+
+ notif = bts_asci_notification_get_next(bts);
+
+ *nn = (struct gsm48_notification_nch) {
+ .proto_discr = GSM48_PDISC_RR,
+ .msg_type = GSM48_MT_RR_NOTIF_NCH,
+ };
+
+ nn->l2_plen = L2_PLEN(nn->data - out_buf);
+
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (nn->data - out_buf);
+ memset(nn->data, GSM_MACBLOCK_PADDING, ro_len);
+
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = nn->data,
+ };
+
+ /* {0 | 1 < NLN(NCH) : bit (2) >}
+ * Only send NLN, at the last notifications.
+ * When the phone receives two NLN with the same value, it knows that all notifications has been received.
+ * Also send NLN if no notification is available. */
+ if (bts->asci.notification_count >= bts->asci.notification_entries - 1) {
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, bts->asci.nln, 2);
+ } else {
+ bitvec_set_bit(&bv, 0);
+ }
+
+ /* Count NLN. */
+ if (++bts->asci.notification_count >= bts->asci.notification_entries)
+ bts->asci.notification_count = 0;
+
+ /* < List of Group Call NCH information > ::=
+ * { 0 | 1 < Group Call information > < List of Group Call NCH information > } ; */
+ if (notif) {
+ bitvec_set_bit(&bv, 1);
+ append_group_call_information(&bv, notif->group_call_ref,
+ notif->chan_desc.present ? notif->chan_desc.value : NULL,
+ notif->chan_desc.len);
+ }
+ bitvec_set_bit(&bv, 0); /* End of list */
+
+ /* TODO: Additions in Release 6 */
+ /* TODO: Additions in Release 7 */
+
+ return GSM_MACBLOCK_LEN;
+}
+
+int bts_asci_notify_facch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf, const uint8_t *group_call_ref,
+ const uint8_t *chan_desc, uint8_t chan_desc_len)
+{
+ struct gsm48_hdr_sh *sh = (struct gsm48_hdr_sh *) out_buf;
+ unsigned int ro_len;
+
+ *sh = (struct gsm48_hdr_sh) {
+ .rr_short_pd = GSM48_PDISC_SH_RR,
+ .msg_type = GSM48_MT_RR_SH_FACCH,
+ .l2_header = 0,
+ };
+
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (sh->data - out_buf);
+ memset(sh->data, GSM_MACBLOCK_PADDING, ro_len);
+
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = sh->data,
+ };
+
+ /* 0 < Group Call information > */
+ bitvec_set_bit(&bv, 0);
+ append_group_call_information(&bv, group_call_ref, chan_desc, chan_desc_len);
+
+ /* TODO: Additions in Release 6 */
+ /* TODO: Additions in Release 7 */
+
+ return GSM_MACBLOCK_LEN;
+}
diff --git a/src/common/oml.c b/src/common/oml.c
index 3defa494..a9e13b52 100644
--- a/src/common/oml.c
+++ b/src/common/oml.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -34,6 +34,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/gsm/abis_nm.h>
#include <osmocom/gsm/tlv.h>
@@ -46,8 +47,10 @@
#include <osmo-bts/oml.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/signal.h>
#include <osmo-bts/phy_link.h>
+#include <osmo-bts/nm_common_fsm.h>
#define LOGPFOH(ss, lvl, foh, fmt, args ...) LOGP(ss, lvl, "%s: " fmt, abis_nm_dump_foh(foh), ## args)
#define DEBUGPFOH(ss, foh, fmt, args ...) LOGPFOH(ss, LOGL_DEBUG, foh, fmt, ## args)
@@ -131,6 +134,7 @@ int oml_send_msg(struct msgb *msg, int is_manuf)
int oml_mo_send_msg(const struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type)
{
struct abis_om_fom_hdr *foh;
+ struct gsm_bts *bts;
msg->l3h = msgb_push(msg, sizeof(*foh));
foh = (struct abis_om_fom_hdr *) msg->l3h;
@@ -138,17 +142,31 @@ int oml_mo_send_msg(const struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_
foh->obj_class = mo->obj_class;
memcpy(&foh->obj_inst, &mo->obj_inst, sizeof(foh->obj_inst));
- /* FIXME: This assumption may not always be correct */
- msg->trx = mo->bts->c0;
+ /* Find and set OML TRX on msg: */
+ switch (mo->obj_class) {
+ case NM_OC_SITE_MANAGER:
+ /* Pick the first BTS: */
+ bts = gsm_bts_num(g_bts_sm, 0);
+ break;
+ default:
+ /* Other objects should have a valid BTS available: */
+ bts = gsm_bts_num(g_bts_sm, mo->obj_inst.bts_nr);
+ }
+ if (OSMO_UNLIKELY(!bts)) {
+ LOGPFOH(DOML, LOGL_NOTICE, foh,
+ "Sending FOM failed (no related BTS object found)\n");
+ return -EINVAL;
+ }
+ msg->trx = bts->c0;
DEBUGPFOH(DOML, foh, "Tx %s\n", get_value_string(abis_nm_msgtype_names, foh->msg_type));
return oml_send_msg(msg, 0);
}
-static inline void add_bts_attrs(struct msgb *msg, const struct gsm_bts *bts)
+/* Put NM_ATT_SW_CONFIG as per 9.4.61 "SW Configuration" */
+static int add_att_sw_config(struct msgb *msg, const struct gsm_abis_mo *mo)
{
- uint16_t total_len = 0;
uint8_t *len;
/* Put NM_ATT_SW_CONFIG as per 9.4.61 "SW Configuration". */
@@ -157,117 +175,291 @@ static inline void add_bts_attrs(struct msgb *msg, const struct gsm_bts *bts)
/* We don't know the length yet, so we update it later. */
len = msgb_put(msg, 2);
- total_len += abis_nm_put_sw_file(msg, "osmobts", PACKAGE_VERSION, true);
- total_len += abis_nm_put_sw_file(msg, btsatttr2str(BTS_TYPE_VARIANT),
- btsvariant2str(bts->variant), true);
+ switch (mo->obj_class) {
+ case NM_OC_BTS:
+ {
+ const struct gsm_bts *bts = mo->bts;
+
+ abis_nm_put_sw_file(msg, "osmobts", PACKAGE_VERSION, true);
+ abis_nm_put_sw_file(msg, btsatttr2str(BTS_TYPE_VARIANT),
+ btsvariant2str(bts->variant), true);
+ if (strlen(bts->sub_model)) {
+ abis_nm_put_sw_file(msg, btsatttr2str(BTS_SUB_MODEL),
+ bts->sub_model, true);
+ }
+ break;
+ }
+ case NM_OC_BASEB_TRANSC:
+ {
+ const struct gsm_bts_trx *trx = container_of(mo, struct gsm_bts_trx, bb_transc.mo);
+ const struct phy_instance *pinst = trx->pinst;
+ const char *phy_version;
- if (strlen(bts->sub_model)) {
- total_len += abis_nm_put_sw_file(msg, btsatttr2str(BTS_SUB_MODEL),
- bts->sub_model, true);
+ phy_version = pinst && strlen(pinst->version) ? pinst->version : "Unknown";
+ abis_nm_put_sw_file(msg, btsatttr2str(TRX_PHY_VERSION), phy_version, true);
+ break;
+ }
+ default:
+ msgb_get(msg, 1 + 2); /* TL16 */
+ return -ENOTSUP;
}
/* Finally, update the length */
- osmo_store16be(total_len, len);
+ osmo_store16be((uint16_t)(msg->tail - (len + 2)), len);
+
+ return 0;
}
/* Add BTS features as 3GPP TS 52.021 §9.4.30 Manufacturer Id */
static inline void add_bts_feat(struct msgb *msg, const struct gsm_bts *bts)
{
- msgb_tl16v_put(msg, NM_ATT_MANUF_ID, _NUM_BTS_FEAT/8 + 1, bts->_features_data);
+ unsigned int len = OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT);
+ msgb_tl16v_put(msg, NM_ATT_MANUF_ID, len, bts->features->data);
}
-static inline void add_trx_attr(struct msgb *msg, const struct gsm_bts_trx *trx)
+/* Add ip.access feature flags for the given MO */
+static int add_att_ipacc_features(struct msgb *msg, const struct gsm_abis_mo *mo)
{
- const struct phy_instance *pinst = trx_phy_instance(trx);
- const char *phy_version;
- uint16_t total_len;
+ const struct gsm_bts *bts = mo->bts;
+ const struct gsm_bts_trx *trx;
+ uint32_t val;
uint8_t *len;
- /* Put NM_ATT_SW_CONFIG as per 9.4.61 "SW Configuration". */
- msgb_v_put(msg, NM_ATT_SW_CONFIG);
+ msgb_v_put(msg, NM_ATT_IPACC_SUPP_FEATURES);
/* We don't know the length yet, so we update it later. */
len = msgb_put(msg, 2);
- phy_version = pinst && strlen(pinst->version) ? pinst->version : "Unknown";
- total_len = abis_nm_put_sw_file(msg, btsatttr2str(TRX_PHY_VERSION), phy_version, true);
+ switch (mo->obj_class) {
+ case NM_OC_BTS:
+ msgb_tv16_put(msg, NM_IPAC_EIE_MAX_TA, 1); /* TL16 */
+ msgb_put_u8(msg, (bts->support.max_ta >> 0) & 0xff);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ trx = container_of(mo, struct gsm_bts_trx, mo);
+ msgb_tv16_put(msg, NM_IPAC_EIE_FREQ_BANDS, 1); /* TL16 */
+ msgb_put_u8(msg, (trx->support.freq_bands >> 0) & 0xff);
+ break;
+ case NM_OC_BASEB_TRANSC:
+ trx = container_of(mo, struct gsm_bts_trx, bb_transc.mo);
+ msgb_tv16_put(msg, NM_IPAC_EIE_CIPH_ALGOS, 1); /* TL16 */
+ msgb_put_u8(msg, bts->support.ciphers); /* LSB is A5/1 */
+
+ msgb_tv16_put(msg, NM_IPAC_EIE_CHAN_TYPES, 2); /* TL16 */
+ msgb_put_u8(msg, (trx->support.chan_types >> 0) & 0xff);
+ msgb_put_u8(msg, (trx->support.chan_types >> 8) & 0xff);
+
+ msgb_tv16_put(msg, NM_IPAC_EIE_CHAN_MODES, 3); /* TL16 */
+ msgb_put_u8(msg, (trx->support.chan_modes >> 0) & 0xff);
+ msgb_put_u8(msg, (trx->support.chan_modes >> 8) & 0xff);
+ msgb_put_u8(msg, (trx->support.chan_modes >> 16) & 0xff);
+
+ msgb_tv16_put(msg, NM_IPAC_EIE_RTP_FEATURES, 1); /* TL16 */
+ val = NM_IPAC_F_RTP_FEAT_IR_64k;
+ msgb_put_u8(msg, (val >> 0) & 0xff);
+
+ msgb_tv16_put(msg, NM_IPAC_EIE_RSL_FEATURES, 1); /* TL16 */
+ val = NM_IPAC_F_RSL_FEAT_DYN_PDCH_ACT
+ | NM_IPAC_F_RSL_FEAT_RTP_PT2;
+ msgb_put_u8(msg, (val >> 0) & 0xff);
+ break;
+ case NM_OC_GPRS_CELL:
+ msgb_tv16_put(msg, NM_IPAC_EIE_GPRS_CODING, 2); /* TL16 */
+ msgb_put_u8(msg, (bts->gprs.cell.support.gprs_codings >> 0) & 0xff);
+ msgb_put_u8(msg, (bts->gprs.cell.support.gprs_codings >> 8) & 0xff);
+ break;
+ default:
+ msgb_get(msg, 1 + 2); /* TL16 */
+ return -ENOTSUP;
+ }
/* Finally, update the length */
- osmo_store16be(total_len, len);
+ osmo_store16be((uint16_t)(msg->tail - (len + 2)), len);
+
+ return 0;
}
-/* Handle a list of attributes requested by the BSC, compose
- * TRX-specific Get Attribute Response IE as per 9.4.64. */
-static inline int handle_attrs_trx(struct msgb *out_msg, const struct gsm_bts_trx *trx,
- const uint8_t *attr, uint16_t attr_len)
+/* Add attribute 9.4.8 BCCH ARFCN for BTS class */
+static inline void add_att_bcch_arfcn(struct msgb *msg, const struct gsm_bts *bts)
{
- uint8_t num_unsupported = 0;
- uint8_t *buf;
- int i;
+ /* type + 16 bit value */
+ msgb_tv16_put(msg, NM_ATT_BCCH_ARFCN, bts->c0->arfcn);
+}
- if (!trx) {
- LOGP(DOML, LOGL_ERROR, "%s: O&M Get Attributes for unknown TRX\n", gsm_trx_name(trx));
- return -NM_NACK_TRXNR_UNKN;
- }
+/* Add attribute 9.4.25 Interference Level Boundaries for BTS class */
+static inline void add_att_interf_bound(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit values */
+ msgb_put_u8(msg, NM_ATT_INTERF_BOUND);
+ for (int j = 0; j < ARRAY_SIZE(bts->interference.boundary); j++)
+ msgb_put_u8(msg, abs(bts->interference.boundary[j]));
+}
- for (i = 0; i < attr_len; i++) {
- switch (attr[i]) {
- case NM_ATT_SW_CONFIG:
- add_trx_attr(out_msg, trx);
- break;
- default:
- LOGP(DOML, LOGL_ERROR, "%s: O&M Get Attributes [%u], %s is unsupported by TRX.\n",
- gsm_trx_name(trx), i, get_value_string(abis_nm_att_names, attr[i]));
- /* Push this tag to the list of unsupported attributes */
- buf = msgb_push(out_msg, 1);
- *buf = attr[i];
- num_unsupported++;
- }
- }
+/* Add attribute 9.4.24 Intave Parameter for BTS class */
+static inline void add_att_intave_param(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_INTAVE_PARAM, bts->interference.intave);
+}
- /* Push the amount of unsupported attributes */
- buf = msgb_push(out_msg, 1);
- *buf = num_unsupported;
+/* Add attribute 9.4.14 Connection Failure Criterion for BTS class */
+static inline void add_att_conn_fail_crit(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + length + values */
+ msgb_tv16_put(msg, NM_ATT_CONN_FAIL_CRIT, 2);
+ msgb_put_u8(msg, 0x01);
+ msgb_put_u8(msg, bts->radio_link_timeout.current);
+}
+
+/* Add attribute 9.4.31 Maximum Timing Advance for BTS class */
+static inline void add_att_max_ta(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_MAX_TA, bts->max_ta);
+}
+
+/* Add attribute 9.4.39 Overload Period for BTS class */
+static inline void add_att_overl_period(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + length + value */
+ msgb_tv16_put(msg, NM_ATT_OVERL_PERIOD, 1);
+ msgb_put_u8(msg, bts->load.overload_period);
+}
+/* Add attribute 9.4.12 CCCH Load Threshold for BTS class */
+static inline void add_att_ccch_l_t(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_CCCH_L_T, bts->load.ccch.load_ind_thresh);
+}
+
+/* Add attribute 9.4.11 CCCH Load Indication Period for BTS class */
+static inline void add_att_ccch_l_i_p(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_CCCH_L_I_P, bts->load.ccch.load_ind_period);
+}
+
+/* Add attribute 9.4.44 RACH Busy Threshold for BTS class */
+static inline void add_att_rach_b_thresh(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_RACH_B_THRESH, abs(bts->load.rach.busy_thresh));
+}
+
+/* Add attribute 9.4.45 RACH Load Averaging Slots for BTS class */
+static inline void add_att_ldavg_slots(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 16 bit value */
+ msgb_tv16_put(msg, NM_ATT_LDAVG_SLOTS, bts->load.rach.averaging_slots);
+}
+
+/* Add attribute 9.4.10 BTS Air Timer for BTS class */
+static inline void add_att_bts_air_timer(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_BTS_AIR_TIMER, bts->t3105_ms / 10);
+}
+
+/* Add attribute 9.4.37 NY1 for BTS class */
+static inline void add_att_ny1(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_NY1, bts->ny1);
+}
+
+/* Add attribute 9.4.9 BSIC for BTS class */
+static inline int add_att_bsic(struct msgb *msg, const struct gsm_bts *bts)
+{
+ /* BSIC must be configured. */
+ if (!bts->bsic_configured)
+ return -EINVAL;
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_BSIC, bts->bsic);
return 0;
}
-/* Handle a list of attributes requested by the BSC, compose
- * BTS-specific Get Attribute Response IE as per 9.4.64. */
-static inline int handle_attrs_bts(struct msgb *out_msg, const struct gsm_bts *bts,
- const uint8_t *attr, uint16_t attr_len)
+/* Add attribute 9.4.20 GSM Time for BTS class */
+static inline void add_att_gsm_time(struct msgb *msg, const struct gsm_bts *bts)
{
- uint8_t num_unsupported = 0;
- uint8_t *buf;
- int i;
+ /* type + 16 bit value */
+ msgb_tv16_put(msg, NM_ATT_GSM_TIME, bts->gsm_time.fn % GSM_RFN_MODULUS);
+}
- if (!bts) {
- LOGP(DOML, LOGL_ERROR, "O&M Get Attributes for unknown BTS\n");
- return -NM_NACK_BTSNR_UNKN;
- }
+/* Add attribute 9.4.47 RF Max Power Reduction for radio carrier class */
+static inline void add_att_rf_maxpowr_r(struct msgb *msg, const struct gsm_bts_trx *trx)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2);
+}
- for (i = 0; i < attr_len; i++) {
- switch (attr[i]) {
- case NM_ATT_SW_CONFIG:
- add_bts_attrs(out_msg, bts);
- break;
- case NM_ATT_MANUF_ID:
- add_bts_feat(out_msg, bts);
- break;
- default:
- LOGP(DOML, LOGL_ERROR, "O&M Get Attributes [%u], %s is unsupported by BTS.\n", i,
- get_value_string(abis_nm_att_names, attr[i]));
- /* Push this tag to the list of unsupported attributes */
- buf = msgb_push(out_msg, 1);
- *buf = attr[i];
- num_unsupported++;
- }
+/* Add attribute 9.4.5 ARFCN List for radio carrier class */
+static inline void add_att_arfcn_list(struct msgb *msg, const struct gsm_bts_trx *trx)
+{
+#if 0
+ /* type + length + values */
+ msgb_tv16_put(msg, NM_ATT_ARFCN_LIST, trx->arfcn_num * 2);
+ for (int j = 0; j < trx->arfcn_num; j++)
+ msgb_put_u16(msg, trx->arfcn_list[j]);
+#else
+ /* type + length + values */
+ msgb_tv16_put(msg, NM_ATT_ARFCN_LIST, 2);
+ msgb_put_u16(msg, trx->arfcn);
+#endif
+}
+
+/* Add attribute 9.4.5 ARFCN List for channel class */
+static inline void add_att_arfcn_list_ts(struct msgb *msg, const struct gsm_bts_trx_ts *ts)
+{
+ if (ts->hopping.enabled) {
+ /* type + length + values */
+ msgb_tv16_put(msg, NM_ATT_ARFCN_LIST, ts->hopping.arfcn_num * 2);
+ for (int j = 0; j < ts->hopping.arfcn_num; j++)
+ msgb_put_u16(msg, ts->hopping.arfcn_list[j]);
+ } else {
+ /* type + length + values */
+ msgb_tv16_put(msg, NM_ATT_ARFCN_LIST, 2);
+ msgb_put_u16(msg, ts->trx->arfcn);
}
+}
- /* Push the amount of unsupported attributes */
- buf = msgb_push(out_msg, 1);
- *buf = num_unsupported;
+/* Add attribute 9.4.13 Channel Combination for channel class */
+static inline int add_att_chan_comb(struct msgb *msg, const struct gsm_bts_trx_ts *ts)
+{
+ int comb = abis_nm_chcomb4pchan(ts->pchan);
+ /* If current channel combination is not yet set, 0xff is returned. */
+ if (comb < 0 || comb == 0xff)
+ return -EINVAL;
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_CHAN_COMB, comb);
+ return 0;
+}
+
+/* Add attribute 9.4.60 TSC for channel class */
+static inline void add_att_tsc(struct msgb *msg, const struct gsm_bts_trx_ts *ts)
+{
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_TSC, ts->tsc);
+}
+
+/* Add attribute 9.4.60 HSN for channel class */
+static inline int add_att_hsn(struct msgb *msg, const struct gsm_bts_trx_ts *ts)
+{
+ if (!ts->hopping.enabled)
+ return -EINVAL;
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
+ return 0;
+}
+
+/* Add attribute 9.4.21 MAIO for channel class */
+static inline int add_att_maio(struct msgb *msg, const struct gsm_bts_trx_ts *ts)
+{
+ if (!ts->hopping.enabled)
+ return -EINVAL;
+ /* type + 8 bit value */
+ msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
return 0;
}
@@ -276,32 +468,177 @@ static int oml_tx_attr_resp(const struct gsm_abis_mo *mo,
const uint8_t *attr, uint16_t attr_len)
{
struct msgb *nmsg = oml_msgb_alloc();
- const char *mo_name = gsm_abis_mo_name(mo);
+ unsigned int num_unsupported = 0;
+ struct gsm_bts_trx *trx = NULL;
+ struct gsm_bts_trx_ts *ts = NULL;
int rc;
if (!nmsg)
return -NM_NACK_CANT_PERFORM;
+ /* Set TRX, if object class is Radio Carrier, Baseband Transceiver or Channel. */
switch (mo->obj_class) {
- case NM_OC_BTS:
- rc = handle_attrs_bts(nmsg, mo->bts, attr, attr_len);
- break;
+ case NM_OC_RADIO_CARRIER:
case NM_OC_BASEB_TRANSC:
- rc = handle_attrs_trx(nmsg, gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr), attr, attr_len);
+ case NM_OC_CHANNEL:
+ trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);
break;
- default:
- LOGP(DOML, LOGL_ERROR, "%s: Unsupported MO class in Get Attribute Response\n",
- mo_name);
- rc = -NM_NACK_OBJCLASS_NOTSUPP;
}
- if (rc < 0) {
- LOGP(DOML, LOGL_ERROR, "%s: Tx Get Attribute Response FAILED with rc=%d\n",
- mo_name, rc);
- msgb_free(nmsg);
- return rc;
+ /* Set TS, if object class is Channel. */
+ if (mo->obj_class == NM_OC_CHANNEL && trx)
+ ts = &trx->ts[mo->obj_inst.ts_nr];
+
+ for (unsigned int i = 0; i < attr_len; i++) {
+ switch (attr[i]) {
+ case NM_ATT_OPER_STATE:
+ msgb_tv16_put(nmsg, attr[i], 1);
+ msgb_put_u8(nmsg, mo->nm_state.operational);
+ break;
+ case NM_ATT_ADM_STATE:
+ msgb_tv16_put(nmsg, attr[i], 1);
+ msgb_put_u8(nmsg, mo->nm_state.administrative);
+ break;
+ case NM_ATT_AVAIL_STATUS:
+ msgb_tv16_put(nmsg, attr[i], 1);
+ msgb_put_u8(nmsg, mo->nm_state.availability);
+ break;
+ case NM_ATT_SW_CONFIG:
+ if (add_att_sw_config(nmsg, mo) != 0)
+ goto unsupported;
+ break;
+ case NM_ATT_MANUF_ID:
+ if (mo->obj_class == NM_OC_BTS)
+ add_bts_feat(nmsg, mo->bts);
+ else
+ goto unsupported;
+ break;
+ case NM_ATT_IPACC_SUPP_FEATURES:
+ if (add_att_ipacc_features(nmsg, mo) != 0)
+ goto unsupported;
+ break;
+ case NM_ATT_BCCH_ARFCN:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_bcch_arfcn(nmsg, mo->bts);
+ break;
+ case NM_ATT_INTERF_BOUND:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_interf_bound(nmsg, mo->bts);
+ break;
+ case NM_ATT_INTAVE_PARAM:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_intave_param(nmsg, mo->bts);
+ break;
+ case NM_ATT_CONN_FAIL_CRIT:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_conn_fail_crit(nmsg, mo->bts);
+ break;
+ case NM_ATT_MAX_TA:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_max_ta(nmsg, mo->bts);
+ break;
+ case NM_ATT_OVERL_PERIOD:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_overl_period(nmsg, mo->bts);
+ break;
+ case NM_ATT_CCCH_L_T:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_ccch_l_t(nmsg, mo->bts);
+ break;
+ case NM_ATT_CCCH_L_I_P:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_ccch_l_i_p(nmsg, mo->bts);
+ break;
+ case NM_ATT_RACH_B_THRESH:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_rach_b_thresh(nmsg, mo->bts);
+ break;
+ case NM_ATT_LDAVG_SLOTS:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_ldavg_slots(nmsg, mo->bts);
+ break;
+ case NM_ATT_BTS_AIR_TIMER:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_bts_air_timer(nmsg, mo->bts);
+ break;
+ case NM_ATT_NY1:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_ny1(nmsg, mo->bts);
+ break;
+ case NM_ATT_BSIC:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ if (add_att_bsic(nmsg, mo->bts) != 0)
+ goto unsupported;
+ break;
+ case NM_ATT_GSM_TIME:
+ if (mo->obj_class != NM_OC_BTS)
+ goto unsupported;
+ add_att_gsm_time(nmsg, mo->bts);
+ break;
+ case NM_ATT_RF_MAXPOWR_R:
+ if (mo->obj_class != NM_OC_RADIO_CARRIER || !trx)
+ goto unsupported;
+ add_att_rf_maxpowr_r(nmsg, trx);
+ break;
+ case NM_ATT_ARFCN_LIST:
+ if (mo->obj_class == NM_OC_RADIO_CARRIER && trx) {
+ add_att_arfcn_list(nmsg, trx);
+ break;
+ }
+ if (mo->obj_class == NM_OC_CHANNEL && ts) {
+ add_att_arfcn_list_ts(nmsg, ts);
+ break;
+ }
+ goto unsupported;
+ case NM_ATT_CHAN_COMB:
+ if (mo->obj_class != NM_OC_CHANNEL || !ts)
+ goto unsupported;
+ if (add_att_chan_comb(nmsg, ts) != 0)
+ goto unsupported;
+ break;
+ case NM_ATT_TSC:
+ if (mo->obj_class != NM_OC_CHANNEL || !ts)
+ goto unsupported;
+ add_att_tsc(nmsg, ts);
+ break;
+ case NM_ATT_HSN:
+ if (mo->obj_class != NM_OC_CHANNEL || !ts)
+ goto unsupported;
+ if (add_att_hsn(nmsg, ts) != 0)
+ goto unsupported;
+ break;
+ case NM_ATT_MAIO:
+ if (mo->obj_class != NM_OC_CHANNEL || !ts)
+ goto unsupported;
+ if (add_att_maio(nmsg, ts) != 0)
+ goto unsupported;
+ break;
+ default:
+unsupported:
+ LOGP(DOML, LOGL_ERROR, "%s: O&M Get Attributes [%u], %s is unsupported\n",
+ gsm_abis_mo_name(mo), i, get_value_string(abis_nm_att_names, attr[i]));
+ /* Push this tag to the list of unsupported attributes */
+ msgb_push_u8(nmsg, attr[i]);
+ num_unsupported++;
+ }
}
+ /* Push the amount of unsupported attributes */
+ msgb_push_u8(nmsg, num_unsupported);
+
/* Push Get Attribute Response Info TL (actually TV where V is L) */
msgb_tv16_push(nmsg, NM_ATT_GET_ARI, msgb_length(nmsg));
@@ -313,6 +650,7 @@ static int oml_tx_attr_resp(const struct gsm_abis_mo *mo,
int oml_tx_state_changed(const struct gsm_abis_mo *mo)
{
struct msgb *nmsg;
+ uint8_t avail_state;
nmsg = oml_msgb_alloc();
if (!nmsg)
@@ -322,7 +660,8 @@ int oml_tx_state_changed(const struct gsm_abis_mo *mo)
msgb_tv_put(nmsg, NM_ATT_OPER_STATE, mo->nm_state.operational);
/* 9.4.7 Availability Status */
- msgb_tl16v_put(nmsg, NM_ATT_AVAIL_STATUS, 1, &mo->nm_state.availability);
+ avail_state = (uint8_t) mo->nm_state.availability;
+ msgb_tl16v_put(nmsg, NM_ATT_AVAIL_STATUS, 1, &avail_state);
/* 9.4.4 Administrative Status -- not in spec but also sent by nanobts */
msgb_tv_put(nmsg, NM_ATT_ADM_STATE, mo->nm_state.administrative);
@@ -337,12 +676,13 @@ void oml_mo_state_init(struct gsm_abis_mo *mo, int op_state, int avail_state)
mo->nm_state.operational = op_state;
}
-int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state)
+int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state, int adm_state)
{
int rc = 0;
if ((op_state != -1 && mo->nm_state.operational != op_state) ||
- (avail_state != -1 && mo->nm_state.availability != avail_state)) {
+ (avail_state != -1 && mo->nm_state.availability != avail_state) ||
+ (adm_state != -1 && mo->nm_state.administrative != adm_state)) {
if (avail_state != -1) {
LOGP(DOML, LOGL_INFO, "%s AVAIL STATE %s -> %s\n",
gsm_abis_mo_name(mo),
@@ -351,13 +691,25 @@ int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state)
mo->nm_state.availability = avail_state;
}
if (op_state != -1) {
+ struct nm_statechg_signal_data nsd;
LOGP(DOML, LOGL_INFO, "%s OPER STATE %s -> %s\n",
gsm_abis_mo_name(mo),
abis_nm_opstate_name(mo->nm_state.operational),
abis_nm_opstate_name(op_state));
+ nsd.mo = mo;
+ nsd.old_state = mo->nm_state.operational;
+ nsd.new_state = op_state;
mo->nm_state.operational = op_state;
- osmo_signal_dispatch(SS_GLOBAL, S_NEW_OP_STATE, NULL);
+ osmo_signal_dispatch(SS_GLOBAL, S_NEW_OP_STATE, &nsd);
}
+ if (adm_state != -1) {
+ LOGP(DOML, LOGL_INFO, "%s ADMIN STATE %s -> %s\n",
+ gsm_abis_mo_name(mo),
+ abis_nm_admin_name(mo->nm_state.administrative),
+ abis_nm_admin_name(adm_state));
+ mo->nm_state.administrative = adm_state;
+ }
+
/* send state change report */
rc = oml_tx_state_changed(mo);
@@ -421,42 +773,48 @@ int oml_mo_opstart_nack(const struct gsm_abis_mo *mo, uint8_t nack_cause)
return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, nack_cause);
}
-/* Send an ACK or NACK response for 'msg' to BSC, deriving message
- * type, obj class, obj inst from 'msg' and copying all attributes
- * contained in 'msg'. ACK is sent if cause == 0; NACK otherwise */
-int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause)
+/* Send an ACK or NACK response to BSC for the given OML message,
+ * reusing it. ACK is sent if cause == 0; NACK otherwise. */
+int oml_fom_ack_nack(struct msgb *msg, uint8_t cause)
{
- struct msgb *msg;
struct abis_om_fom_hdr *foh;
- msg = msgb_copy(old_msg, "OML_fom_ack_nack");
- if (!msg)
- return -ENOMEM;
-
- /* remove any l2/l1 that may be present in copy */
+ /* remove any l2/l1 that may be already present */
msgb_pull_to_l2(msg);
- msg->trx = old_msg->trx;
-
foh = (struct abis_om_fom_hdr *) msg->l3h;
/* alter message type */
if (cause) {
- LOGPFOH(DOML, LOGL_NOTICE, foh, "Sending FOM NACK with cause %s.\n",
+ LOGPFOH(DOML, LOGL_NOTICE, foh, "Sending FOM NACK with cause %s\n",
abis_nm_nack_cause_name(cause));
foh->msg_type += 2; /* nack */
/* add cause */
msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause);
- /* update the length as we just made the message larger */
- struct abis_om_hdr *omh = (struct abis_om_hdr *) msgb_l2(msg);
- omh->length = msgb_l3len(msg);
} else {
- LOGPFOH(DOML, LOGL_DEBUG, foh, "Sending FOM ACK.\n");
+ LOGPFOH(DOML, LOGL_DEBUG, foh, "Sending FOM ACK\n");
foh->msg_type++; /* ack */
}
+ /* ensure that the message length is up to date */
+ struct abis_om_hdr *omh = (struct abis_om_hdr *) msgb_l2(msg);
+ omh->length = msgb_l3len(msg);
+
/* we cannot use oml_send_msg() as we already have the OML header */
- return abis_oml_sendmsg(msg);
+ if (abis_oml_sendmsg(msg) != 0)
+ LOGPFOH(DOML, LOGL_ERROR, foh, "Failed to send ACK/NACK\n");
+
+ /* msgb was reused, do not free() */
+ return 1;
+}
+
+/* Copy msg before calling oml_fom_ack_nack(), which takes its ownership */
+int oml_fom_ack_nack_copy_msg(const struct msgb *old_msg, uint8_t cause)
+{
+ struct msgb *msg = msgb_copy(old_msg, "OML-ack_nack");
+ msg->trx = old_msg->trx;
+ oml_fom_ack_nack(msg, cause);
+ return 0;
}
/*
@@ -472,20 +830,24 @@ int oml_mo_tx_sw_act_rep(const struct gsm_abis_mo *mo)
if (!nmsg)
return -ENOMEM;
- msgb_put(nmsg, sizeof(struct abis_om_fom_hdr));
return oml_mo_send_msg(mo, nmsg, NM_MT_SW_ACTIVATED_REP);
}
-/* The defaults below correspond to various sources/recommendations that could be found online.
- * The BSC should override this via OML anyway. */
-const unsigned int oml_default_t200_ms[7] = {
- [T200_SDCCH] = 1000,
- [T200_FACCH_F] = 1000,
- [T200_FACCH_H] = 1000,
- [T200_SACCH_TCH_SAPI0] = 2000,
- [T200_SACCH_SDCCH] = 2000,
- [T200_SDCCH_SAPI3] = 1000,
- [T200_SACCH_TCH_SAPI3] = 2000,
+/* The defaults below correspond to the number of frames until a response from the MS is expected.
+ * It defines the FN distance between the frame number when a message is sent (first frame) and when the response is
+ * received (first frame). On SACCH the duration is two frames, because SAPI0 and SAPI3 are are transmitted in
+ * alternating order. On DCCH with SAPI3 the duration is two seconds, because SAPI0 has priority over SAPI3.
+ *
+ * See Table 8 if 3GPP TS 44.006. Note that the table only shows the FN distance between frames.
+ */
+const uint32_t oml_default_t200_fn[7] = {
+ [T200_SDCCH] = 4+32,
+ [T200_FACCH_F] = 8+9,
+ [T200_FACCH_H] = 6+10,
+ [T200_SACCH_TCH_SAPI0] = 79+25+104,
+ [T200_SACCH_SDCCH] = 4+32+51,
+ [T200_SDCCH_SAPI3] = 4+32+408, /* two seconds */
+ [T200_SACCH_TCH_SAPI3] = 79+25+104,
};
/* 3GPP TS 52.021 §8.11.1 Get Attributes has been received */
@@ -495,6 +857,7 @@ static int oml_rx_get_attr(struct gsm_bts *bts, struct msgb *msg)
const struct gsm_abis_mo *mo;
struct tlv_parsed tp;
int rc;
+ enum abis_nm_nack_cause c;
if (!foh || !bts)
return -EINVAL;
@@ -502,10 +865,9 @@ static int oml_rx_get_attr(struct gsm_bts *bts, struct msgb *msg)
DEBUGPFOH(DOML, foh, "Rx GET ATTR\n");
/* Determine which OML object is addressed */
- mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
- if (!mo) {
+ if ((mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL) {
LOGPFOH(DOML, LOGL_ERROR, foh, "Get Attributes for unknown Object Instance\n");
- return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ return oml_fom_ack_nack(msg, c);
}
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
@@ -537,6 +899,7 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
struct tlv_parsed tp, *tp_merged;
int rc, i;
const uint8_t *payload;
+ struct nm_fsm_ev_setattr_data ev_data;
DEBUGPFOH(DOML, foh, "Rx SET BTS ATTR\n");
@@ -550,11 +913,11 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
/* Test for globally unsupported stuff here */
if (TLVP_PRES_LEN(&tp, NM_ATT_BCCH_ARFCN, 2)) {
uint16_t arfcn = ntohs(tlvp_val16_unal(&tp, NM_ATT_BCCH_ARFCN));
- if (arfcn > 1024) {
+ if (arfcn >= 1024) { /* 0 .. 1023 (1024 channels total) */
oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_WARN_SW_WARN,
"Given ARFCN %u is not supported",
arfcn);
- LOGPFOH(DOML, LOGL_ERROR, foh, "Given ARFCN %u is not supported.\n", arfcn);
+ LOGPFOH(DOML, LOGL_ERROR, foh, "Given ARFCN %u is not supported\n", arfcn);
return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL);
}
}
@@ -568,6 +931,7 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
/* merge existing BTS attributes with new attributes */
tp_merged = osmo_tlvp_copy(bts->mo.nm_attr, bts);
+ talloc_set_name_const(tp_merged, "oml_bts_attr");
osmo_tlvp_merge(tp_merged, &tp);
/* Ask BTS driver to validate new merged attributes */
@@ -586,8 +950,8 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
/* 9.4.25 Interference Level Boundaries */
if (TLVP_PRES_LEN(&tp, NM_ATT_INTERF_BOUND, 6)) {
payload = TLVP_VAL(&tp, NM_ATT_INTERF_BOUND);
- for (i = 0; i < 6; i++) {
- int16_t boundary = *payload;
+ for (i = 0; i < ARRAY_SIZE(bts->interference.boundary); i++) {
+ const int16_t boundary = payload[i];
bts->interference.boundary[i] = -1 * boundary;
}
}
@@ -603,12 +967,16 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
case 0xFF: /* Osmocom specific Extension of TS 12.21 */
LOGPFOH(DOML, LOGL_NOTICE, foh, "WARNING: Radio Link Timeout "
"explicitly disabled, only use this for lab testing!\n");
- bts->radio_link_timeout = -1;
+ bts->radio_link_timeout.oml = -1;
+ if (!bts->radio_link_timeout.vty_override)
+ bts->radio_link_timeout.current = bts->radio_link_timeout.oml;
break;
case 0x01: /* Based on uplink SACCH (radio link timeout) */
if (TLVP_LEN(&tp, NM_ATT_CONN_FAIL_CRIT) >= 2 &&
val[1] >= 4 && val[1] <= 64) {
- bts->radio_link_timeout = val[1];
+ bts->radio_link_timeout.oml = val[1];
+ if (!bts->radio_link_timeout.vty_override)
+ bts->radio_link_timeout.current = bts->radio_link_timeout.oml;
break;
}
/* fall-through */
@@ -622,25 +990,26 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
}
/* 9.4.53 T200 */
- if (TLVP_PRES_LEN(&tp, NM_ATT_T200, ARRAY_SIZE(bts->t200_ms))) {
+ if (TLVP_PRES_LEN(&tp, NM_ATT_T200, ARRAY_SIZE(bts->t200_fn))) {
+ /* The OML message NM_ATT_T200 is ignored, because T200 timeouts are set to
+ * the minimal response time. Longer timeouts would cause lower throughput
+ * in case of lost frames. Shorter timeouts would cause LAPDm to fail. */
+ DEBUGPFOH(DOML, foh, "Ignoring T200 BTS attribute.\n");
+#if 0
payload = TLVP_VAL(&tp, NM_ATT_T200);
- for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++) {
+ for (i = 0; i < ARRAY_SIZE(bts->t200_fn); i++) {
uint32_t t200_ms = payload[i] * abis_nm_t200_ms[i];
-#if 0
- bts->t200_ms[i] = t200_ms;
- DEBUGPFOH(DOML, foh, "T200[%u]: OML=%u, mult=%u => %u ms\n",
+ uint32_t t200_fn = t200_ms * 1000 + (GSM_TDMA_FN_DURATION_uS - 1) / GSM_TDMA_FN_DURATION_uS;
+ /* Values must not be less than absolute minimum. */
+ if (oml_default_t200_fn[i] <= t200_fn)
+ bts->t200_fn[i] = t200_fn;
+ else
+ bts->t200_fn[i] = oml_default_t200_fn[i];
+ DEBUGPFOH(DOML, foh, "T200[%u]: OML=%u, mult=%u => %u ms -> %u fn\n",
i, payload[i], abis_nm_t200_ms[i],
- bts->t200_ms[i]);
-#else
- /* we'd rather use the 1s/2s (long) defaults by
- * libosmocore, as we appear to have some bug(s)
- * related to handling T200 expiration in
- * libosmogsm lapd(m) code? */
- LOGPFOH(DOML, LOGL_NOTICE, foh, "Ignoring T200[%u] (%u ms) "
- "as sent by BSC due to suspected LAPDm bug!\n",
- i, t200_ms);
-#endif
+ t200_ms, bts->t200_fn[i]);
}
+#endif
}
/* 9.4.31 Maximum Timing Advance */
@@ -658,7 +1027,10 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
/* 9.4.11 CCCH Load Indication Period */
if (TLVP_PRES_LEN(&tp, NM_ATT_CCCH_L_I_P, 1)) {
bts->load.ccch.load_ind_period = *TLVP_VAL(&tp, NM_ATT_CCCH_L_I_P);
- load_timer_start(bts);
+ if (load_timer_is_running(bts)) {
+ load_timer_stop(bts);
+ load_timer_start(bts);
+ }
}
/* 9.4.44 RACH Busy Threshold */
@@ -677,26 +1049,64 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
if (TLVP_PRES_LEN(&tp, NM_ATT_BTS_AIR_TIMER, 1)) {
uint8_t t3105 = *TLVP_VAL(&tp, NM_ATT_BTS_AIR_TIMER);
if (t3105 == 0) {
- LOGPFOH(DOML, LOGL_NOTICE, foh, "T3105 must have a value != 0.\n");
+ LOGPFOH(DOML, LOGL_NOTICE, foh, "T3105 must have a value != 0\n");
return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE);
}
bts->t3105_ms = t3105 * 10;
+ /* there are no OML IEs for T3115; let's use T3105 as HO detection is a similar procedure */
+ bts->t3115_ms = bts->t3105_ms;
}
/* 9.4.37 NY1 */
- if (TLVP_PRES_LEN(&tp, NM_ATT_NY1, 1))
+ if (TLVP_PRES_LEN(&tp, NM_ATT_NY1, 1)) {
bts->ny1 = *TLVP_VAL(&tp, NM_ATT_NY1);
+ /* there are no OML IEs for NY2; let's use NY1 as HO detection is a similar procedure */
+ bts->ny2 = bts->ny1;
+ }
/* 9.4.8 BCCH ARFCN */
if (TLVP_PRES_LEN(&tp, NM_ATT_BCCH_ARFCN, 2))
bts->c0->arfcn = ntohs(tlvp_val16_unal(&tp, NM_ATT_BCCH_ARFCN));
/* 9.4.9 BSIC */
- if (TLVP_PRES_LEN(&tp, NM_ATT_BSIC, 1))
+ if (TLVP_PRES_LEN(&tp, NM_ATT_BSIC, 1)) {
+ struct gsm_bts_trx *trx;
+ uint8_t bts_tsc;
+
bts->bsic = *TLVP_VAL(&tp, NM_ATT_BSIC);
+ bts->bsic_configured = true;
+ bts_tsc = BTS_TSC(bts);
+
+ /* Apply TSC update on each TS if required: */
+ llist_for_each_entry(trx, &bts->trx_list, list) { /* C0..n */
+ unsigned int tn;
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ /* First some config validation: */
+ if (ts->tsc_oml_configured &&
+ ts->tsc_oml != bts_tsc &&
+ !osmo_bts_has_feature(bts->features, BTS_FEAT_MULTI_TSC)) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET BTS ATTR: this BTS model does not "
+ "support TSC %u != BSIC-BCC %u (TSC %u)\n",
+ ts->tsc_oml, bts->bsic, bts_tsc);
+ return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE);
+ }
+
+ /* Now update TS TSC if needed: */
+ gsm_ts_apply_configured_tsc(ts);
+ }
+ }
+ }
+
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
- /* call into BTS driver to apply new attributes to hardware */
- return bts_model_apply_oml(bts, msg, tp_merged, NM_OC_BTS, bts);
+ rc = osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
+ return rc;
}
/* 8.6.2 Set Radio Attributes has been received */
@@ -705,6 +1115,7 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
struct abis_om_fom_hdr *foh = msgb_l3(msg);
struct tlv_parsed tp, *tp_merged;
int rc;
+ struct nm_fsm_ev_setattr_data ev_data;
DEBUGPFOH(DOML, foh, "Rx SET RADIO CARRIER ATTR\n");
@@ -716,8 +1127,9 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
}
- /* merge existing BTS attributes with new attributes */
- tp_merged = osmo_tlvp_copy(trx->mo.nm_attr, trx->bts);
+ /* merge existing TRX attributes with new attributes */
+ tp_merged = osmo_tlvp_copy(trx->mo.nm_attr, trx);
+ talloc_set_name_const(tp_merged, "oml_trx_attr");
osmo_tlvp_merge(tp_merged, &tp);
/* Ask BTS driver to validate new merged attributes */
@@ -727,7 +1139,7 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
return oml_fom_ack_nack(msg, -rc);
}
- /* Success: replace old BTS attributes with new */
+ /* Success: replace old TRX attributes with new */
talloc_free(trx->mo.nm_attr);
trx->mo.nm_attr = tp_merged;
@@ -773,22 +1185,33 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
memcpy(&_value, value, 2);
arfcn = ntohs(_value);
value += 2;
- if (arfcn > 1024) {
+ if (arfcn >= 1024) { /* 0 .. 1023 (1024 channels total) */
oml_tx_failure_event_rep(&trx->bts->mo, NM_SEVER_MAJOR, OSMO_EVT_WARN_SW_WARN,
"Given ARFCN %u is unsupported", arfcn);
- LOGPFOH(DOML, LOGL_NOTICE, foh, "Given ARFCN %u is unsupported.\n", arfcn);
+ LOGPFOH(DOML, LOGL_NOTICE, foh, "Given ARFCN %u is unsupported\n", arfcn);
return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL);
}
trx->arfcn = arfcn;
}
#endif
- /* call into BTS driver to apply new attributes to hardware */
- return bts_model_apply_oml(trx->bts, msg, tp_merged, NM_OC_RADIO_CARRIER, trx);
+
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
+
+ rc = osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
+ return rc;
+
}
-static int conf_lchans(struct gsm_bts_trx_ts *ts)
+static int handle_chan_comb(struct gsm_bts_trx_ts *ts, const uint8_t comb)
{
- enum gsm_phys_chan_config pchan = ts->pchan;
+ enum gsm_phys_chan_config pchan;
+
+ pchan = abis_nm_pchan4chcomb(comb);
+ ts->pchan = pchan;
/* RSL_MT_IPAC_PDCH_ACT style dyn PDCH */
if (pchan == GSM_PCHAN_TCH_F_PDCH)
@@ -796,7 +1219,7 @@ static int conf_lchans(struct gsm_bts_trx_ts *ts)
: GSM_PCHAN_TCH_F;
/* Osmocom RSL CHAN ACT style dyn TS */
- if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ if (pchan == GSM_PCHAN_OSMO_DYN) {
pchan = ts->dyn.pchan_is;
/* If the dyn TS doesn't have a pchan yet, do nothing. */
@@ -807,62 +1230,65 @@ static int conf_lchans(struct gsm_bts_trx_ts *ts)
return conf_lchans_as_pchan(ts, pchan);
}
+static inline void lchans_type_set(struct gsm_bts_trx_ts *ts,
+ enum gsm_chan_t lchan_type,
+ unsigned int num_lchans)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_lchans; i++)
+ ts->lchan[i].type = lchan_type;
+}
+
int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
enum gsm_phys_chan_config pchan)
{
- struct gsm_lchan *lchan;
- unsigned int i;
+ /* Initialize all lchans with GSM_LCHAN_NONE first */
+ lchans_type_set(ts, GSM_LCHAN_NONE, ARRAY_SIZE(ts->lchan));
switch (pchan) {
case GSM_PCHAN_CCCH_SDCCH4_CBCH:
- /* fallthrough */
case GSM_PCHAN_CCCH_SDCCH4:
- for (i = 0; i < 4; i++) {
- lchan = &ts->lchan[i];
- if (pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH
- && i == 2) {
- lchan->type = GSM_LCHAN_CBCH;
- } else {
- lchan->type = GSM_LCHAN_SDCCH;
- }
- }
+ lchans_type_set(ts, GSM_LCHAN_SDCCH, 4);
+ if (pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH)
+ ts->lchan[2].type = GSM_LCHAN_CBCH;
/* fallthrough */
case GSM_PCHAN_CCCH:
- lchan = &ts->lchan[CCCH_LCHAN];
- lchan->type = GSM_LCHAN_CCCH;
+ ts->lchan[CCCH_LCHAN].type = GSM_LCHAN_CCCH;
break;
case GSM_PCHAN_TCH_F:
- lchan = &ts->lchan[0];
- lchan->type = GSM_LCHAN_TCH_F;
+ if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_F, 1);
+ ts->vamos.peer->pchan = GSM_PCHAN_TCH_F;
+ }
+ lchans_type_set(ts, GSM_LCHAN_TCH_F, 1);
break;
case GSM_PCHAN_TCH_H:
- for (i = 0; i < 2; i++) {
- lchan = &ts->lchan[i];
- lchan->type = GSM_LCHAN_TCH_H;
+ if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_H, 2);
+ ts->vamos.peer->pchan = GSM_PCHAN_TCH_H;
}
+ lchans_type_set(ts, GSM_LCHAN_TCH_H, 2);
break;
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
- /* fallthrough */
case GSM_PCHAN_SDCCH8_SACCH8C:
- for (i = 0; i < 8; i++) {
- lchan = &ts->lchan[i];
- if (pchan == GSM_PCHAN_SDCCH8_SACCH8C_CBCH
- && i == 2) {
- lchan->type = GSM_LCHAN_CBCH;
- } else {
- lchan->type = GSM_LCHAN_SDCCH;
- }
- }
+ lchans_type_set(ts, GSM_LCHAN_SDCCH, 8);
+ if (pchan == GSM_PCHAN_SDCCH8_SACCH8C_CBCH)
+ ts->lchan[2].type = GSM_LCHAN_CBCH;
break;
case GSM_PCHAN_PDCH:
- lchan = &ts->lchan[0];
- lchan->type = GSM_LCHAN_PDTCH;
+ if (ts->vamos.peer != NULL) { /* VAMOS: disable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_NONE, 1);
+ ts->vamos.peer->pchan = GSM_PCHAN_NONE;
+ }
+ lchans_type_set(ts, GSM_LCHAN_PDTCH, 1);
break;
default:
LOGP(DOML, LOGL_ERROR, "Unknown/unhandled PCHAN type: %u %s\n",
ts->pchan, gsm_pchan_name(ts->pchan));
return -NM_NACK_PARAM_RANGE;
}
+
return 0;
}
@@ -872,7 +1298,8 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
struct abis_om_fom_hdr *foh = msgb_l3(msg);
struct gsm_bts *bts = ts->trx->bts;
struct tlv_parsed tp, *tp_merged;
- int rc;
+ int rc, i;
+ struct nm_fsm_ev_setattr_data ev_data;
DEBUGPFOH(DOML, foh, "Rx SET CHAN ATTR\n");
@@ -883,21 +1310,50 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
}
- /* 9.4.21 HSN... */
- /* 9.4.27 MAIO */
+ /* Check frequency hopping parameters (HSN, MAIO, ARFCN list) */
if (TLVP_PRESENT(&tp, NM_ATT_HSN) || TLVP_PRESENT(&tp, NM_ATT_MAIO)) {
- LOGPFOH(DOML, LOGL_NOTICE, foh, "SET CHAN ATTR: Frequency hopping not supported.\n");
- return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_HOPPING)) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: Frequency hopping not supported\n");
+ return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
+ }
+
+ if (!TLVP_PRES_LEN(&tp, NM_ATT_HSN, 1) || !TLVP_PRES_LEN(&tp, NM_ATT_MAIO, 1)) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: HSN and/or MAIO is missing: "
+ "hsn=%u, maio=%u\n", TLVP_LEN(&tp, NM_ATT_HSN), TLVP_LEN(&tp, NM_ATT_MAIO));
+ return oml_fom_ack_nack(msg, NM_NACK_ATTRLIST_INCONSISTENT);
+ }
+
+ if (!TLVP_PRES_LEN(&tp, NM_ATT_ARFCN_LIST, 2)) { /* At least one ARFCN */
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: ARFCN list is missing\n");
+ return oml_fom_ack_nack(msg, NM_NACK_ATTRLIST_INCONSISTENT);
+ }
+
+ if (TLVP_LEN(&tp, NM_ATT_ARFCN_LIST) > sizeof(ts->hopping.arfcn_list)) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: ARFCN list is too long\n");
+ return oml_fom_ack_nack(msg, NM_NACK_ATTRLIST_INCONSISTENT);
+ } else if (TLVP_LEN(&tp, NM_ATT_ARFCN_LIST) % 2 != 0) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: ARFCN list has odd length\n");
+ return oml_fom_ack_nack(msg, NM_NACK_ATTRLIST_INCONSISTENT);
+ }
+
+ ts->hopping.enabled = true;
+ ts->hopping.hsn = *TLVP_VAL(&tp, NM_ATT_HSN);
+ ts->hopping.maio = *TLVP_VAL(&tp, NM_ATT_MAIO);
+
+ ts->hopping.arfcn_num = TLVP_LEN(&tp, NM_ATT_ARFCN_LIST) / sizeof(uint16_t);
+ for (i = 0; i < ts->hopping.arfcn_num; i++)
+ ts->hopping.arfcn_list[i] = osmo_load16be(TLVP_VAL(&tp, NM_ATT_ARFCN_LIST) + i * 2);
}
/* 9.4.52 Starting Time */
if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) {
- LOGPFOH(DOML, LOGL_NOTICE, foh, "SET CHAN ATTR: Starting time not supported.\n");
+ LOGPFOH(DOML, LOGL_NOTICE, foh, "SET CHAN ATTR: Starting time not supported\n");
return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
}
- /* merge existing BTS attributes with new attributes */
- tp_merged = osmo_tlvp_copy(ts->mo.nm_attr, bts);
+ /* merge existing CHAN attributes with new attributes */
+ tp_merged = osmo_tlvp_copy(ts->mo.nm_attr, ts->trx);
+ talloc_set_name_const(tp_merged, "oml_chan_attr");
osmo_tlvp_merge(tp_merged, &tp);
/* Call into BTS driver to check attribute values */
@@ -909,18 +1365,16 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
return oml_fom_ack_nack(msg, -rc);
}
- /* Success: replace old BTS attributes with new */
+ /* Success: replace old CHAN attributes with new */
talloc_free(ts->mo.nm_attr);
ts->mo.nm_attr = tp_merged;
/* 9.4.13 Channel Combination */
if (TLVP_PRES_LEN(&tp, NM_ATT_CHAN_COMB, 1)) {
- uint8_t comb = *TLVP_VAL(&tp, NM_ATT_CHAN_COMB);
- ts->pchan = abis_nm_pchan4chcomb(comb);
- rc = conf_lchans(ts);
- if (rc < 0) {
+ const uint8_t comb = *TLVP_VAL(&tp, NM_ATT_CHAN_COMB);
+ if ((rc = handle_chan_comb(ts, comb)) != 0) {
LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: invalid Chan Comb 0x%x"
- " (pchan=%s, conf_lchans()->%d)\n",
+ " (pchan=%s, handle_chan_comb() returns %d)\n",
comb, gsm_pchan_name(ts->pchan), rc);
talloc_free(tp_merged);
/* Send NACK */
@@ -928,20 +1382,40 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
}
}
- /* 9.4.5 ARFCN List */
-
/* 9.4.60 TSC */
if (TLVP_PRES_LEN(&tp, NM_ATT_TSC, 1)) {
- ts->tsc = *TLVP_VAL(&tp, NM_ATT_TSC);
- } else {
- /* If there is no TSC specified, use the BCC */
- ts->tsc = BSIC2BCC(bts->bsic);
+ ts->tsc_oml = *TLVP_VAL(&tp, NM_ATT_TSC);
+ ts->tsc_oml_configured = true;
+ }
+
+ if (ts->tsc_oml_configured) {
+ if (bts->bsic_configured &&
+ ts->tsc_oml != BTS_TSC(bts) &&
+ !osmo_bts_has_feature(bts->features, BTS_FEAT_MULTI_TSC)) {
+ LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: this BTS model does not "
+ "support TSC %u != BSIC-BCC %u\n", ts->tsc_oml, BTS_TSC(bts));
+ talloc_free(tp_merged);
+ return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE);
+ }
+ gsm_ts_apply_configured_tsc(ts);
}
- LOGPFOH(DOML, LOGL_INFO, foh, "%s SET CHAN ATTR (TSC=%u pchan=%s)\n",
- gsm_abis_mo_name(&ts->mo), ts->tsc, gsm_pchan_name(ts->pchan));
- /* call into BTS driver to apply new attributes to hardware */
- return bts_model_apply_oml(bts, msg, tp_merged, NM_OC_CHANNEL, ts);
+ LOGPFOH(DOML, LOGL_INFO, foh, "SET CHAN ATTR (TSC=%d pchan=%s",
+ ts->tsc_oml_configured ? (int)ts->tsc_oml : -1,
+ gsm_pchan_name(ts->pchan));
+ if (ts->hopping.enabled)
+ LOGPC(DOML, LOGL_INFO, " hsn=%u maio=%u chan_num=%u",
+ ts->hopping.hsn, ts->hopping.maio, ts->hopping.arfcn_num);
+ LOGPC(DOML, LOGL_INFO, ")\n");
+
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
+
+ rc = osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
+ return rc;
}
/* 8.9.2 Opstart has been received */
@@ -950,14 +1424,16 @@ static int oml_rx_opstart(struct gsm_bts *bts, struct msgb *msg)
struct abis_om_fom_hdr *foh = msgb_l3(msg);
struct gsm_abis_mo *mo;
void *obj;
+ int rc;
+ enum abis_nm_nack_cause c;
DEBUGPFOH(DOML, foh, "Rx OPSTART\n");
/* Step 1: Resolve MO by obj_class/obj_inst */
- mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
- obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
- if (!mo || !obj)
- return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ if ((mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
+ if ((obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
/* Step 2: Do some global dependency/consistency checking */
if (mo->nm_state.operational == NM_OPSTATE_ENABLED) {
@@ -965,8 +1441,13 @@ static int oml_rx_opstart(struct gsm_bts *bts, struct msgb *msg)
return oml_mo_opstart_ack(mo);
}
- /* Step 3: Ask BTS driver to apply the opstart */
- return bts_model_opstart(bts, mo, obj);
+ /* Make sure all NM objects already have an FSM implemented: */
+ OSMO_ASSERT(mo->fi);
+
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_RX_OPSTART, NULL);
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
+ return rc;
}
static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg)
@@ -977,6 +1458,7 @@ static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg)
uint8_t adm_state;
void *obj;
int rc;
+ enum abis_nm_nack_cause c;
DEBUGPFOH(DOML, foh, "Rx CHG ADM STATE\n");
@@ -994,15 +1476,20 @@ static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg)
adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
/* Step 1: Resolve MO by obj_class/obj_inst */
- mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
- obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
- if (!mo || !obj)
- return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ if ((mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
+ if ((obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
/* Step 2: Do some global dependency/consistency checking */
- if (mo->nm_state.administrative == adm_state)
+ if (mo->nm_state.administrative == adm_state) {
LOGPFOH(DOML, LOGL_NOTICE, foh, "ADM state already was %s\n",
get_value_string(abis_nm_adm_state_names, adm_state));
+ return oml_mo_statechg_ack(mo);
+ }
+ LOGPFOH(DOML, LOGL_NOTICE, foh, "ADM STATE %s -> %s\n",
+ get_value_string(abis_nm_adm_state_names, mo->nm_state.administrative),
+ get_value_string(abis_nm_adm_state_names, adm_state));
/* Step 3: Ask BTS driver to apply the state chg */
return bts_model_chg_adm_state(bts, mo, obj, adm_state);
@@ -1114,16 +1601,21 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg)
* manufacturer related messages
*/
-static int oml_ipa_mo_set_attr_nse(void *obj, struct tlv_parsed *tp)
+static int oml_ipa_mo_set_attr_nse(void *obj,
+ const struct msgb *msg,
+ const struct tlv_parsed *tp)
{
- struct gsm_bts *bts = container_of(obj, struct gsm_bts, gprs.nse);
+ struct gsm_gprs_nse *nse = obj;
+ struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
+ struct nm_fsm_ev_setattr_data ev_data;
+ int rc;
if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_NSEI, 2))
- bts->gprs.nse.nsei =
+ nse->nsei =
ntohs(tlvp_val16_unal(tp, NM_ATT_IPACC_NSEI));
if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_NS_CFG, 7)) {
- memcpy(&bts->gprs.nse.timer,
+ memcpy(&nse->timer,
TLVP_VAL(tp, NM_ATT_IPACC_NS_CFG), 7);
}
@@ -1132,15 +1624,27 @@ static int oml_ipa_mo_set_attr_nse(void *obj, struct tlv_parsed *tp)
TLVP_VAL(tp, NM_ATT_IPACC_BSSGP_CFG), 11);
}
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
+ rc = osmo_fsm_inst_dispatch(nse->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return NM_NACK_CANT_PERFORM;
+
osmo_signal_dispatch(SS_GLOBAL, S_NEW_NSE_ATTR, bts);
return 0;
}
-static int oml_ipa_mo_set_attr_cell(void *obj, struct tlv_parsed *tp)
+static int oml_ipa_mo_set_attr_cell(void *obj,
+ const struct msgb *msg,
+ const struct tlv_parsed *tp)
{
- struct gsm_bts *bts = container_of(obj, struct gsm_bts, gprs.cell);
- struct gprs_rlc_cfg *rlcc = &bts->gprs.cell.rlc_cfg;
+ struct gsm_gprs_cell *gprs_cell = obj;
+ struct gsm_bts *bts = gsm_gprs_cell_get_bts(gprs_cell);
+ struct gprs_rlc_cfg *rlcc = &gprs_cell->rlc_cfg;
+ struct nm_fsm_ev_setattr_data ev_data;
+ int rc;
const uint8_t *cur;
uint16_t _cur_s;
@@ -1154,8 +1658,7 @@ static int oml_ipa_mo_set_attr_cell(void *obj, struct tlv_parsed *tp)
}
if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_BVCI, 2))
- bts->gprs.cell.bvci =
- ntohs(tlvp_val16_unal(tp, NM_ATT_IPACC_BVCI));
+ gprs_cell->bvci = ntohs(tlvp_val16_unal(tp, NM_ATT_IPACC_BVCI));
if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_RLC_CFG, 9)) {
cur = TLVP_VAL(tp, NM_ATT_IPACC_RLC_CFG);
@@ -1202,14 +1705,25 @@ static int oml_ipa_mo_set_attr_cell(void *obj, struct tlv_parsed *tp)
rlcc->initial_mcs = *TLVP_VAL(tp, NM_ATT_IPACC_RLC_CFG_3);
}
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
+ rc = osmo_fsm_inst_dispatch(gprs_cell->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return NM_NACK_CANT_PERFORM;
+
osmo_signal_dispatch(SS_GLOBAL, S_NEW_CELL_ATTR, bts);
return 0;
}
-static int oml_ipa_mo_set_attr_nsvc(struct gsm_bts_gprs_nsvc *nsvc,
- struct tlv_parsed *tp)
+static int oml_ipa_mo_set_attr_nsvc(struct gsm_gprs_nsvc *nsvc,
+ const struct msgb *msg,
+ const struct tlv_parsed *tp)
{
+ struct nm_fsm_ev_setattr_data ev_data;
+ int rc;
+
if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_NSVCI, 2))
nsvc->nsvci = ntohs(tlvp_val16_unal(tp, NM_ATT_IPACC_NSVCI));
@@ -1218,41 +1732,69 @@ static int oml_ipa_mo_set_attr_nsvc(struct gsm_bts_gprs_nsvc *nsvc,
uint16_t _cur_s;
uint32_t _cur_l;
+ memset(&nsvc->local, 0, sizeof(nsvc->local));
+ memset(&nsvc->remote, 0, sizeof(nsvc->remote));
+
+ nsvc->local.u.sin.sin_family = AF_INET;
+ nsvc->remote.u.sin.sin_family = AF_INET;
+
memcpy(&_cur_s, cur, 2);
- nsvc->remote_port = ntohs(_cur_s);
+ nsvc->remote.u.sin.sin_port = _cur_s;
cur += 2;
memcpy(&_cur_l, cur, 4);
- nsvc->remote_ip = ntohl(_cur_l);
+ nsvc->remote.u.sin.sin_addr.s_addr = _cur_l;
cur += 4;
memcpy(&_cur_s, cur, 2);
- nsvc->local_port = ntohs(_cur_s);
+ nsvc->local.u.sin.sin_port = _cur_s;
}
- osmo_signal_dispatch(SS_GLOBAL, S_NEW_NSVC_ATTR, nsvc);
+ if (TLVP_PRES_LEN(tp, NM_ATT_OSMO_NS_LINK_CFG, 10)) {
+ const uint8_t *cur = TLVP_VAL(tp, NM_ATT_OSMO_NS_LINK_CFG);
+ uint8_t address_family;
- return 0;
-}
+ memset(&nsvc->local, 0, sizeof(nsvc->local));
+ memset(&nsvc->remote, 0, sizeof(nsvc->remote));
-static int oml_ipa_mo_set_attr(struct gsm_bts *bts, const struct gsm_abis_mo *mo,
- void *obj, struct tlv_parsed *tp)
-{
- int rc;
+ address_family = *cur;
+ /* 1byte padding */
+ cur += 2;
- switch (mo->obj_class) {
- case NM_OC_GPRS_NSE:
- rc = oml_ipa_mo_set_attr_nse(obj, tp);
- break;
- case NM_OC_GPRS_CELL:
- rc = oml_ipa_mo_set_attr_cell(obj, tp);
- break;
- case NM_OC_GPRS_NSVC:
- rc = oml_ipa_mo_set_attr_nsvc(obj, tp);
- break;
- default:
- rc = NM_NACK_OBJINST_UNKN;
+ memcpy(&nsvc->local.u.sin.sin_port, cur, 2);
+ cur += 2;
+
+ memcpy(&nsvc->remote.u.sin.sin_port, cur, 2);
+ cur += 2;
+
+ switch (address_family) {
+ case OSMO_NSVC_ADDR_IPV4:
+ /* we already checked for 10 bytes */
+ nsvc->remote.u.sas.ss_family = AF_INET;
+ nsvc->local.u.sas.ss_family = AF_INET;
+ memcpy(&nsvc->remote.u.sin.sin_addr.s_addr, cur, sizeof(in_addr_t));
+ break;
+ case OSMO_NSVC_ADDR_IPV6:
+ if (TLVP_LEN(tp, NM_ATT_OSMO_NS_LINK_CFG) < 22) {
+ return -1;
+ }
+ nsvc->remote.u.sas.ss_family = AF_INET6;
+ nsvc->local.u.sas.ss_family = AF_INET6;
+ memcpy(&nsvc->remote.u.sin6.sin6_addr, cur, sizeof(struct in6_addr));
+ break;
+ default:
+ return -1;
+ }
}
- return rc;
+ ev_data = (struct nm_fsm_ev_setattr_data){
+ .msg = msg,
+ };
+ rc = osmo_fsm_inst_dispatch(nsvc->mo.fi, NM_EV_RX_SETATTR, &ev_data);
+ if (rc < 0)
+ return NM_NACK_CANT_PERFORM;
+
+ osmo_signal_dispatch(SS_GLOBAL, S_NEW_NSVC_ATTR, nsvc);
+
+ return 0;
}
static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg)
@@ -1262,75 +1804,107 @@ static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg)
struct tlv_parsed tp, *tp_merged;
void *obj;
int rc;
+ enum abis_nm_nack_cause c;
DEBUGPFOH(DOML, foh, "Rx IPA SET ATTR\n");
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
if (rc < 0) {
- mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
- if (!mo)
- return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ if ((mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
oml_tx_failure_event_rep(mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UNSUP_ATTR,
"New value for IPAC Set Attribute not supported\n");
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
}
/* Resolve MO by obj_class/obj_inst */
- mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
- obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
- if (!mo || !obj)
- return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ if ((mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
+ if ((obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst, &c)) == NULL)
+ return oml_fom_ack_nack(msg, c);
+
- rc = oml_ipa_mo_set_attr(bts, mo, obj, &tp);
- if (rc == 0) {
- /* Success: replace old MO attributes with new */
- /* merge existing MO attributes with new attributes */
- tp_merged = osmo_tlvp_copy(mo->nm_attr, bts);
- osmo_tlvp_merge(tp_merged, &tp);
- talloc_free(mo->nm_attr);
- mo->nm_attr = tp_merged;
+ switch (mo->obj_class) {
+ case NM_OC_GPRS_NSE:
+ rc = oml_ipa_mo_set_attr_nse(obj, msg, &tp);
+ break;
+ case NM_OC_GPRS_CELL:
+ rc = oml_ipa_mo_set_attr_cell(obj, msg, &tp);
+ break;
+ case NM_OC_GPRS_NSVC:
+ rc = oml_ipa_mo_set_attr_nsvc(obj, msg, &tp);
+ break;
+ default:
+ rc = NM_NACK_OBJINST_UNKN;
}
- return oml_fom_ack_nack(msg, rc);
+ if (rc != 0)
+ return oml_fom_ack_nack(msg, rc);
+
+ /* Success: replace old MO attributes with new */
+ /* merge existing MO attributes with new attributes */
+ tp_merged = osmo_tlvp_copy(mo->nm_attr, bts);
+ talloc_set_name_const(tp_merged, "oml_ipa_attr");
+ osmo_tlvp_merge(tp_merged, &tp);
+ talloc_free(mo->nm_attr);
+ mo->nm_attr = tp_merged;
+
+ return rc;
}
-static int rx_oml_ipa_rsl_connect(struct gsm_bts_trx *trx, struct msgb *msg,
- struct tlv_parsed *tp)
+static int rx_oml_ipa_rsl_connect(struct gsm_bts *bts, struct msgb *msg,
+ const struct tlv_parsed *tp)
{
- struct e1inp_sign_link *oml_link = trx->bts->oml_link;
- uint16_t port = IPA_TCP_PORT_RSL;
- uint32_t ip = get_signlink_remote_ip(oml_link);
- const char *trx_name = gsm_trx_name(trx);
+ struct e1inp_sign_link *oml_link = bts->oml_link;
+ const struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ struct gsm_bts_bb_trx *bb_transc;
+ const char *trx_name;
struct in_addr in;
+ uint16_t port = IPA_TCP_PORT_RSL;
+ uint8_t stream_id = 0;
int rc;
- uint8_t stream_id = 0;
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP))
+ in.s_addr = tlvp_val32_unal(tp, NM_ATT_IPACC_DST_IP);
+ else
+ in.s_addr = htonl(get_signlink_remote_ip(oml_link));
- if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_DST_IP, 4)) {
- ip = ntohl(tlvp_val32_unal(tp, NM_ATT_IPACC_DST_IP));
- }
- if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_DST_IP_PORT, 2)) {
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP_PORT))
port = ntohs(tlvp_val16_unal(tp, NM_ATT_IPACC_DST_IP_PORT));
- }
- if (TLVP_PRES_LEN(tp, NM_ATT_IPACC_STREAM_ID, 1)) {
+
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_STREAM_ID))
stream_id = *TLVP_VAL(tp, NM_ATT_IPACC_STREAM_ID);
+
+ if (!trx) {
+ LOGP(DOML, LOGL_ERROR, "Rx IPA RSL CONNECT IP=%s PORT=%u STREAM=0x%02x for unknown TRX_NR=%u\n",
+ inet_ntoa(in), port, stream_id, foh->obj_inst.trx_nr);
+ rc = NM_NACK_TRXNR_UNKN;
+ goto tx_ack_nack;
}
- in.s_addr = htonl(ip);
- LOGP(DOML, LOGL_INFO, "%s: Rx IPA RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
- trx_name, inet_ntoa(in), port, stream_id);
+ bb_transc = &trx->bb_transc;
+ osmo_sockaddr_str_from_in_addr(&bb_transc->rsl.rem_addrstr, &in, port);
+ bb_transc->rsl.tei = stream_id;
- if (trx->bts->variant == BTS_OSMO_OMLDUMMY) {
- rc = 0;
- LOGP(DOML, LOGL_NOTICE, "%s: Not connecting RSL in OML-DUMMY!\n", trx_name);
- } else
- rc = e1inp_ipa_bts_rsl_connect_n(oml_link->ts->line, inet_ntoa(in), port, trx->nr);
- if (rc < 0) {
- LOGP(DOML, LOGL_ERROR, "%s: Error in abis_open(RSL): %d\n", trx_name, rc);
- return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
- }
+ trx_name = gsm_trx_name(trx);
+ LOGP(DOML, LOGL_INFO, "%s: Rx IPA RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
+ trx_name, bb_transc->rsl.rem_addrstr.ip, bb_transc->rsl.rem_addrstr.port,
+ bb_transc->rsl.tei);
+
+ rc = 0;
- return oml_fom_ack_nack(msg, 0);
+tx_ack_nack:
+ /* The ACK/NACK is expected to contain all IEs */
+ if (!TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP)) /* TV32 */
+ msgb_tv_fixed_put(msg, NM_ATT_IPACC_DST_IP, sizeof(in),
+ (const uint8_t *) &in);
+ if (!TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP_PORT)) /* TV16 */
+ msgb_tv16_put(msg, NM_ATT_IPACC_DST_IP_PORT, port);
+ if (!TLVP_PRESENT(tp, NM_ATT_IPACC_STREAM_ID)) /* TV */
+ msgb_tv_put(msg, NM_ATT_IPACC_STREAM_ID, stream_id);
+
+ return oml_fom_ack_nack(msg, rc);
}
static int down_mom(struct gsm_bts *bts, struct msgb *msg)
@@ -1379,8 +1953,7 @@ static int down_mom(struct gsm_bts *bts, struct msgb *msg)
switch (foh->msg_type) {
case NM_MT_IPACC_RSL_CONNECT:
- trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
- ret = rx_oml_ipa_rsl_connect(trx, msg, &tp);
+ ret = rx_oml_ipa_rsl_connect(bts, msg, &tp);
break;
case NM_MT_IPACC_SET_ATTR:
ret = oml_ipa_set_attr(bts, msg);
@@ -1452,16 +2025,144 @@ int down_oml(struct gsm_bts *bts, struct msgb *msg)
ret = -EINVAL;
}
+ /* msgb was reused, do not free() */
+ if (ret == 1)
+ return 0;
+
msgb_free(msg);
return ret;
}
-int oml_init(struct gsm_abis_mo *mo)
+int oml_init()
{
DEBUGP(DOML, "Initializing OML attribute definitions\n");
tlv_def_patch(&abis_nm_att_tlvdef_ipa_local, &abis_nm_att_tlvdef_ipa);
tlv_def_patch(&abis_nm_att_tlvdef_ipa_local, &abis_nm_att_tlvdef);
+ tlv_def_patch(&abis_nm_att_tlvdef_ipa_local, &abis_nm_osmo_att_tlvdef);
return 0;
}
+
+void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
+ uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3)
+{
+ mo->bts = bts;
+ mo->obj_class = obj_class;
+ mo->obj_inst.bts_nr = p1;
+ mo->obj_inst.trx_nr = p2;
+ mo->obj_inst.ts_nr = p3;
+ mo->nm_state.operational = NM_OPSTATE_DISABLED;
+ mo->nm_state.availability = NM_AVSTATE_POWER_OFF;
+ mo->nm_state.administrative = NM_STATE_LOCKED;
+}
+
+/* Obtain the MO structure for a given object instance
+ * \param[out] c nack cause for reply in case of error. Ignored if NULL */
+struct gsm_abis_mo *gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
+ const struct abis_om_obj_inst *obj_inst,
+ enum abis_nm_nack_cause *c)
+{
+ struct gsm_bts_trx *trx;
+
+ switch ((enum abis_nm_obj_class)obj_class) {
+ case NM_OC_BTS:
+ return &bts->mo;
+ case NM_OC_RADIO_CARRIER:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ return &trx->mo;
+ case NM_OC_BASEB_TRANSC:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ return &trx->bb_transc.mo;
+ case NM_OC_CHANNEL:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ if (obj_inst->ts_nr >= TRX_NR_TS)
+ goto nm_nack_objinst_unkn;
+ return &trx->ts[obj_inst->ts_nr].mo;
+ case NM_OC_SITE_MANAGER:
+ return &g_bts_sm->mo;
+ case NM_OC_GPRS_NSE:
+ if (obj_inst->bts_nr > 0)
+ goto nm_nack_objinst_unkn;
+ return &g_bts_sm->gprs.nse.mo;
+ case NM_OC_GPRS_CELL:
+ return &bts->gprs.cell.mo;
+ case NM_OC_GPRS_NSVC:
+ if (obj_inst->bts_nr > 0)
+ goto nm_nack_objinst_unkn;
+ if (obj_inst->trx_nr >= ARRAY_SIZE(g_bts_sm->gprs.nse.nsvc))
+ goto nm_nack_objinst_unkn;
+ return &g_bts_sm->gprs.nse.nsvc[obj_inst->trx_nr].mo;
+ default:
+ if (c != NULL)
+ *c = NM_NACK_OBJCLASS_NOTSUPP;
+ return NULL;
+ }
+
+nm_nack_trxnr_unkn:
+ if (c != NULL)
+ *c = NM_NACK_TRXNR_UNKN;
+ return NULL;
+nm_nack_objinst_unkn:
+ if (c != NULL)
+ *c = NM_NACK_OBJINST_UNKN;
+ return NULL;
+}
+
+/* Obtain the in-memory data structure of a given object instance
+ * \param[out] c nack cause for reply in case of error. Ignored if NULL */
+void *gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
+ const struct abis_om_obj_inst *obj_inst,
+ enum abis_nm_nack_cause *c)
+{
+ struct gsm_bts_trx *trx;
+
+ switch ((enum abis_nm_obj_class)obj_class) {
+ case NM_OC_BTS:
+ return bts;
+ case NM_OC_RADIO_CARRIER:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ return trx;
+ case NM_OC_BASEB_TRANSC:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ return &trx->bb_transc;
+ case NM_OC_CHANNEL:
+ if (!(trx = gsm_bts_trx_num(bts, obj_inst->trx_nr)))
+ goto nm_nack_trxnr_unkn;
+ if (obj_inst->ts_nr >= TRX_NR_TS)
+ goto nm_nack_objinst_unkn;
+ return &trx->ts[obj_inst->ts_nr];
+ case NM_OC_SITE_MANAGER:
+ return g_bts_sm;
+ case NM_OC_GPRS_NSE:
+ if (obj_inst->bts_nr > 0)
+ goto nm_nack_objinst_unkn;
+ return &g_bts_sm->gprs.nse;
+ case NM_OC_GPRS_CELL:
+ return &bts->gprs.cell;
+ case NM_OC_GPRS_NSVC:
+ if (obj_inst->bts_nr > 0)
+ goto nm_nack_objinst_unkn;
+ if (obj_inst->trx_nr >= ARRAY_SIZE(g_bts_sm->gprs.nse.nsvc))
+ goto nm_nack_objinst_unkn;
+ return &g_bts_sm->gprs.nse.nsvc[obj_inst->trx_nr];
+ default:
+ if (c != NULL)
+ *c = NM_NACK_OBJCLASS_NOTSUPP;
+ return NULL;
+ }
+
+nm_nack_trxnr_unkn:
+ if (c != NULL)
+ *c = NM_NACK_TRXNR_UNKN;
+ return NULL;
+nm_nack_objinst_unkn:
+ if (c != NULL)
+ *c = NM_NACK_OBJINST_UNKN;
+ return NULL;
+}
diff --git a/src/common/osmux.c b/src/common/osmux.c
new file mode 100644
index 00000000..9513bdc4
--- /dev/null
+++ b/src/common/osmux.c
@@ -0,0 +1,545 @@
+/* Osmux related routines & logic */
+
+/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/netif/rtp.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/osmux.h>
+#include <osmo-bts/lchan.h>
+#include <osmo-bts/msg_utils.h>
+#include <osmo-bts/l1sap.h>
+
+/* Bitmask containing Allocated Osmux circuit ID. +7 to round up to 8 bit boundary. */
+static uint8_t osmux_cid_bitmap[OSMO_BYTES_FOR_BITS(OSMUX_CID_MAX + 1)];
+
+/*! Find and reserve a free OSMUX cid. Keep state of last allocated CID to
+ * rotate allocated CIDs over time. This helps in letting CIDs unused for some
+ * time after last use.
+ * \returns OSMUX cid */
+static int osmux_get_local_cid(void)
+{
+ static uint8_t next_free_osmux_cid_lookup = 0;
+ uint8_t start_i, start_j;
+ uint8_t i, j, cid;
+
+ /* i = octet index, j = bit index inside ith octet */
+ start_i = next_free_osmux_cid_lookup >> 3;
+ start_j = next_free_osmux_cid_lookup & 0x07;
+
+ for (i = start_i; i < sizeof(osmux_cid_bitmap); i++) {
+ for (j = start_j; j < 8; j++) {
+ if (osmux_cid_bitmap[i] & (1 << j))
+ continue;
+ goto found;
+ }
+ }
+
+ for (i = 0; i <= start_i; i++) {
+ for (j = 0; j < start_j; j++) {
+ if (osmux_cid_bitmap[i] & (1 << j))
+ continue;
+ goto found;
+ }
+ }
+
+ LOGP(DOSMUX, LOGL_ERROR, "All Osmux circuits are in use!\n");
+ return -1;
+
+found:
+ osmux_cid_bitmap[i] |= (1 << j);
+ cid = (i << 3) | j;
+ next_free_osmux_cid_lookup = (cid + 1) & 0xff;
+ LOGP(DOSMUX, LOGL_DEBUG,
+ "Allocating Osmux CID %u from pool\n", cid);
+ return cid;
+}
+
+/*! put back a no longer used OSMUX cid.
+ * \param[in] osmux_cid OSMUX cid */
+void osmux_put_local_cid(uint8_t osmux_cid)
+{
+ LOGP(DOSMUX, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
+ osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
+}
+
+/* Deliver OSMUX batch to the remote end */
+static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
+{
+ struct osmux_handle *handle = data;
+ struct gsm_bts *bts = handle->bts;
+ socklen_t dest_len;
+ ssize_t rc;
+
+ switch (handle->rem_addr.u.sa.sa_family) {
+ case AF_INET6:
+ dest_len = sizeof(handle->rem_addr.u.sin6);
+ break;
+ case AF_INET:
+ default:
+ dest_len = sizeof(handle->rem_addr.u.sin);
+ break;
+ }
+ rc = sendto(bts->osmux.fd.fd, batch_msg->data, batch_msg->len, 0,
+ (struct sockaddr *)&handle->rem_addr.u.sa, dest_len);
+ if (rc < 0) {
+ char errbuf[129];
+ strerror_r(errno, errbuf, sizeof(errbuf));
+ LOGP(DOSMUX, LOGL_ERROR, "osmux sendto(%s) failed: %s\n",
+ osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
+ }
+ msgb_free(batch_msg);
+}
+
+/* Lookup existing OSMUX handle for specified destination address. */
+static struct osmux_handle *osmux_handle_find_get(const struct gsm_bts *bts,
+ const struct osmo_sockaddr *rem_addr)
+{
+ struct osmux_handle *h;
+
+ llist_for_each_entry(h, &bts->osmux.osmux_handle_list, head) {
+ if (osmo_sockaddr_cmp(&h->rem_addr, rem_addr) == 0) {
+ LOGP(DOSMUX, LOGL_DEBUG,
+ "Using existing OSMUX handle for rem_addr=%s\n",
+ osmo_sockaddr_to_str(rem_addr));
+ h->refcnt++;
+ return h;
+ }
+ }
+
+ return NULL;
+}
+
+/* Put down no longer needed OSMUX handle */
+static void osmux_handle_put(struct gsm_bts *bts, struct osmux_in_handle *in)
+{
+ struct osmux_handle *h;
+
+ llist_for_each_entry(h, &bts->osmux.osmux_handle_list, head) {
+ if (h->in == in) {
+ if (--h->refcnt == 0) {
+ LOGP(DOSMUX, LOGL_INFO,
+ "Releasing unused osmux handle for %s\n",
+ osmo_sockaddr_to_str(&h->rem_addr));
+ llist_del(&h->head);
+ TALLOC_FREE(h->in);
+ talloc_free(h);
+ }
+ return;
+ }
+ }
+ LOGP(DOSMUX, LOGL_ERROR, "Cannot find Osmux input handle %p\n", in);
+}
+
+/* Allocate free OSMUX handle */
+static struct osmux_handle *osmux_handle_alloc(struct gsm_bts *bts, const struct osmo_sockaddr *rem_addr)
+{
+ struct osmux_handle *h;
+ char name[128] = "r=";
+
+ h = talloc_zero(bts, struct osmux_handle);
+ if (!h)
+ return NULL;
+ h->bts = bts;
+ h->rem_addr = *rem_addr;
+ h->refcnt++;
+
+ h->in = osmux_xfrm_input_alloc(h);
+ if (!h->in) {
+ talloc_free(h);
+ return NULL;
+ }
+
+ osmo_sockaddr_to_str_buf(name + 2, sizeof(name) - 2, rem_addr);
+ osmux_xfrm_input_set_name(h->in, name);
+ /* sequence number to start OSMUX message from */
+ osmux_xfrm_input_set_initial_seqnum(h->in, 0);
+ osmux_xfrm_input_set_batch_factor(h->in, bts->osmux.batch_factor);
+ /* If batch size is zero, the library defaults to 1472 bytes. */
+ osmux_xfrm_input_set_batch_size(h->in, bts->osmux.batch_size);
+ osmux_xfrm_input_set_deliver_cb(h->in, osmux_deliver_cb, h);
+
+ llist_add(&h->head, &bts->osmux.osmux_handle_list);
+
+ LOGP(DOSMUX, LOGL_DEBUG, "Created new OSMUX handle for rem_addr=%s\n",
+ osmo_sockaddr_to_str(rem_addr));
+
+ return h;
+}
+
+/* Lookup existing handle for a specified address, if the handle can not be
+ * found, the function will automatically allocate one */
+static struct osmux_in_handle *
+osmux_handle_find_or_create(struct gsm_bts *bts, const struct osmo_sockaddr *rem_addr)
+{
+ struct osmux_handle *h;
+
+ if (rem_addr->u.sa.sa_family != AF_INET) {
+ LOGP(DOSMUX, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n");
+ return NULL;
+ }
+
+ h = osmux_handle_find_get(bts, rem_addr);
+ if (h != NULL)
+ return h->in;
+
+ h = osmux_handle_alloc(bts, rem_addr);
+ if (h == NULL)
+ return NULL;
+
+ return h->in;
+}
+
+
+static struct msgb *osmux_recv(struct osmo_fd *ofd, struct osmo_sockaddr *addr)
+{
+ struct msgb *msg;
+ socklen_t slen = sizeof(addr->u.sas);
+ int ret;
+
+ msg = msgb_alloc(4096, "OSMUX"); /* TODO: pool? */
+ if (!msg) {
+ LOGP(DOSMUX, LOGL_ERROR, "cannot allocate message\n");
+ return NULL;
+ }
+ ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0, &addr->u.sa, &slen);
+ if (ret <= 0) {
+ msgb_free(msg);
+ LOGP(DOSMUX, LOGL_ERROR, "cannot receive message\n");
+ return NULL;
+ }
+ msgb_put(msg, ret);
+
+ return msg;
+}
+
+static struct gsm_lchan *osmux_lchan_find(struct gsm_bts *bts, const struct osmo_sockaddr *rem_addr, uint8_t osmux_cid)
+{
+ /* TODO: Optimize this by maintaining a hashmap local_cid->lchan in bts */
+ struct gsm_bts_trx *trx;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) { /* C0..n */
+ unsigned int tn;
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ uint8_t subslot, subslots;
+ if (!ts_is_tch(ts))
+ continue;
+
+ subslots = ts_subslots(ts);
+ for (subslot = 0; subslot < subslots; subslot++) {
+ struct gsm_lchan *lchan = &ts->lchan[subslot];
+ struct osmux_handle *h;
+ if (!lchan->abis_ip.osmux.use)
+ continue;
+ if (!lchan_osmux_connected(lchan))
+ continue;
+ if (lchan->abis_ip.osmux.local_cid != osmux_cid)
+ continue;
+ h = osmux_xfrm_input_get_deliver_cb_data(lchan->abis_ip.osmux.in);
+ if (osmo_sockaddr_cmp(&h->rem_addr, rem_addr) != 0)
+ continue;
+ return lchan; /* Found it! */
+ }
+ }
+ }
+ return NULL;
+}
+
+static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ struct msgb *msg;
+ struct osmux_hdr *osmuxh;
+ struct osmo_sockaddr rem_addr;
+ struct gsm_bts *bts = ofd->data;
+
+ msg = osmux_recv(ofd, &rem_addr);
+ if (!msg)
+ return -1;
+
+ while ((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
+ struct gsm_lchan *lchan = osmux_lchan_find(bts, &rem_addr, osmuxh->circuit_id);
+ if (!lchan) {
+ char addr_str[64];
+ osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), &rem_addr);
+ LOGP(DOSMUX, LOGL_DEBUG,
+ "Cannot find lchan for %s CID=%d\n",
+ addr_str, osmuxh->circuit_id);
+ continue;
+ }
+ osmux_xfrm_output_sched(lchan->abis_ip.osmux.out, osmuxh);
+ }
+ msgb_free(msg);
+ return 0;
+}
+
+/* Called before config file read, set defaults */
+int bts_osmux_init(struct gsm_bts *bts)
+{
+ bts->osmux.use = OSMUX_USAGE_OFF;
+ bts->osmux.local_addr = talloc_strdup(bts, "127.0.0.1");
+ bts->osmux.local_port = OSMUX_DEFAULT_PORT;
+ bts->osmux.batch_factor = 4;
+ bts->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
+ bts->osmux.dummy_padding = false;
+ INIT_LLIST_HEAD(&bts->osmux.osmux_handle_list);
+ bts->osmux.fd.fd = -1;
+ return 0;
+}
+
+void bts_osmux_release(struct gsm_bts *bts)
+{
+ /* bts->osmux.osmux_handle_list should end up empty when all lchans are
+ * released/freed upon talloc_free(bts). */
+ /* If bts->osmux.fd.data is NULL, bts is being released/freed without
+ * passing bts_osmux_init()/through bts_osmux_open() and hence fd is
+ * probably 0 (memzeored). Avoid accessing it if not initialized. */
+ if (bts->osmux.fd.fd != -1 && bts->osmux.fd.data)
+ osmo_fd_close(&bts->osmux.fd);
+}
+
+/* Called after config file read, start services */
+int bts_osmux_open(struct gsm_bts *bts)
+{
+ int rc;
+
+ /* If Osmux is not enabled by VTY, don't initialize stuff */
+ if (bts->osmux.use == OSMUX_USAGE_OFF)
+ return 0;
+
+ bts->osmux.fd.cb = osmux_read_fd_cb;
+ bts->osmux.fd.data = bts;
+ rc = osmo_sock_init2_ofd(&bts->osmux.fd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+ bts->osmux.local_addr, bts->osmux.local_port,
+ NULL, 0, OSMO_SOCK_F_BIND);
+ if (rc < 0) {
+ LOGP(DOSMUX, LOGL_ERROR,
+ "Failed binding Osmux socket to %s:%u\n",
+ bts->osmux.local_addr ? : "*", bts->osmux.local_port);
+ return rc;
+ }
+
+ LOGP(DOSMUX, LOGL_INFO,
+ "Osmux socket listening on %s:%u\n",
+ bts->osmux.local_addr ? : "*", bts->osmux.local_port);
+
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OSMUX);
+ return rc;
+}
+
+static struct msgb *osmux_rtp_msgb_alloc_cb(void *rtp_msgb_alloc_priv_data,
+ unsigned int msg_len)
+{
+ struct msgb *msg;
+ msg = l1sap_msgb_alloc(msg_len);
+ /* We have size for "struct osmo_phsap_prim" reserved & aligned at the
+ * start of the msg. Osmux will start filling RTP Header at the tail.
+ * Later on, when pushing it down the stack (scheduled_from_osmux_tx_rtp_cb)
+ * we'll want to get rid of the RTP header and have RTP payload
+ * immediately follow the the struct osmo_phsap_prim. Hence, we rework
+ * reserved space so that end of RTP header (12 bytes) filled by Osmux
+ * ends up at the same position where "struct osmo_phsap_prim" currently
+ * ends up */
+ msg->l2h = msgb_get(msg, sizeof(struct rtp_hdr));
+ return msg;
+}
+
+static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
+{
+ struct gsm_lchan *lchan = data;
+ struct rtp_hdr *rtph;
+
+ /* if we're in loopback mode, we don't accept frames from the
+ * RTP socket anymore */
+ if (lchan->loopback) {
+ msgb_free(msg);
+ return;
+ }
+
+ /* This is where start of rtp_hdr was prepared in osmux_rtp_msgb_alloc_cb() */
+ rtph = (struct rtp_hdr *)msg->l2h;
+ if (msgb_l2len(msg) < sizeof(*rtph)) {
+ LOGPLCHAN(lchan, DOSMUX, LOGL_ERROR, "received RTP frame too short (len = %d)\n",
+ msgb_l2len(msg));
+ msgb_free(msg);
+ return;
+ }
+
+ /* Store RTP header Marker bit in control buffer */
+ rtpmsg_marker_bit(msg) = rtph->marker;
+ /* Store RTP header Sequence Number in control buffer */
+ rtpmsg_seq(msg) = ntohs(rtph->sequence);
+ /* Store RTP header Timestamp in control buffer */
+ rtpmsg_ts(msg) = ntohl(rtph->timestamp);
+
+ /* No need to pull() rtph out of msg here, because it was written inside
+ * initial space reserved for "struct osmo_phsap_prim". We need to pull
+ * the whole "struct osmo_phsap_prim" since it will be pushed and filled
+ * by lower layers:
+ */
+ msgb_pull(msg, sizeof(struct osmo_phsap_prim));
+
+ /* enqueue making sure the queue doesn't get too long */
+ lchan_dl_tch_queue_enqueue(lchan, msg, 16);
+}
+
+int lchan_osmux_init(struct gsm_lchan *lchan, uint8_t rtp_payload)
+{
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+ int local_cid = osmux_get_local_cid();
+ struct in_addr ia;
+
+ if (local_cid < 0)
+ return local_cid;
+
+ if (inet_pton(AF_INET, trx->bts->osmux.local_addr, &ia) != 1)
+ return -1;
+
+ lchan->abis_ip.osmux.out = osmux_xfrm_output_alloc(trx);
+ osmux_xfrm_output_set_rtp_ssrc(lchan->abis_ip.osmux.out, random() /*TODO: SSRC */);
+ osmux_xfrm_output_set_rtp_pl_type(lchan->abis_ip.osmux.out, rtp_payload);
+ osmux_xfrm_output_set_tx_cb(lchan->abis_ip.osmux.out, scheduled_from_osmux_tx_rtp_cb, lchan);
+ osmux_xfrm_output_set_rtp_msgb_alloc_cb(lchan->abis_ip.osmux.out, osmux_rtp_msgb_alloc_cb, lchan);
+
+ lchan->abis_ip.bound_ip = ntohl(ia.s_addr);
+ lchan->abis_ip.bound_port = trx->bts->osmux.local_port;
+ lchan->abis_ip.osmux.local_cid = local_cid;
+ lchan->abis_ip.osmux.rtpst = osmo_rtp_handle_create(trx);
+ lchan->abis_ip.osmux.use = true;
+ return 0;
+}
+
+void lchan_osmux_release(struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ OSMO_ASSERT(lchan->abis_ip.osmux.use);
+ /* We are closing, we don't need pending RTP packets to be transmitted */
+ osmux_xfrm_output_set_tx_cb(lchan->abis_ip.osmux.out, NULL, NULL);
+ TALLOC_FREE(lchan->abis_ip.osmux.out);
+
+ msgb_queue_free(&lchan->dl_tch_queue);
+ lchan->dl_tch_queue_len = 0;
+
+ osmux_put_local_cid(lchan->abis_ip.osmux.local_cid);
+
+ /* Now the remote / tx part, if ever set (connected): */
+ if (lchan->abis_ip.osmux.in) {
+ osmux_xfrm_input_close_circuit(lchan->abis_ip.osmux.in,
+ lchan->abis_ip.osmux.remote_cid);
+ osmux_handle_put(bts, lchan->abis_ip.osmux.in);
+ lchan->abis_ip.osmux.in = NULL;
+ }
+ if (lchan->abis_ip.osmux.rtpst) {
+ osmo_rtp_handle_free(lchan->abis_ip.osmux.rtpst);
+ lchan->abis_ip.osmux.rtpst = NULL;
+ }
+
+ lchan->abis_ip.osmux.use = false;
+}
+
+bool lchan_osmux_connected(const struct gsm_lchan *lchan)
+{
+ return lchan->abis_ip.osmux.in != NULL;
+}
+
+int lchan_osmux_connect(struct gsm_lchan *lchan)
+{
+ struct osmo_sockaddr rem_addr;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ OSMO_ASSERT(lchan->abis_ip.connect_ip != 0);
+ OSMO_ASSERT(lchan->abis_ip.connect_port != 0);
+
+ memset(&rem_addr, 0, sizeof(rem_addr));
+ rem_addr.u.sa.sa_family = AF_INET;
+ rem_addr.u.sin.sin_addr.s_addr = lchan->abis_ip.connect_ip;
+ rem_addr.u.sin.sin_port = htons(lchan->abis_ip.connect_port);
+ lchan->abis_ip.osmux.in = osmux_handle_find_or_create(bts, &rem_addr);
+ if (!lchan->abis_ip.osmux.in) {
+ LOGPLCHAN(lchan, DOSMUX, LOGL_ERROR, "Cannot allocate input osmux handle\n");
+ return -1;
+ }
+ if (osmux_xfrm_input_open_circuit(lchan->abis_ip.osmux.in,
+ lchan->abis_ip.osmux.remote_cid,
+ bts->osmux.dummy_padding) < 0) {
+ LOGPLCHAN(lchan, DOSMUX, LOGL_ERROR, "Cannot open osmux circuit %u\n",
+ lchan->abis_ip.osmux.remote_cid);
+ osmux_handle_put(bts, lchan->abis_ip.osmux.in);
+ lchan->abis_ip.osmux.in = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+/* Create RTP packet from l1sap payload and feed it to osmux */
+int lchan_osmux_send_frame(struct gsm_lchan *lchan, const uint8_t *payload,
+ unsigned int payload_len, unsigned int duration, bool marker)
+{
+ struct msgb *msg;
+ struct rtp_hdr *rtph;
+ int rc;
+
+ msg = osmo_rtp_build(lchan->abis_ip.osmux.rtpst, lchan->abis_ip.rtp_payload,
+ payload_len, payload, duration);
+ if (!msg)
+ return -1;
+
+ /* Set marker bit: */
+ rtph = (struct rtp_hdr *)msgb_data(msg);
+ rtph->marker = marker;
+
+ /* Avoid using the osmux.in if not yet connected. */
+ if (!lchan_osmux_connected(lchan)) {
+ msgb_free(msg);
+ return -1;
+ }
+
+ while ((rc = osmux_xfrm_input(lchan->abis_ip.osmux.in, msg,
+ lchan->abis_ip.osmux.remote_cid)) > 0) {
+ /* batch full, build and deliver it */
+ osmux_xfrm_input_deliver(lchan->abis_ip.osmux.in);
+ }
+ return 0;
+}
+
+int lchan_osmux_skipped_frame(struct gsm_lchan *lchan, unsigned int duration)
+{
+ struct msgb *msg;
+
+ /* Let osmo_rtp_handle take care of updating state, and send nothing: */
+ msg = osmo_rtp_build(lchan->abis_ip.osmux.rtpst, lchan->abis_ip.rtp_payload,
+ 0, NULL, duration);
+ if (!msg)
+ return -1;
+ msgb_free(msg);
+ return 0;
+}
diff --git a/src/common/paging.c b/src/common/paging.c
index fca58b5f..bdd51801 100644
--- a/src/common/paging.c
+++ b/src/common/paging.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -43,13 +43,14 @@
#include <osmo-bts/paging.h>
#include <osmo-bts/signal.h>
#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/notification.h>
#define MAX_PAGING_BLOCKS_CCCH 9
#define MAX_BS_PA_MFRMS 9
enum paging_record_type {
- PAGING_RECORD_PAGING,
- PAGING_RECORD_IMM_ASS
+ PAGING_RECORD_NORMAL,
+ PAGING_RECORD_MACBLOCK
};
struct paging_record {
@@ -60,10 +61,12 @@ struct paging_record {
time_t expiration_time;
uint8_t chan_needed;
uint8_t identity_lv[9];
- } paging;
+ } normal;
struct {
uint8_t msg[GSM_MACBLOCK_LEN];
- } imm_ass;
+ bool confirm;
+ uint32_t msg_id; /* used as identifier for confirmation */
+ } macblock;
} u;
};
@@ -80,8 +83,37 @@ struct paging_state {
/* total number of currently active paging records in queue */
unsigned int num_paging;
struct llist_head paging_queue[MAX_PAGING_BLOCKS_CCCH*MAX_BS_PA_MFRMS];
+
+ /* prioritization of cs pagings will automatically become
+ * active on congestions (queue almost full) */
+ bool cs_priority_active;
};
+/* The prioritization of cs pagings is controlled by a hysteresis. When the
+ * fill state of the paging queue exceeds the upper fill level
+ * THRESHOLD_CONGESTED [%], then PS pagings (immediate assignments and pagings
+ * from the PCU) will be dropped until fill state of the paging queue drops
+ * under the lower fill level THRESHOLD_CLEAR [%]. */
+#define THRESHOLD_CONGESTED 66 /* (percent of num_paging_max) */
+#define THRESHOLD_CLEAR 50 /* (percent of num_paging_max) */
+
+/* Check the queue fill status and decide if prioritization of CS pagings
+ * must be turned on to flatten the negative effects of the congestion
+ * situation on the CS domain. */
+static void check_congestion(struct paging_state *ps)
+{
+ int pag_queue_len = paging_queue_length(ps);
+ int pag_queue_max = paging_get_queue_max(ps);
+ unsigned int treshold_upper = pag_queue_max * THRESHOLD_CONGESTED / 100;
+ unsigned int treshold_lower = pag_queue_max * THRESHOLD_CLEAR / 100;
+
+ if (pag_queue_len > treshold_upper && ps->cs_priority_active == false) {
+ ps->cs_priority_active = true;
+ rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_CONG);
+ } else if (pag_queue_len < treshold_lower)
+ ps->cs_priority_active = false;
+}
+
unsigned int paging_get_lifetime(struct paging_state *ps)
{
return ps->paging_lifetime;
@@ -181,6 +213,8 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
int blocks = gsm48_number_of_paging_subchannels(&ps->chan_desc);
struct paging_record *pr;
+ check_congestion(ps);
+
rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_RCVD);
if (paging_group >= blocks) {
@@ -199,13 +233,13 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
/* Check if we already have this identity */
llist_for_each_entry(pr, group_q, list) {
- if (pr->type != PAGING_RECORD_PAGING)
+ if (pr->type != PAGING_RECORD_NORMAL)
continue;
- if (identity_lv[0] == pr->u.paging.identity_lv[0] &&
- !memcmp(identity_lv+1, pr->u.paging.identity_lv+1,
+ if (identity_lv[0] == pr->u.normal.identity_lv[0] &&
+ !memcmp(identity_lv+1, pr->u.normal.identity_lv+1,
identity_lv[0])) {
LOGP(DPAG, LOGL_INFO, "Ignoring duplicate paging\n");
- pr->u.paging.expiration_time =
+ pr->u.normal.expiration_time =
time(NULL) + ps->paging_lifetime;
return -EEXIST;
}
@@ -214,9 +248,9 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
pr = talloc_zero(ps, struct paging_record);
if (!pr)
return -ENOMEM;
- pr->type = PAGING_RECORD_PAGING;
+ pr->type = PAGING_RECORD_NORMAL;
- if (*identity_lv + 1 > sizeof(pr->u.paging.identity_lv)) {
+ if (*identity_lv + 1 > sizeof(pr->u.normal.identity_lv)) {
talloc_free(pr);
return -E2BIG;
}
@@ -224,9 +258,9 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
LOGP(DPAG, LOGL_INFO, "Add paging to queue (group=%u, queue_len=%u)\n",
paging_group, ps->num_paging+1);
- pr->u.paging.expiration_time = time(NULL) + ps->paging_lifetime;
- pr->u.paging.chan_needed = chan_needed;
- memcpy(&pr->u.paging.identity_lv, identity_lv, identity_lv[0]+1);
+ pr->u.normal.expiration_time = time(NULL) + ps->paging_lifetime;
+ pr->u.normal.chan_needed = chan_needed;
+ memcpy(&pr->u.normal.identity_lv, identity_lv, identity_lv[0]+1);
/* enqueue the new identity to the HEAD of the queue,
* to ensure it will be paged quickly at least once. */
@@ -236,35 +270,59 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
return 0;
}
-/* Add an IMM.ASS message to the paging queue */
-int paging_add_imm_ass(struct paging_state *ps, const uint8_t *data,
- uint8_t len)
+/* Convert the last three digits of a given IMSI string to their decimal representation. In case the given IMSI string
+ * is shorter than three or zero digits, it will be assumed as "000" */
+static uint16_t convert_imsi_to_decimal(const char *imsi)
+{
+ uint16_t _imsi;
+ size_t imsi_len = strlen(imsi);
+
+ /* Tha paging group is calculated from the last three digits of the IMSI */
+ if (imsi_len < 3) {
+ LOGP(DPAG, LOGL_ERROR, "short IMSI (%zu digits), will assume \"000\" to calculate paging group\n", imsi_len);
+ _imsi = 0;
+ } else {
+ imsi = imsi + imsi_len - 3;
+ _imsi = 100 * ((*(imsi++)) - '0');
+ _imsi += 10 * ((*(imsi++)) - '0');
+ _imsi += (*(imsi++)) - '0';
+ }
+
+ return _imsi;
+}
+
+/* Add a ready formatted MAC block message to the paging queue, this can be an IMMEDIATE ASSIGNMENT, or a
+ * PAGING COMMAND (from the PCU) */
+int paging_add_macblock(struct paging_state *ps, uint32_t msg_id, const char *imsi, bool confirm, const uint8_t *macblock)
{
struct llist_head *group_q;
struct paging_record *pr;
- uint16_t imsi, paging_group;
+ uint16_t paging_group;
+ uint16_t _imsi;
- if (len != GSM_MACBLOCK_LEN + 3) {
- LOGP(DPAG, LOGL_ERROR, "IMM.ASS invalid length %d\n", len);
- return -EINVAL;
- }
- len -= 3;
+ check_congestion(ps);
- imsi = 100 * ((*(data++)) - '0');
- imsi += 10 * ((*(data++)) - '0');
- imsi += (*(data++)) - '0';
- paging_group = gsm0502_calc_paging_group(&ps->chan_desc, imsi);
+ if (ps->cs_priority_active) {
+ LOGP(DPAG, LOGL_NOTICE, "Dropping paging for PS, queue congested (%u)\n",
+ ps->num_paging);
+ rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_DROP_PS);
+ return -ENOSPC;
+ }
+ _imsi = convert_imsi_to_decimal(imsi);
+ paging_group = gsm0502_calc_paging_group(&ps->chan_desc, _imsi);
group_q = &ps->paging_queue[paging_group];
pr = talloc_zero(ps, struct paging_record);
if (!pr)
return -ENOMEM;
- pr->type = PAGING_RECORD_IMM_ASS;
+ pr->type = PAGING_RECORD_MACBLOCK;
- LOGP(DPAG, LOGL_INFO, "Add IMM.ASS to queue (group=%u)\n",
+ LOGP(DPAG, LOGL_INFO, "Add MAC block to paging queue (group=%u)\n",
paging_group);
- memcpy(pr->u.imm_ass.msg, data, GSM_MACBLOCK_LEN);
+ memcpy(pr->u.macblock.msg, macblock, GSM_MACBLOCK_LEN);
+ pr->u.macblock.confirm = confirm;
+ pr->u.macblock.msg_id = msg_id;
/* enqueue the new message to the HEAD of the queue */
llist_add(&pr->list, group_q);
@@ -274,22 +332,6 @@ int paging_add_imm_ass(struct paging_state *ps, const uint8_t *data,
#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
-/* abstract representation of P1 rest octets; we only implement those parts we need for now */
-struct p1_rest_octets {
- bool packet_page_ind[2];
- bool r8_present;
- struct {
- bool prio_ul_access;
- bool etws_present;
- struct {
- bool is_first;
- uint8_t page_nr;
- const uint8_t *page;
- size_t page_bytes;
- } etws;
- } r8;
-};
-
/* 3GPP TS 44.018 10.5.2.23 append a segment/page of an ETWS primary notification to given bitvec */
static void append_etws_prim_notif(struct bitvec *bv, bool is_first, uint8_t page_nr,
const uint8_t *etws, ssize_t etws_len)
@@ -316,13 +358,27 @@ static void append_etws_prim_notif(struct bitvec *bv, bool is_first, uint8_t pag
}
/* 3GPP TS 44.018 10.5.2.23 append P1 Rest Octets to given bit-vector */
-static void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro)
+void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro,
+ const struct asci_notification *notif)
{
/* Paging 1 RO (at least 10 bits before ETWS struct) */
- bitvec_set_bit(bv, L); /* no NLN */
+ if (p1ro->nln_pch.present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, p1ro->nln_pch.nln, 2);
+ bitvec_set_uint(bv, p1ro->nln_pch.nln_status, 1);
+ } else {
+ bitvec_set_bit(bv, L); /* no NLN */
+ }
bitvec_set_bit(bv, L); /* no Priority1 */
bitvec_set_bit(bv, L); /* no Priority2 */
- bitvec_set_bit(bv, L); /* no Group Call Info */
+ if (notif) {
+ bitvec_set_bit(bv, H); /* Group Call Info */
+ append_group_call_information(bv, notif->group_call_ref,
+ notif->chan_desc.present ? notif->chan_desc.value : NULL,
+ notif->chan_desc.len);
+ } else {
+ bitvec_set_bit(bv, L); /* no Group Call Info */
+ }
if (p1ro->packet_page_ind[0])
bitvec_set_bit(bv, H); /* Packet Page Indication 1 */
else
@@ -347,49 +403,97 @@ static void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets
}
}
+/* 3GPP TS 44.018 10.5.2.24 append P2 Rest Octets to given bit-vector */
+void append_p2_rest_octets(struct bitvec *bv, const struct p2_rest_octets *p2ro)
+{
+ /* {L | H <CN3: bit (2)>} */
+ if (p2ro->cneed.present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, p2ro->cneed.cn3, 2);
+ } else
+ bitvec_set_bit(bv, L); /* no CN3 */
+
+ /* {L | H < NLN(PCH) : bit (2) <NLN status(PCH) : bit>} */
+ if (p2ro->nln_pch.present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, p2ro->nln_pch.nln, 2);
+ bitvec_set_uint(bv, p2ro->nln_pch.nln_status, 1);
+ } else
+ bitvec_set_bit(bv, L); /* no NLN */
+
+ /* Note: If this needs to be extended in the future, check if it actually fits into rest of P2! */
+}
+
+/* 3GPP TS 44.018 10.5.2.25 append P3 Rest Octets to given bit-vector */
+void append_p3_rest_octets(struct bitvec *bv, const struct p3_rest_octets *p3ro)
+{
+ /* {L | H <CN3: bit (2)> <CN3: bit (2)>} */
+ if (p3ro->cneed.present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, p3ro->cneed.cn3, 2);
+ bitvec_set_uint(bv, p3ro->cneed.cn4, 2);
+ } else
+ bitvec_set_bit(bv, L); /* no CN3/CN4 */
+
+ /* {L | H < NLN(PCH) : bit (2) <NLN status(PCH) : bit>} */
+ if (p3ro->nln_pch.present) {
+ bitvec_set_bit(bv, H);
+ bitvec_set_uint(bv, p3ro->nln_pch.nln, 2);
+ bitvec_set_uint(bv, p3ro->nln_pch.nln_status, 1);
+ } else
+ bitvec_set_bit(bv, L); /* no NLN */
+
+ /* Note: If this needs to be extended in the future, check if it actually fits into 3 octets! */
+}
+
static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
uint8_t chan1, const uint8_t *identity2_lv,
- uint8_t chan2, const struct p1_rest_octets *p1ro)
+ uint8_t chan2, const struct p1_rest_octets *p1ro,
+ const struct asci_notification *notif)
{
struct gsm48_paging1 *pt1 = (struct gsm48_paging1 *) out_buf;
- struct bitvec bv;
- unsigned int paging_len;
+ unsigned int ro_len;
uint8_t *cur;
- memset(out_buf, 0, sizeof(*pt1));
+ *pt1 = (struct gsm48_paging1) {
+ .proto_discr = GSM48_PDISC_RR,
+ .msg_type = GSM48_MT_RR_PAG_REQ_1,
+ .pag_mode = GSM48_PM_NORMAL,
+ .cneed1 = chan1 & 3,
+ .cneed2 = chan2 & 3,
+ };
- pt1->proto_discr = GSM48_PDISC_RR;
- pt1->msg_type = GSM48_MT_RR_PAG_REQ_1;
- pt1->pag_mode = GSM48_PM_NORMAL;
- pt1->cneed1 = chan1 & 3;
- pt1->cneed2 = chan2 & 3;
cur = lv_put(pt1->data, identity1_lv[0], identity1_lv+1);
if (identity2_lv)
cur = tlv_put(cur, GSM48_IE_MOBILE_ID, identity2_lv[0], identity2_lv+1);
pt1->l2_plen = L2_PLEN(cur - out_buf);
- paging_len = cur - out_buf;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = cur;
- bv.data_len = GSM_MACBLOCK_LEN - paging_len;
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (cur - out_buf);
+ memset(cur, GSM_MACBLOCK_PADDING, ro_len);
- if (p1ro)
- append_p1_rest_octets(&bv, p1ro);
+ /* Optional P1 Rest Octets */
+ if (p1ro) {
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = cur,
+ };
- /* pad to the end of the MAC block */
- bitvec_spare_padding(&bv, bv.data_len *8);
+ append_p1_rest_octets(&bv, p1ro, notif);
+ }
return GSM_MACBLOCK_LEN;
}
static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
uint8_t cneed1, const uint8_t *tmsi2_lv,
- uint8_t cneed2, const uint8_t *identity3_lv)
+ uint8_t cneed2, const uint8_t *identity3_lv,
+ const struct p2_rest_octets *p2ro)
{
struct gsm48_paging2 *pt2 = (struct gsm48_paging2 *) out_buf;
uint32_t tmsi;
+ unsigned int ro_len;
uint8_t *cur;
int rc;
@@ -413,16 +517,32 @@ static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
pt2->l2_plen = L2_PLEN(cur - out_buf);
- return cur - out_buf;
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (cur - out_buf);
+ memset(cur, GSM_MACBLOCK_PADDING, ro_len);
+
+ /* Optional P2 Rest Octets */
+ if (p2ro) {
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = cur,
+ };
+
+ append_p2_rest_octets(&bv, p2ro);
+ }
+
+ return GSM_MACBLOCK_LEN;
}
static int fill_paging_type_3(uint8_t *out_buf, const uint8_t *tmsi1_lv, uint8_t cneed1,
const uint8_t *tmsi2_lv, uint8_t cneed2,
- const uint8_t *tmsi3_lv, uint8_t cneed3,
- const uint8_t *tmsi4_lv, uint8_t cneed4)
+ const uint8_t *tmsi3_lv, const uint8_t *tmsi4_lv,
+ const struct p3_rest_octets *p3ro)
{
struct gsm48_paging3 *pt3 = (struct gsm48_paging3 *) out_buf;
uint32_t tmsi;
+ unsigned int ro_len;
+ uint8_t *cur;
int rc;
memset(out_buf, 0, sizeof(*pt3));
@@ -444,13 +564,25 @@ static int fill_paging_type_3(uint8_t *out_buf, const uint8_t *tmsi1_lv, uint8_t
rc = tmsi_mi_to_uint(&tmsi, tmsi4_lv);
if (rc == 0)
pt3->tmsi4 = tmsi;
+ cur = out_buf + 20; /* Cannot use sizeof(*pt3), because it has more octets. */
- /* The structure definition in libosmocore is wrong. It includes as last
- * byte some invalid definition of chneed3/chneed4, so we must do this by hand
- * here and cannot rely on sizeof(*pt3) */
- out_buf[20] = (0x23 & ~0xf8) | 0x80 | (cneed3 & 3) << 5 | (cneed4 & 3) << 3;
+ pt3->l2_plen = L2_PLEN(cur - out_buf);
- return 21;
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (cur - out_buf);
+ memset(cur, GSM_MACBLOCK_PADDING, ro_len);
+
+ /* Optional P3 Rest Octets */
+ if (p3ro) {
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = cur,
+ };
+
+ append_p3_rest_octets(&bv, p3ro);
+ }
+
+ return GSM_MACBLOCK_LEN;
}
static const uint8_t empty_id_lv[] = { 0x01, 0xF0 };
@@ -467,7 +599,7 @@ static struct paging_record *dequeue_pr(struct llist_head *group_q)
static int pr_is_imsi(struct paging_record *pr)
{
- if ((pr->u.paging.identity_lv[1] & 7) == GSM_MI_TYPE_IMSI)
+ if ((pr->u.normal.identity_lv[1] & 7) == GSM_MI_TYPE_IMSI)
return 1;
else
return 0;
@@ -496,6 +628,7 @@ static void sort_pr_tmsi_imsi(struct paging_record *pr[], unsigned int n)
static void build_p1_rest_octets(struct p1_rest_octets *p1ro, struct gsm_bts *bts)
{
memset(p1ro, 0, sizeof(*p1ro));
+ p1ro->nln_pch.present = false;
p1ro->packet_page_ind[0] = false;
p1ro->packet_page_ind[1] = false;
p1ro->r8_present = true;
@@ -528,6 +661,10 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
int group;
int len;
+ /* This will have no effect on behavior of this function, we just need
+ * need to check the congestion status of the queue from time to time. */
+ check_congestion(ps);
+
*is_empty = 0;
bts->load.ccch.pch_total += 1;
@@ -544,16 +681,24 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
if (ps->bts->etws.prim_notif) {
struct p1_rest_octets p1ro;
build_p1_rest_octets(&p1ro, bts);
- len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro);
+ /* we intentioanally don't try to add notifications here, as ETWS is more critical */
+ len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro, NULL);
} else if (llist_empty(group_q)) {
+ struct p1_rest_octets p1ro;
+ memset(&p1ro, 0, sizeof(p1ro));
+ /* Use NLN to notify MS about ongoing VGCS/VBS calls.
+ * This is required to make the phone read the NCH to get an updated list of ongoing calls.
+ * Without this the phone will not allow making VGCS/VBS calls. */
+ p1ro.nln_pch.present = (bts->asci.pos_nch >= 0);
+ p1ro.nln_pch.nln = bts->asci.nln;
+ p1ro.nln_pch.nln_status = bts->asci.nln_status;
/* There is nobody to be paged, send Type1 with two empty ID */
//DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n");
- len = fill_paging_type_1(out_buf, empty_id_lv, 0,
- NULL, 0, NULL);
+ len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro, NULL);
*is_empty = 1;
} else {
struct paging_record *pr[4];
- unsigned int num_pr = 0, imm_ass = 0;
+ unsigned int num_pr = 0, macblock = 0;
time_t now = time(NULL);
unsigned int i, num_imsi = 0;
@@ -565,9 +710,9 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
break;
pr[i] = dequeue_pr(group_q);
- /* check for IMM.ASS */
- if (pr[i]->type == PAGING_RECORD_IMM_ASS) {
- imm_ass = 1;
+ /* check for MAC block */
+ if (pr[i]->type == PAGING_RECORD_MACBLOCK) {
+ macblock = 1;
break;
}
@@ -578,17 +723,18 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
num_imsi++;
}
- /* if we have an IMMEDIATE ASSIGNMENT */
- if (imm_ass) {
- /* re-add paging records */
+ /* Handle MAC block (from the PCU) */
+ if (macblock) {
+ /* re-add normal paging records */
for (i = 0; i < num_pr; i++)
llist_add(&pr[i]->list, group_q);
- /* get message and free record */
- memcpy(out_buf, pr[num_pr]->u.imm_ass.msg,
- GSM_MACBLOCK_LEN);
- pcu_tx_pch_data_cnf(gt->fn, pr[num_pr]->u.imm_ass.msg,
+ /* get MAC block message and free record */
+ memcpy(out_buf, pr[num_pr]->u.macblock.msg,
GSM_MACBLOCK_LEN);
+ /* send a confirmation back (if required) */
+ if (pr[num_pr]->u.macblock.confirm)
+ pcu_tx_data_cnf(pr[num_pr]->u.macblock.msg_id, PCU_IF_SAPI_PCH_2);
talloc_free(pr[num_pr]);
return GSM_MACBLOCK_LEN;
}
@@ -599,24 +745,39 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
if (num_pr == 4 && num_imsi == 0) {
/* No IMSI: easy case, can use TYPE 3 */
DEBUGP(DPAG, "Tx PAGING TYPE 3 (4 TMSI)\n");
+ struct p3_rest_octets p3ro;
+ memset(&p3ro, 0, sizeof(p3ro));
+ p3ro.cneed.present = true;
+ p3ro.cneed.cn3 = pr[2]->u.normal.chan_needed;
+ p3ro.cneed.cn4 = pr[3]->u.normal.chan_needed;
+ p3ro.nln_pch.present = (bts->asci.pos_nch >= 0);
+ p3ro.nln_pch.nln = bts->asci.nln;
+ p3ro.nln_pch.nln_status = bts->asci.nln_status;
len = fill_paging_type_3(out_buf,
- pr[0]->u.paging.identity_lv,
- pr[0]->u.paging.chan_needed,
- pr[1]->u.paging.identity_lv,
- pr[1]->u.paging.chan_needed,
- pr[2]->u.paging.identity_lv,
- pr[2]->u.paging.chan_needed,
- pr[3]->u.paging.identity_lv,
- pr[3]->u.paging.chan_needed);
+ pr[0]->u.normal.identity_lv,
+ pr[0]->u.normal.chan_needed,
+ pr[1]->u.normal.identity_lv,
+ pr[1]->u.normal.chan_needed,
+ pr[2]->u.normal.identity_lv,
+ pr[3]->u.normal.identity_lv,
+ &p3ro);
} else if (num_pr >= 3 && num_imsi <= 1) {
/* 3 or 4, of which only up to 1 is IMSI */
DEBUGP(DPAG, "Tx PAGING TYPE 2 (2 TMSI,1 xMSI)\n");
+ struct p2_rest_octets p2ro;
+ memset(&p2ro, 0, sizeof(p2ro));
+ p2ro.cneed.present = true;
+ p2ro.cneed.cn3 = pr[2]->u.normal.chan_needed;
+ p2ro.nln_pch.present = (bts->asci.pos_nch >= 0);
+ p2ro.nln_pch.nln = bts->asci.nln;
+ p2ro.nln_pch.nln_status = bts->asci.nln_status;
len = fill_paging_type_2(out_buf,
- pr[0]->u.paging.identity_lv,
- pr[0]->u.paging.chan_needed,
- pr[1]->u.paging.identity_lv,
- pr[1]->u.paging.chan_needed,
- pr[2]->u.paging.identity_lv);
+ pr[0]->u.normal.identity_lv,
+ pr[0]->u.normal.chan_needed,
+ pr[1]->u.normal.identity_lv,
+ pr[1]->u.normal.chan_needed,
+ pr[2]->u.normal.identity_lv,
+ &p2ro);
if (num_pr == 4) {
/* re-add #4 for next time */
llist_add(&pr[3]->list, group_q);
@@ -624,19 +785,21 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
}
} else if (num_pr == 1) {
DEBUGP(DPAG, "Tx PAGING TYPE 1 (1 xMSI,1 empty)\n");
+ /* TODO: check if we can include an ASCI notification */
len = fill_paging_type_1(out_buf,
- pr[0]->u.paging.identity_lv,
- pr[0]->u.paging.chan_needed,
- NULL, 0, NULL);
+ pr[0]->u.normal.identity_lv,
+ pr[0]->u.normal.chan_needed,
+ NULL, 0, NULL, NULL);
} else {
/* 2 (any type) or
* 3 or 4, of which only 2 will be sent */
DEBUGP(DPAG, "Tx PAGING TYPE 1 (2 xMSI)\n");
+ /* TODO: check if we can include an ASCI notification */
len = fill_paging_type_1(out_buf,
- pr[0]->u.paging.identity_lv,
- pr[0]->u.paging.chan_needed,
- pr[1]->u.paging.identity_lv,
- pr[1]->u.paging.chan_needed, NULL);
+ pr[0]->u.normal.identity_lv,
+ pr[0]->u.normal.chan_needed,
+ pr[1]->u.normal.identity_lv,
+ pr[1]->u.normal.chan_needed, NULL, NULL);
if (num_pr >= 3) {
/* re-add #4 for next time */
llist_add(&pr[2]->list, group_q);
@@ -656,7 +819,7 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
rate_ctr_inc2(bts->ctrs, BTS_CTR_PAGING_SENT);
/* check if we can expire the paging record,
* or if we need to re-queue it */
- if (pr[i]->u.paging.expiration_time <= now) {
+ if (pr[i]->u.normal.expiration_time <= now) {
talloc_free(pr[i]);
ps->num_paging--;
LOGP(DPAG, LOGL_INFO, "Removed paging record, queue_len=%u\n",
@@ -709,6 +872,7 @@ struct paging_state *paging_init(struct gsm_bts *bts,
ps->bts = bts;
ps->paging_lifetime = paging_lifetime;
ps->num_paging_max = num_paging_max;
+ ps->cs_priority_active = false;
for (i = 0; i < ARRAY_SIZE(ps->paging_queue); i++)
INIT_LLIST_HEAD(&ps->paging_queue[i]);
diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c
index ba9e1721..048e7668 100644
--- a/src/common/pcu_sock.c
+++ b/src/common/pcu_sock.c
@@ -15,10 +15,6 @@
* 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 General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <stdio.h>
@@ -32,37 +28,39 @@
#include <inttypes.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
+#include <osmocom/core/write_queue.h>
#include <osmocom/gsm/gsm23003.h>
+#include <osmocom/gsm/abis_nm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/pcu_if.h>
#include <osmo-bts/pcuif_proto.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/signal.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/abis_osmo.h>
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx);
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx);
-extern struct gsm_network bts_gsmnet;
int pcu_direct = 0;
static int avail_lai = 0, avail_nse = 0, avail_cell = 0, avail_nsvc[2] = {0, 0};
static const char *sapi_string[] = {
[PCU_IF_SAPI_RACH] = "RACH",
- [PCU_IF_SAPI_AGCH] = "AGCH",
- [PCU_IF_SAPI_PCH] = "PCH",
[PCU_IF_SAPI_BCCH] = "BCCH",
[PCU_IF_SAPI_PDTCH] = "PDTCH",
[PCU_IF_SAPI_PRACH] = "PRACH",
[PCU_IF_SAPI_PTCCH] = "PTCCH",
+ [PCU_IF_SAPI_PCH_2] = "PCH_2",
+ [PCU_IF_SAPI_AGCH_2] = "AGCH_2",
};
-static int pcu_sock_send(struct gsm_network *net, struct msgb *msg);
-
/*
* PCU messages
*/
@@ -83,10 +81,12 @@ struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr)
return msg;
}
-static bool ts_should_be_pdch(struct gsm_bts_trx_ts *ts) {
- if (ts->pchan == GSM_PCHAN_PDCH)
+static bool ts_should_be_pdch(const struct gsm_bts_trx_ts *ts)
+{
+ switch (ts->pchan) {
+ case GSM_PCHAN_PDCH:
return true;
- if (ts->pchan == GSM_PCHAN_TCH_F_PDCH) {
+ case GSM_PCHAN_TCH_F_PDCH:
/* When we're busy deactivating the PDCH, we first set
* DEACT_PENDING, tell the PCU about it and wait for a
* response. So DEACT_PENDING means "no PDCH" to the PCU.
@@ -97,35 +97,174 @@ static bool ts_should_be_pdch(struct gsm_bts_trx_ts *ts) {
return !(ts->flags & TS_F_PDCH_DEACT_PENDING);
else
return (ts->flags & TS_F_PDCH_ACT_PENDING);
- }
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ case GSM_PCHAN_OSMO_DYN:
/*
* When we're busy de-/activating the PDCH, we first set
* ts->dyn.pchan_want, tell the PCU about it and wait for a
- * response. So only care about dyn.pchan_want here.
+ * response. To make it available to PCU, we want to make sure
+ * it's already configured by phy (pchan_is==PDCH) and that we
+ * are not in progress of removing it (pchan_want=None).
*/
- return ts->dyn.pchan_want == GSM_PCHAN_PDCH;
+
+ return ts->dyn.pchan_is == GSM_PCHAN_PDCH && ts->dyn.pchan_want == GSM_PCHAN_PDCH;
+ default:
+ return false;
+ }
+}
+
+/* As a BTS, we do not (and neither need to) know the Mobile Allocation, because
+ * in CS domain it's responsibility of the BSC to encode RR messages containing
+ * this IE. However, a BTS co-located PCU needs to know all hopping parameters,
+ * including the Mobile Allocation, because it's responsible for encoding of the
+ * packet resource assignment messages.
+ *
+ * This function, similar to generate_ma_for_ts() in osmo-bsc, computes the
+ * Mobile Allocation bit-mask and populates the given part of INFO.ind with
+ * the hopping parameters for the given timeslot. */
+static void info_ind_fill_fhp(struct gsm_pcu_if_info_trx_ts *ts_info,
+ const struct gsm_bts_trx_ts *ts)
+{
+ const struct gsm_bts *bts = ts->trx->bts;
+ const struct gsm_bts_trx *trx;
+ uint8_t ca_buf[1024 / 8] = { 0 };
+ uint8_t sa_buf[1024 / 8] = { 0 };
+ struct bitvec ca, sa, ma;
+ unsigned int i;
+
+ ts_info->maio = ts->hopping.maio;
+ ts_info->hsn = ts->hopping.hsn;
+ ts_info->hopping = 0x01;
+
+ /* Cell Allocation bit-mask */
+ ca = (struct bitvec) {
+ .data_len = sizeof(ca_buf),
+ .data = &ca_buf[0],
+ };
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ /* Skip non-provisioned transceivers */
+ if (trx->mo.nm_attr == NULL) {
+ LOGPTRX(trx, DPCU, LOGL_NOTICE, "not (yet) provisioned\n");
+ continue;
+ }
+
+ bitvec_set_bit_pos(&ca, trx->arfcn, ONE);
+ ts_info->ma_bit_len++;
+ }
+
+ /* Slot Allocation bit-mask */
+ sa = (struct bitvec) {
+ .data_len = sizeof(sa_buf),
+ .data = &sa_buf[0],
+ };
+
+ for (i = 0; i < ts->hopping.arfcn_num; i++) {
+ bitvec_set_bit_pos(&sa, ts->hopping.arfcn_list[i], ONE);
+ if (bitvec_get_bit_pos(&ca, ts->hopping.arfcn_list[i]) != ONE) {
+ LOGP(DPCU, LOGL_NOTICE, "A transceiver with ARFCN %u "
+ "is not (yet) provisioned\n", ts->hopping.arfcn_list[i]);
+ bitvec_set_bit_pos(&ca, ts->hopping.arfcn_list[i], ONE);
+ ts_info->ma_bit_len++;
+ }
+ }
+
+ /* Mobile Allocation bit-mask */
+ ma = (struct bitvec) {
+ .cur_bit = sizeof(ts_info->ma) * 8 - 1,
+ .data_len = sizeof(ts_info->ma),
+ .data = &ts_info->ma[0],
+ };
+
+ /* Skip ARFCN 0, it goes to the end of MA bit-mask */
+ for (i = 1; i < sizeof(ca_buf) * 8; i++) {
+ if (bitvec_get_bit_pos(&ca, i) != ONE)
+ continue;
+ if (bitvec_get_bit_pos(&sa, i) == ONE)
+ bitvec_set_bit_pos(&ma, ma.cur_bit, ONE);
+ ma.cur_bit--;
+ }
+
+ if (bitvec_get_bit_pos(&sa, 0) == ONE)
+ bitvec_set_bit_pos(&ma, ma.cur_bit, ONE);
+}
+
+static void info_ind_fill_trx(struct gsm_pcu_if_info_trx *trx_info,
+ const struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ trx_info->pdch_mask = 0;
+ trx_info->arfcn = trx->arfcn;
+ trx_info->hlayer1 = trx_get_hlayer1(trx);
+
+ if (trx->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
+ trx->mo.nm_state.administrative != NM_STATE_UNLOCKED) {
+ LOGPTRX(trx, DPCU, LOGL_INFO, "unavailable for PCU (op=%s adm=%s)\n",
+ abis_nm_opstate_name(trx->mo.nm_state.operational),
+ abis_nm_admin_name(trx->mo.nm_state.administrative));
+ return;
+ }
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (!ts_should_be_pdch(ts))
+ continue;
+
+ trx_info->pdch_mask |= (1 << tn);
+ trx_info->ts[tn].tsc = ts->tsc;
+
+ if (ts->hopping.enabled)
+ info_ind_fill_fhp(&trx_info->ts[tn], ts);
+
+ LOGPTRX(trx, DPCU, LOGL_INFO, "PDCH on ts=%u is available "
+ "(tsc=%u ", ts->nr, trx_info->ts[tn].tsc);
+ if (ts->hopping.enabled) {
+ LOGPC(DPCU, LOGL_INFO, "hopping=yes hsn=%u maio=%u ma_bit_len=%u)\n",
+ ts->hopping.hsn, ts->hopping.maio, trx_info->ts[tn].ma_bit_len);
+ } else {
+ LOGPC(DPCU, LOGL_INFO, "hopping=no arfcn=%u)\n", trx->arfcn);
+ }
+ }
+}
+
+static enum gsm_pcuif_bts_model bts_model_from_variant(enum gsm_bts_type_variant variant)
+{
+ switch (variant) {
+ case BTS_OSMO_LITECELL15:
+ return PCU_IF_BTS_MODEL_LC15;
+ case BTS_OSMO_OC2G:
+ return PCU_IF_BTS_MODEL_OC2G;
+ case BTS_OSMO_OCTPHY:
+ return PCU_IF_BTS_MODEL_OCTPHY;
+ case BTS_OSMO_SYSMO:
+ return PCU_IF_BTS_MODEL_SYSMO;
+ case BTS_OSMO_TRX:
+ case BTS_OSMO_VIRTUAL:
+ return PCU_IF_BTS_MODEL_TRX;
+ default:
+ return PCU_IF_BTS_MODEL_UNSPEC;
}
- return false;
}
int pcu_tx_info_ind(void)
{
- struct gsm_network *net = &bts_gsmnet;
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_info_ind *info_ind;
struct gsm_bts *bts;
struct gprs_rlc_cfg *rlcc;
- struct gsm_bts_gprs_nsvc *nsvc;
struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int i, j;
+ int i;
+ struct gsm_gprs_nse *nse;
LOGP(DPCU, LOGL_INFO, "Sending info\n");
+ nse = &g_bts_sm->gprs.nse;
/* FIXME: allow multiple BTS */
- bts = llist_entry(net->bts_list.next, struct gsm_bts, list);
+ bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
rlcc = &bts->gprs.cell.rlc_cfg;
msg = pcu_msgb_alloc(PCU_IF_MSG_INFO_IND, bts->nr);
@@ -142,18 +281,19 @@ int pcu_tx_info_ind(void)
LOGP(DPCU, LOGL_INFO, "BTS is down\n");
if (pcu_direct)
- info_ind->flags |= PCU_IF_FLAG_SYSMO;
+ info_ind->flags |= PCU_IF_FLAG_DIRECT_PHY;
+ info_ind->bsic = bts->bsic;
/* RAI */
- info_ind->mcc = net->plmn.mcc;
- info_ind->mnc = net->plmn.mnc;
- info_ind->mnc_3_digits = net->plmn.mnc_3_digits;
+ info_ind->mcc = g_bts_sm->plmn.mcc;
+ info_ind->mnc = g_bts_sm->plmn.mnc;
+ info_ind->mnc_3_digits = g_bts_sm->plmn.mnc_3_digits;
info_ind->lac = bts->location_area_code;
info_ind->rac = bts->gprs.rac;
/* NSE */
- info_ind->nsei = bts->gprs.nse.nsei;
- memcpy(info_ind->nse_timer, bts->gprs.nse.timer, 7);
+ info_ind->nsei = nse->nsei;
+ memcpy(info_ind->nse_timer, nse->timer, 7);
memcpy(info_ind->cell_timer, bts->gprs.cell.timer, 11);
/* cell attributes */
@@ -196,53 +336,56 @@ int pcu_tx_info_ind(void)
info_ind->flags |= PCU_IF_FLAG_MCS8;
if (rlcc->cs_mask & (1 << GPRS_MCS9))
info_ind->flags |= PCU_IF_FLAG_MCS9;
-#warning "isn't dl_tbf_ext wrong?: * 10 and no ntohs"
+ /* FIXME: isn't dl_tbf_ext wrong?: * 10 and no ntohs */
info_ind->dl_tbf_ext = rlcc->parameter[T_DL_TBF_EXT];
-#warning "isn't ul_tbf_ext wrong?: * 10 and no ntohs"
+ /* FIXME: isn't ul_tbf_ext wrong?: * 10 and no ntohs */
info_ind->ul_tbf_ext = rlcc->parameter[T_UL_TBF_EXT];
info_ind->initial_cs = rlcc->initial_cs;
info_ind->initial_mcs = rlcc->initial_mcs;
/* NSVC */
- for (i = 0; i < 2; i++) {
- nsvc = &bts->gprs.nsvc[i];
+ for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
+ const struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
info_ind->nsvci[i] = nsvc->nsvci;
- info_ind->local_port[i] = nsvc->local_port;
- info_ind->remote_port[i] = nsvc->remote_port;
- info_ind->remote_ip[i] = nsvc->remote_ip;
+ /* PCUIF beauty: the NSVC addresses are sent in the network byte order,
+ * while the port numbers need to be send in the host order. Sigh. */
+ info_ind->local_port[i] = ntohs(nsvc->local.u.sin.sin_port);
+ info_ind->remote_port[i] = ntohs(nsvc->remote.u.sin.sin_port);
+ switch (nsvc->remote.u.sas.ss_family) {
+ case AF_INET:
+ info_ind->address_type[i] = PCU_IF_ADDR_TYPE_IPV4;
+ info_ind->remote_ip[i].v4 = nsvc->remote.u.sin.sin_addr;
+ break;
+ case AF_INET6:
+ info_ind->address_type[i] = PCU_IF_ADDR_TYPE_IPV6;
+ info_ind->remote_ip[i].v6 = nsvc->remote.u.sin6.sin6_addr;
+ break;
+ default:
+ info_ind->address_type[i] = PCU_IF_ADDR_TYPE_UNSPEC;
+ break;
+ }
}
- for (i = 0; i < 8; i++) {
- trx = gsm_bts_trx_num(bts, i);
- if (!trx)
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->nr >= ARRAY_SIZE(info_ind->trx)) {
+ LOGPTRX(trx, DPCU, LOGL_NOTICE, "PCU interface (version %u) "
+ "cannot handle more than %zu transceivers => skipped\n",
+ PCU_IF_VERSION, ARRAY_SIZE(info_ind->trx));
break;
- info_ind->trx[i].pdch_mask = 0;
- info_ind->trx[i].arfcn = trx->arfcn;
- info_ind->trx[i].hlayer1 = trx_get_hlayer1(trx);
- for (j = 0; j < 8; j++) {
- ts = &trx->ts[j];
- if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED
- && ts_should_be_pdch(ts)) {
- info_ind->trx[i].pdch_mask |= (1 << j);
- info_ind->trx[i].tsc[j] = gsm_ts_tsc(ts);
-
- LOGP(DPCU, LOGL_INFO, "trx=%d ts=%d: "
- "available (tsc=%d arfcn=%d)\n",
- trx->nr, ts->nr,
- info_ind->trx[i].tsc[j],
- info_ind->trx[i].arfcn);
- }
}
+
+ info_ind_fill_trx(&info_ind->trx[trx->nr], trx);
}
- return pcu_sock_send(net, msg);
+ info_ind->bts_model = bts_model_from_variant(bts->variant);
+
+ return pcu_sock_send(msg);
}
static int pcu_if_signal_cb(unsigned int subsys, unsigned int signal,
void *hdlr_data, void *signal_data)
{
- struct gsm_network *net = &bts_gsmnet;
- struct gsm_bts_gprs_nsvc *nsvc;
+ struct gsm_gprs_nsvc *nsvc;
struct gsm_bts *bts;
struct gsm48_system_information_type_3 *si3;
int id;
@@ -257,7 +400,7 @@ static int pcu_if_signal_cb(unsigned int subsys, unsigned int signal,
break;
si3 = (struct gsm48_system_information_type_3 *)
bts->si_buf[SYSINFO_TYPE_3];
- osmo_plmn_from_bcd(si3->lai.digits, &net->plmn);
+ osmo_plmn_from_bcd(si3->lai.digits, &g_bts_sm->plmn);
bts->location_area_code = ntohs(si3->lai.lac);
bts->cell_identity = ntohs(si3->cell_identity);
avail_lai = 1;
@@ -283,6 +426,10 @@ static int pcu_if_signal_cb(unsigned int subsys, unsigned int signal,
return -EINVAL;
}
+ /* Do not send INFO.ind if PCU is not connected */
+ if (!pcu_connected())
+ return 0;
+
/* If all infos have been received, of if one info is updated after
* all infos have been received, transmit info update. */
if (avail_lai && avail_nse && avail_cell && avail_nsvc[0])
@@ -309,7 +456,7 @@ int pcu_tx_app_info_req(struct gsm_bts *bts, uint8_t app_type, uint8_t len, cons
ai_req->len = len;
memcpy(ai_req->data, app_data, ai_req->len);
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
@@ -336,7 +483,7 @@ int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
rts_req->ts_nr = ts->nr;
rts_req->block_nr = block_nr;
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn,
@@ -351,12 +498,6 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn,
LOGP(DPCU, LOGL_DEBUG, "Sending data indication: sapi=%s arfcn=%d block=%d data=%s\n",
sapi_string[sapi], arfcn, block_nr, osmo_hexdump(data, len));
- if (lqual < bts->min_qual_norm) {
- LOGP(DPCU, LOGL_DEBUG, "Link quality %"PRId16" is below threshold %d, dropping packet\n",
- lqual, bts->min_qual_norm);
- return 0;
- }
-
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_IND, bts->nr);
if (!msg)
return -ENOMEM;
@@ -373,14 +514,16 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn,
data_ind->ber10k = ber10k;
data_ind->ta_offs_qbits = bto;
data_ind->lqual_cb = lqual;
- memcpy(data_ind->data, data, len);
+ if (len)
+ memcpy(data_ind->data, data, len);
data_ind->len = len;
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
-int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn,
- uint8_t is_11bit, enum ph_burst_type burst_type)
+int pcu_tx_rach_ind(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
+ int16_t qta, uint16_t ra, uint32_t fn, uint8_t is_11bit,
+ enum ph_burst_type burst_type, uint8_t sapi)
{
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
@@ -389,20 +532,22 @@ int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn,
LOGP(DPCU, LOGL_INFO, "Sending RACH indication: qta=%d, ra=%d, "
"fn=%d\n", qta, ra, fn);
- msg = pcu_msgb_alloc(PCU_IF_MSG_RACH_IND, bts->nr);
+ msg = pcu_msgb_alloc(PCU_IF_MSG_RACH_IND, bts_nr);
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msg->data;
rach_ind = &pcu_prim->u.rach_ind;
- rach_ind->sapi = PCU_IF_SAPI_RACH;
+ rach_ind->sapi = sapi;
rach_ind->ra = ra;
rach_ind->qta = qta;
rach_ind->fn = fn;
rach_ind->is_11bit = is_11bit;
rach_ind->burst_type = burst_type;
+ rach_ind->trx_nr = trx_nr;
+ rach_ind->ts_nr = ts_nr;
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
int pcu_tx_time_ind(uint32_t fn)
@@ -424,12 +569,45 @@ int pcu_tx_time_ind(uint32_t fn)
time_ind->fn = fn;
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
+}
+
+int pcu_tx_interf_ind(const struct gsm_bts_trx *trx, uint32_t fn)
+{
+ struct gsm_pcu_if_interf_ind *interf_ind;
+ struct gsm_pcu_if *pcu_prim;
+ struct msgb *msg;
+ unsigned int tn;
+
+ msg = pcu_msgb_alloc(PCU_IF_MSG_INTERF_IND, trx->bts->nr);
+ if (!msg)
+ return -ENOMEM;
+ pcu_prim = (struct gsm_pcu_if *) msg->data;
+ interf_ind = &pcu_prim->u.interf_ind;
+
+ interf_ind->trx_nr = trx->nr;
+ interf_ind->fn = fn;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ const struct gsm_lchan *lchan = &ts->lchan[0];
+
+ if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (ts->mo.nm_state.availability != NM_AVSTATE_OK)
+ continue;
+ if (ts_pchan(ts) != GSM_PCHAN_PDCH)
+ continue;
+
+ interf_ind->interf[tn] = -1 * lchan->meas.interf_meas_avg_dbm;
+ }
+
+ return pcu_sock_send(msg);
}
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed)
{
- struct pcu_sock_state *state = bts_gsmnet.pcu_state;
+ struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
struct gsm_pcu_if_pag_req *pag_req;
@@ -457,34 +635,31 @@ int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed)
pag_req->chan_needed = chan_needed;
memcpy(pag_req->identity_lv, identity_lv, identity_lv[0] + 1);
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
-int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len)
+int pcu_tx_data_cnf(uint32_t msg_id, uint8_t sapi)
{
- struct gsm_network *net = &bts_gsmnet;
struct gsm_bts *bts;
struct msgb *msg;
struct gsm_pcu_if *pcu_prim;
- struct gsm_pcu_if_data *data_cnf;
/* FIXME: allow multiple BTS */
- bts = llist_entry(net->bts_list.next, struct gsm_bts, list);
+ bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
- LOGP(DPCU, LOGL_INFO, "Sending PCH confirm\n");
+ LOGP(DPCU, LOGL_DEBUG, "Sending DATA.cnf: sapi=%s msg_id=%08x\n",
+ sapi_string[sapi], msg_id);
- msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_CNF, bts->nr);
+ msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_CNF_2, bts->nr);
if (!msg)
return -ENOMEM;
pcu_prim = (struct gsm_pcu_if *) msg->data;
- data_cnf = &pcu_prim->u.data_cnf;
+ pcu_prim->u.data_cnf2 = (struct gsm_pcu_if_data_cnf) {
+ .sapi = sapi,
+ .msg_id = msg_id,
+ };
- data_cnf->sapi = PCU_IF_SAPI_PCH;
- data_cnf->fn = fn;
- memcpy(data_cnf->data, data, len);
- data_cnf->len = len;
-
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
/* forward data from a RR GPRS SUSPEND REQ towards PCU */
@@ -501,7 +676,7 @@ int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id
memcpy(pcu_prim->u.susp_req.ra_id, ra_id, sizeof(pcu_prim->u.susp_req.ra_id));
pcu_prim->u.susp_req.cause = cause;
- return pcu_sock_send(&bts_gsmnet, msg);
+ return pcu_sock_send(msg);
}
static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type,
@@ -519,22 +694,45 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type,
osmo_hexdump(data_req->data, data_req->len));
switch (data_req->sapi) {
- case PCU_IF_SAPI_PCH:
- paging_add_imm_ass(bts->paging_state, data_req->data, data_req->len);
+ case PCU_IF_SAPI_PCH_2:
+ {
+ const struct gsm_pcu_if_pch *gsm_pcu_if_pch;
+
+ if (OSMO_UNLIKELY(data_req->len != sizeof(*gsm_pcu_if_pch))) {
+ LOGP(DPCU, LOGL_ERROR, "Rx malformed DATA.req for PCH\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ gsm_pcu_if_pch = (struct gsm_pcu_if_pch *)data_req->data;
+ rc = paging_add_macblock(bts->paging_state, gsm_pcu_if_pch->msg_id,
+ gsm_pcu_if_pch->imsi, gsm_pcu_if_pch->confirm, gsm_pcu_if_pch->data);
break;
- case PCU_IF_SAPI_AGCH:
- msg = msgb_alloc(data_req->len, "pcu_agch");
+ }
+ case PCU_IF_SAPI_AGCH_2:
+ {
+ const struct gsm_pcu_if_agch *gsm_pcu_if_agch;
+ struct bts_agch_msg_cb *msg_cb;
+
+ gsm_pcu_if_agch = (struct gsm_pcu_if_agch *)data_req->data;
+
+ msg = msgb_alloc(GSM_MACBLOCK_LEN, "pcu_agch");
if (!msg) {
rc = -ENOMEM;
break;
}
- msg->l3h = msgb_put(msg, data_req->len);
- memcpy(msg->l3h, data_req->data, data_req->len);
+ msg->l3h = msgb_put(msg, GSM_MACBLOCK_LEN);
+ memcpy(msg->l3h, gsm_pcu_if_agch->data, GSM_MACBLOCK_LEN);
+
+ msg_cb = (struct bts_agch_msg_cb *) msg->cb;
+ msg_cb->confirm = gsm_pcu_if_agch->confirm;
+ msg_cb->msg_id = gsm_pcu_if_agch->msg_id;
if (bts_agch_enqueue(bts, msg) < 0) {
msgb_free(msg);
rc = -EIO;
}
break;
+ }
case PCU_IF_SAPI_PDTCH:
case PCU_IF_SAPI_PTCCH:
trx = gsm_bts_trx_num(bts, data_req->trx_nr);
@@ -594,24 +792,74 @@ static int pcu_rx_pag_req(struct gsm_bts *bts, uint8_t msg_type,
return rc;
}
-int pcu_tx_si13(const struct gsm_bts *bts, bool enable)
+int pcu_tx_si(const struct gsm_bts *bts, enum osmo_sysinfo_type si_type,
+ bool enable)
{
/* the SI is per-BTS so it doesn't matter which TRX we use */
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, 0);
- /* The low-level data like FN, ARFCN etc will be ignored but we have to set lqual high enough to bypass
- the check at lower levels */
- int rc = pcu_tx_data_ind(&trx->ts[0], PCU_IF_SAPI_BCCH, 0, 0, 0, GSM_BTS_SI(bts, SYSINFO_TYPE_13),
- enable ? GSM_MACBLOCK_LEN : 0, 0, 0, 0, INT16_MAX);
+ uint8_t si_buf[GSM_MACBLOCK_LEN];
+ uint8_t len;
+ int rc;
+
+ if (enable) {
+ memcpy(si_buf, GSM_BTS_SI(bts, si_type), GSM_MACBLOCK_LEN);
+ len = GSM_MACBLOCK_LEN;
+ LOGP(DPCU, LOGL_DEBUG, "Updating SI%s to PCU: %s\n",
+ get_value_string(osmo_sitype_strs, si_type),
+ osmo_hexdump_nospc(si_buf, GSM_MACBLOCK_LEN));
+ } else {
+ si_buf[0] = si_type;
+ len = 1;
+
+ /* Note: SI13 is the only system information type that is revked
+ * by just sending a completely empty message. This is due to
+ * historical reasons */
+ if (si_type != SYSINFO_TYPE_13)
+ len = 0;
+
+ LOGP(DPCU, LOGL_DEBUG, "Revoking SI%s from PCU\n",
+ get_value_string(osmo_sitype_strs, si_buf[0]));
+ }
+
+ /* The low-level data like FN, ARFCN etc will be ignored but we have to
+ * set lqual high enough to bypass the check at lower levels */
+ rc = pcu_tx_data_ind(&trx->ts[0], PCU_IF_SAPI_BCCH, 0, 0, 0, si_buf, len,
+ 0, 0, 0, INT16_MAX);
if (rc < 0)
- LOGP(DPCU, LOGL_NOTICE, "Failed to send SI13 to PCU: %d\n", rc);
+ LOGP(DPCU, LOGL_NOTICE, "Failed to send SI%s to PCU: rc=%d\n",
+ get_value_string(osmo_sitype_strs, si_type), rc);
return rc;
}
+static int pcu_tx_si_all(struct gsm_bts *bts)
+{
+ const enum osmo_sysinfo_type si_types[] =
+ { SYSINFO_TYPE_1, SYSINFO_TYPE_2, SYSINFO_TYPE_3, SYSINFO_TYPE_13 };
+ unsigned int i;
+ int rc = 0;
+
+ for (i = 0; i < ARRAY_SIZE(si_types); i++) {
+ if (GSM_BTS_HAS_SI(bts, si_types[i])) {
+ rc = pcu_tx_si(bts, si_types[i], true);
+ if (rc < 0)
+ return rc;
+ } else {
+ LOGP(DPCU, LOGL_INFO,
+ "SI%s is not available on PCU connection\n",
+ get_value_string(osmo_sitype_strs, si_types[i]));
+ }
+ }
+
+ return 0;
+}
+
static int pcu_rx_txt_ind(struct gsm_bts *bts,
struct gsm_pcu_if_txt_ind *txt)
{
+ int rc;
+
switch (txt->type) {
case PCU_VERSION:
LOGP(DPCU, LOGL_INFO, "OsmoPCU version %s connected\n",
@@ -619,13 +867,14 @@ static int pcu_rx_txt_ind(struct gsm_bts *bts,
oml_tx_failure_event_rep(&bts->gprs.cell.mo, NM_SEVER_CEASED, OSMO_EVT_PCU_VERS, txt->text);
osmo_strlcpy(bts->pcu_version, txt->text, MAX_VERSION_LENGTH);
- /* patch SI3 to advertise GPRS, *if* the SI3 sent by BSC said so */
+ /* patch SI to advertise GPRS, *if* the SI sent by BSC said so */
regenerate_si3_restoctets(bts);
+ regenerate_si4_restoctets(bts);
- if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_13))
- return pcu_tx_si13(bts, true);
+ rc = pcu_tx_si_all(bts);
+ if (rc < 0)
+ return -EINVAL;
- LOGP(DPCU, LOGL_INFO, "SI13 is not available on PCU connection\n");
break;
case PCU_OML_ALERT:
oml_tx_failure_event_rep(&bts->gprs.cell.mo, NM_SEVER_INDETERMINATE, OSMO_EVT_EXT_ALARM,
@@ -646,7 +895,7 @@ static int pcu_rx_act_req(struct gsm_bts *bts,
struct gsm_bts_trx *trx;
struct gsm_lchan *lchan;
- LOGP(DPCU, LOGL_INFO, "%s request received: TRX=%d TX=%d\n",
+ LOGP(DPCU, LOGL_INFO, "%s request received: TRX=%d TS=%d\n",
(act_req->activate) ? "Activate" : "Deactivate",
act_req->trx_nr, act_req->ts_nr);
@@ -663,40 +912,70 @@ static int pcu_rx_act_req(struct gsm_bts *bts,
gsm_lchant_name(lchan->type));
return -EINVAL;
}
+ if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN &&
+ lchan->ts->dyn.pchan_is != GSM_PCHAN_PDCH) {
+ LOGP(DPCU, LOGL_ERROR,
+ "%s request, but lchan in dyn TS is not configured as PDCH in lower layers (is %s)\n",
+ (act_req->activate) ? "Activate" : "Deactivate",
+ gsm_pchan_name(lchan->ts->dyn.pchan_is));
+ return -EINVAL;
+ }
if (act_req->activate)
- l1sap_chan_act(trx, gsm_lchan2chan_nr(lchan), NULL);
+ l1sap_chan_act(trx, gsm_lchan2chan_nr(lchan));
else
l1sap_chan_rel(trx, gsm_lchan2chan_nr(lchan));
return 0;
}
-static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
- struct gsm_pcu_if *pcu_prim)
+#define CHECK_IF_MSG_SIZE(prim_len, prim_msg) \
+ do { \
+ size_t _len = PCUIF_HDR_SIZE + sizeof(prim_msg); \
+ if (prim_len < _len) { \
+ LOGP(DPCU, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive %s " \
+ "size is %zu, discarding\n", prim_len, #prim_msg, _len); \
+ return -EINVAL; \
+ } \
+ } while (0)
+static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim, size_t prim_len)
{
int rc = 0;
struct gsm_bts *bts;
+ size_t exp_len;
- /* FIXME: allow multiple BTS */
- if (pcu_prim->bts_nr != 0) {
+ if ((bts = gsm_bts_num(g_bts_sm, pcu_prim->bts_nr)) == NULL) {
LOGP(DPCU, LOGL_ERROR, "Received PCU Prim for non-existent BTS %u\n", pcu_prim->bts_nr);
return -EINVAL;
}
- bts = llist_entry(net->bts_list.next, struct gsm_bts, list);
switch (msg_type) {
case PCU_IF_MSG_DATA_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.data_req);
rc = pcu_rx_data_req(bts, msg_type, &pcu_prim->u.data_req);
break;
case PCU_IF_MSG_PAG_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.pag_req);
rc = pcu_rx_pag_req(bts, msg_type, &pcu_prim->u.pag_req);
break;
case PCU_IF_MSG_ACT_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.act_req);
rc = pcu_rx_act_req(bts, &pcu_prim->u.act_req);
break;
case PCU_IF_MSG_TXT_IND:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.txt_ind);
rc = pcu_rx_txt_ind(bts, &pcu_prim->u.txt_ind);
break;
+ case PCU_IF_MSG_CONTAINER:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.container);
+ /* ^ check if we can access container fields, v check with container data length */
+ exp_len = PCUIF_HDR_SIZE + sizeof(pcu_prim->u.container) + osmo_load16be(&pcu_prim->u.container.length);
+ if (prim_len < exp_len) {
+ LOGP(DPCU, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive "
+ "container size is %zu, discarding\n", prim_len, exp_len);
+ return -EINVAL;
+ }
+ rc = abis_osmo_pcu_tx_container(bts, &pcu_prim->u.container);
+ break;
default:
LOGP(DPCU, LOGL_ERROR, "Received unknown PCU msg type %d\n",
msg_type);
@@ -711,49 +990,58 @@ static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
*/
struct pcu_sock_state {
- struct gsm_network *net;
struct osmo_fd listen_bfd; /* fd for listen socket */
- struct osmo_fd conn_bfd; /* fd for connection to lcr */
- struct llist_head upqueue; /* queue for sending messages */
+ struct osmo_wqueue upqueue; /* For sending messages; has fd for conn. to PCU */
};
-static int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
+static void pcu_sock_close(struct pcu_sock_state *state);
+
+int pcu_sock_send(struct msgb *msg)
{
- struct pcu_sock_state *state = net->pcu_state;
+ struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
struct osmo_fd *conn_bfd;
struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *) msg->data;
+ int rc;
if (!state) {
- if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND)
+ if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND &&
+ pcu_prim->msg_type != PCU_IF_MSG_INTERF_IND)
LOGP(DPCU, LOGL_INFO, "PCU socket not created, "
"dropping message\n");
msgb_free(msg);
return -EINVAL;
}
- conn_bfd = &state->conn_bfd;
+ conn_bfd = &state->upqueue.bfd;
if (conn_bfd->fd <= 0) {
- if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND)
+ if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND &&
+ pcu_prim->msg_type != PCU_IF_MSG_INTERF_IND)
LOGP(DPCU, LOGL_NOTICE, "PCU socket not connected, "
"dropping message\n");
msgb_free(msg);
return -EIO;
}
- msgb_enqueue(&state->upqueue, msg);
- conn_bfd->when |= BSC_FD_WRITE;
+ rc = osmo_wqueue_enqueue(&state->upqueue, msg);
+ if (rc < 0) {
+ if (rc == -ENOSPC)
+ LOGP(DPCU, LOGL_NOTICE, "PCU not reacting (more than %u messages waiting). Closing connection\n",
+ state->upqueue.max_length);
+ pcu_sock_close(state);
+ msgb_free(msg);
+ return rc;
+ }
return 0;
}
static void pcu_sock_close(struct pcu_sock_state *state)
{
- struct osmo_fd *bfd = &state->conn_bfd;
+ struct osmo_fd *bfd = &state->upqueue.bfd;
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int i, j;
+ unsigned int tn;
/* FIXME: allow multiple BTS */
- bts = llist_entry(state->net->bts_list.next, struct gsm_bts, list);
+ bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
LOGP(DPCU, LOGL_NOTICE, "PCU socket has LOST connection\n");
oml_tx_failure_event_rep(&bts->gprs.cell.mo, NM_SEVER_MAJOR, OSMO_EVT_PCU_VERS,
@@ -761,15 +1049,16 @@ static void pcu_sock_close(struct pcu_sock_state *state)
bts->pcu_version[0] = '\0';
+ osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
- osmo_fd_unregister(bfd);
/* patch SI3 to remove GPRS indicator */
regenerate_si3_restoctets(bts);
+ regenerate_si4_restoctets(bts);
/* re-enable the generation of ACCEPT for new connections */
- state->listen_bfd.when |= BSC_FD_READ;
+ osmo_fd_read_enable(&state->listen_bfd);
#if 0
/* remove si13, ... */
@@ -777,27 +1066,22 @@ static void pcu_sock_close(struct pcu_sock_state *state)
osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts);
#endif
- /* release PDCH */
- for (i = 0; i < 8; i++) {
- trx = gsm_bts_trx_num(bts, i);
- if (!trx)
- break;
- for (j = 0; j < 8; j++) {
- ts = &trx->ts[j];
- if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED
- && ts->pchan == GSM_PCHAN_PDCH) {
- ts->lchan[0].rel_act_kind = LCHAN_REL_ACT_PCU;
- l1sap_chan_rel(trx,
- gsm_lchan2chan_nr(&ts->lchan[0]));
- }
+ /* Deactivate all active PDCH timeslots */
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ for (tn = 0; tn < 8; tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (!ts_should_be_pdch(ts))
+ continue;
+
+ ts->lchan[0].rel_act_kind = LCHAN_REL_ACT_PCU;
+ l1sap_chan_rel(trx, gsm_lchan2chan_nr(&ts->lchan[0]));
}
}
- /* flush the queue */
- while (!llist_empty(&state->upqueue)) {
- struct msgb *msg = msgb_dequeue(&state->upqueue);
- msgb_free(msg);
- }
+ osmo_wqueue_clear(&state->upqueue);
}
static int pcu_sock_read(struct osmo_fd *bfd)
@@ -807,7 +1091,7 @@ static int pcu_sock_read(struct osmo_fd *bfd)
struct msgb *msg;
int rc;
- msg = msgb_alloc(sizeof(*pcu_prim), "pcu_sock_rx");
+ msg = msgb_alloc(sizeof(*pcu_prim) + 1000, "pcu_sock_rx");
if (!msg)
return -ENOMEM;
@@ -825,14 +1109,14 @@ static int pcu_sock_read(struct osmo_fd *bfd)
goto close;
}
- if (rc < sizeof(*pcu_prim)) {
- LOGP(DPCU, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive size "
- "is %zu, discarding\n", rc, sizeof(*pcu_prim));
+ if (rc < PCUIF_HDR_SIZE) {
+ LOGP(DPCU, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive hdr size "
+ "is %zu, discarding\n", rc, PCUIF_HDR_SIZE);
msgb_free(msg);
return 0;
}
- rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim);
+ rc = pcu_rx(pcu_prim->msg_type, pcu_prim, rc);
/* as we always synchronously process the message in pcu_rx() and
* its callbacks, we can free the message here. */
@@ -846,102 +1130,57 @@ close:
return -1;
}
-static int pcu_sock_write(struct osmo_fd *bfd)
+static int pcu_sock_write(struct osmo_fd *bfd, struct msgb *msg)
{
struct pcu_sock_state *state = bfd->data;
int rc;
- while (!llist_empty(&state->upqueue)) {
- struct msgb *msg, *msg2;
- struct gsm_pcu_if *pcu_prim;
-
- /* peek at the beginning of the queue */
- msg = llist_entry(state->upqueue.next, struct msgb, list);
- pcu_prim = (struct gsm_pcu_if *)msg->data;
-
- bfd->when &= ~BSC_FD_WRITE;
-
- /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
- if (!msgb_length(msg)) {
- LOGP(DPCU, LOGL_ERROR, "message type (%d) with ZERO "
- "bytes!\n", pcu_prim->msg_type);
- goto dontsend;
- }
-
- /* try to send it over the socket */
- rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
- if (rc == 0)
- goto close;
- if (rc < 0) {
- if (errno == EAGAIN) {
- bfd->when |= BSC_FD_WRITE;
- break;
- }
- goto close;
- }
-
-dontsend:
- /* _after_ we send it, we can deueue */
- msg2 = msgb_dequeue(&state->upqueue);
- assert(msg == msg2);
- msgb_free(msg);
+ /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
+ OSMO_ASSERT(msgb_length(msg) > 0);
+ /* try to send it over the socket */
+ rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+ if (OSMO_UNLIKELY(rc == 0))
+ goto close;
+ if (OSMO_UNLIKELY(rc < 0)) {
+ if (errno == EAGAIN)
+ return -EAGAIN;
+ return -1;
}
return 0;
close:
pcu_sock_close(state);
-
return -1;
}
-static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
-{
- int rc = 0;
-
- if (flags & BSC_FD_READ)
- rc = pcu_sock_read(bfd);
- if (rc < 0)
- return rc;
-
- if (flags & BSC_FD_WRITE)
- rc = pcu_sock_write(bfd);
-
- return rc;
-}
-
-/* accept connection comming from PCU */
+/* accept connection coming from PCU */
static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags)
{
struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data;
- struct osmo_fd *conn_bfd = &state->conn_bfd;
+ struct osmo_fd *conn_bfd = &state->upqueue.bfd;
struct sockaddr_un un_addr;
socklen_t len;
- int rc;
+ int fd;
len = sizeof(un_addr);
- rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len);
- if (rc < 0) {
+ fd = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
+ if (fd < 0) {
LOGP(DPCU, LOGL_ERROR, "Failed to accept a new connection\n");
return -1;
}
if (conn_bfd->fd >= 0) {
- LOGP(DPCU, LOGL_NOTICE, "PCU connects but we already have "
- "another active connection ?!?\n");
+ LOGP(DPCU, LOGL_NOTICE, "PCU connects but we already have another active connection ?!?\n");
/* We already have one PCU connected, this is all we support */
- state->listen_bfd.when &= ~BSC_FD_READ;
- close(rc);
+ osmo_fd_read_disable(&state->listen_bfd);
+ close(fd);
return 0;
}
- conn_bfd->fd = rc;
- conn_bfd->when = BSC_FD_READ;
- conn_bfd->cb = pcu_sock_cb;
- conn_bfd->data = state;
+ osmo_fd_setup(conn_bfd, fd, OSMO_FD_READ, osmo_wqueue_bfd_cb, state, 0);
if (osmo_fd_register(conn_bfd) != 0) {
- LOGP(DPCU, LOGL_ERROR, "Failed to register new connection "
- "fd\n");
+ LOGP(DPCU, LOGL_ERROR, "Failed to register new connection fd\n");
close(conn_bfd->fd);
conn_bfd->fd = -1;
return -1;
@@ -955,34 +1194,32 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags)
return 0;
}
-int pcu_sock_init(const char *path)
+int pcu_sock_init(const char *path, int qlength_max)
{
struct pcu_sock_state *state;
struct osmo_fd *bfd;
int rc;
- state = talloc_zero(NULL, struct pcu_sock_state);
+ state = talloc_zero(g_bts_sm, struct pcu_sock_state);
if (!state)
return -ENOMEM;
- INIT_LLIST_HEAD(&state->upqueue);
- state->net = &bts_gsmnet;
- state->conn_bfd.fd = -1;
+ osmo_wqueue_init(&state->upqueue, qlength_max);
+ state->upqueue.read_cb = pcu_sock_read;
+ state->upqueue.write_cb = pcu_sock_write;
+ state->upqueue.bfd.fd = -1;
bfd = &state->listen_bfd;
- bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path,
- OSMO_SOCK_F_BIND);
- if (bfd->fd < 0) {
+ rc = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND);
+ if (rc < 0) {
LOGP(DPCU, LOGL_ERROR, "Could not create %s unix socket: %s\n",
path, strerror(errno));
talloc_free(state);
return -1;
}
- bfd->when = BSC_FD_READ;
- bfd->cb = pcu_sock_accept;
- bfd->data = state;
+ osmo_fd_setup(bfd, rc, OSMO_FD_READ, pcu_sock_accept, state, 0);
rc = osmo_fd_register(bfd);
if (rc < 0) {
@@ -995,39 +1232,38 @@ int pcu_sock_init(const char *path)
osmo_signal_register_handler(SS_GLOBAL, pcu_if_signal_cb, NULL);
- bts_gsmnet.pcu_state = state;
+ g_bts_sm->gprs.pcu_state = state;
- LOGP(DPCU, LOGL_INFO, "Started listening on PCU socket: %s\n", path);
+ LOGP(DPCU, LOGL_INFO, "Started listening on PCU socket (PCU IF v%u): %s\n", PCU_IF_VERSION, path);
return 0;
}
void pcu_sock_exit(void)
{
- struct pcu_sock_state *state = bts_gsmnet.pcu_state;
+ struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
struct osmo_fd *bfd, *conn_bfd;
if (!state)
return;
osmo_signal_unregister_handler(SS_GLOBAL, pcu_if_signal_cb, NULL);
- conn_bfd = &state->conn_bfd;
+ conn_bfd = &state->upqueue.bfd;
if (conn_bfd->fd > 0)
pcu_sock_close(state);
bfd = &state->listen_bfd;
close(bfd->fd);
osmo_fd_unregister(bfd);
talloc_free(state);
- bts_gsmnet.pcu_state = NULL;
+ g_bts_sm->gprs.pcu_state = NULL;
}
bool pcu_connected(void) {
- struct gsm_network *net = &bts_gsmnet;
- struct pcu_sock_state *state = net->pcu_state;
+ struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
if (!state)
return false;
- if (state->conn_bfd.fd <= 0)
+ if (state->upqueue.bfd.fd <= 0)
return false;
return true;
}
diff --git a/src/common/phy_link.c b/src/common/phy_link.c
index 588fcc91..352d8f72 100644
--- a/src/common/phy_link.c
+++ b/src/common/phy_link.c
@@ -2,6 +2,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/gsm_data.h>
@@ -9,6 +10,7 @@
#include <osmo-bts/oml.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts_model.h>
+#include <osmo-bts/nm_common_fsm.h>
static LLIST_HEAD(g_phy_links);
@@ -53,9 +55,11 @@ 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));
+ LOGPPHL(plink, 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));
+
+ plink->state = state;
/* notify all TRX associated with this phy */
llist_for_each_entry(pinst, &plink->instances, list) {
@@ -63,25 +67,28 @@ void phy_link_state_set(struct phy_link *plink, enum phy_link_state state)
if (!trx)
continue;
- switch (state) {
- case PHY_LINK_CONNECTED:
- LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n");
- trx_set_available(trx, 1);
- break;
- case PHY_LINK_SHUTDOWN:
- LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n");
- trx_set_available(trx, 0);
- break;
- case PHY_LINK_CONNECTING:
- /* nothing to do */
- break;
- }
+ osmo_fsm_inst_dispatch(trx->mo.fi,
+ state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP :
+ NM_EV_PHYLINK_DOWN,
+ NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi,
+ state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP :
+ NM_EV_PHYLINK_DOWN,
+ NULL);
}
+}
- plink->state = state;
+enum phy_link_state phy_link_state_get(struct phy_link *plink)
+{
+ return plink->state;
+}
+
+const char *phy_link_state_name(enum phy_link_state state)
+{
+ return get_value_string(phy_link_state_vals, state);
}
-struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num)
+struct phy_instance *phy_instance_by_num(const struct phy_link *plink, int num)
{
struct phy_instance *pinst;
@@ -111,7 +118,9 @@ 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)
{
- trx->role_bts.l1h = pinst;
+ /* There might already be an associated TRX */
+ OSMO_ASSERT(pinst->trx == NULL)
+ trx->pinst = pinst;
pinst->trx = trx;
}
@@ -120,10 +129,12 @@ 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;
+ /* remove reverse link from TRX (if associated) */
+ if (pinst->trx != NULL) {
+ OSMO_ASSERT(pinst->trx->pinst == pinst);
+ pinst->trx->pinst = NULL;
+ pinst->trx = NULL;
+ }
talloc_free(pinst);
}
@@ -138,13 +149,29 @@ void phy_link_destroy(struct phy_link *plink)
talloc_free(plink);
}
+static char name_buf[32];
+const char *phy_link_name(const struct phy_link *plink)
+{
+ snprintf(name_buf, sizeof(name_buf), "phy%u", plink->num);
+ return name_buf;
+}
+
int phy_links_open(void)
{
+ const struct phy_instance *pinst;
struct phy_link *plink;
llist_for_each_entry(plink, &g_phy_links, list) {
int rc;
+ /* Warn about dangling PHY instances */
+ llist_for_each_entry(pinst, &plink->instances, list) {
+ if (pinst->trx != NULL)
+ continue;
+ LOGPPHI(pinst, DL1C, LOGL_NOTICE, "This PHY instance is not associated "
+ "with a TRX instance, check the configuration file!\n");
+ }
+
rc = bts_model_phy_link_open(plink);
if (rc < 0)
return rc;
@@ -153,11 +180,9 @@ int phy_links_open(void)
return 0;
}
-const char *phy_instance_name(struct phy_instance *pinst)
+const char *phy_instance_name(const struct phy_instance *pinst)
{
- static char buf[32];
-
- snprintf(buf, sizeof(buf), "phy%u.%u", pinst->phy_link->num,
+ snprintf(name_buf, sizeof(name_buf), "phy%u.%u", pinst->phy_link->num,
pinst->num);
- return buf;
+ return name_buf;
}
diff --git a/src/common/power_control.c b/src/common/power_control.c
index b1728705..7f98a417 100644
--- a/src/common/power_control.c
+++ b/src/common/power_control.c
@@ -1,6 +1,8 @@
/* MS Power Control Loop L1 */
/* (C) 2014 by Holger Hans Peter Freyther
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
*
* All Rights Reserved
*
@@ -12,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -22,6 +24,7 @@
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
+#include <inttypes.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
@@ -29,61 +32,544 @@
#include <osmo-bts/measurement.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/power_control.h>
-/*
- * Check if manual power control is needed
- * Check if fixed power was selected
- * Check if the MS is already using our level if not
- * the value is bogus..
- * TODO: Add a timeout.. e.g. if the ms is not capable of reaching
- * the value we have set.
+/* We don't want to deal with floating point, so we scale up */
+#define EWMA_SCALE_FACTOR 100
+/* EWMA_SCALE_FACTOR/2 = +50: Round to nearest value when downscaling, otherwise floor() is applied. */
+#define EWMA_ROUND_FACTOR (EWMA_SCALE_FACTOR / 2)
+
+/* Base Low-Pass Single-Pole IIR Filter (EWMA) formula:
+ *
+ * Avg[n] = a * Val[n] + (1 - a) * Avg[n - 1]
+ *
+ * where parameter 'a' determines how much weight of the latest measurement value
+ * 'Val[n]' carries vs the weight of the accumulated average 'Avg[n - 1]'. The
+ * value of 'a' is usually a float in range 0 .. 1, so:
+ *
+ * - value 0.5 gives equal weight to both 'Val[n]' and 'Avg[n - 1]';
+ * - value 1.0 means no filtering at all (pass through);
+ * - value 0.0 makes no sense.
+ *
+ * Further optimization:
+ *
+ * Avg[n] = a * Val[n] + Avg[n - 1] - a * Avg[n - 1]
+ * ^^^^^^ ^^^^^^^^^^
+ *
+ * a) this can be implemented in C using '+=' operator:
+ *
+ * Avg += a * Val - a * Avg
+ * Avg += a * (Val - Avg)
+ *
+ * b) everything is scaled up by 100 to avoid floating point stuff:
+ *
+ * Avg100 += A * (Val - Avg)
+ *
+ * where 'Avg100' is 'Avg * 100' and 'A' is 'a * 100'.
+ *
+ * For more details, see:
+ *
+ * https://en.wikipedia.org/wiki/Moving_average
+ * https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter
+ * https://tomroelandts.com/articles/low-pass-single-pole-iir-filter
+ */
+static int do_pf_ewma(const struct gsm_power_ctrl_meas_params *mp,
+ struct gsm_power_ctrl_meas_proc_state *mps,
+ const int Val)
+{
+ const uint8_t A = mp->ewma.alpha;
+ int *Avg100 = &mps->ewma.Avg100;
+
+ /* We don't have 'Avg[n - 1]' if this is the first run */
+ if (mps->meas_num++ == 0) {
+ *Avg100 = Val * EWMA_SCALE_FACTOR;
+ return Val;
+ }
+
+ *Avg100 += A * (Val - (*Avg100 + EWMA_ROUND_FACTOR) / EWMA_SCALE_FACTOR);
+ return (*Avg100 + EWMA_ROUND_FACTOR) / EWMA_SCALE_FACTOR;
+}
+
+/* Calculate target RxLev value from lower/upper thresholds */
+#define CALC_TARGET(mp) \
+ ((mp).lower_thresh + (mp).upper_thresh) / 2
+
+static int do_avg_algo(const struct gsm_power_ctrl_meas_params *mp,
+ struct gsm_power_ctrl_meas_proc_state *mps,
+ const int val)
+{
+ int val_avg;
+ switch (mp->algo) {
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA:
+ val_avg = do_pf_ewma(mp, mps, val);
+ break;
+ /* TODO: implement other pre-processing methods */
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE:
+ default:
+ /* No filtering (pass through) */
+ val_avg = val;
+ }
+ return val_avg;
+}
+/* Calculate a 'delta' value (for the given MS/BS power control parameters)
+ * to be applied to the current Tx power level to approach the target level. */
+static int calc_delta_rxlev(const struct gsm_power_ctrl_params *params, const uint8_t rxlev)
+{
+ int delta;
+
+ /* Check if RxLev is within the threshold window */
+ if (rxlev >= params->rxlev_meas.lower_thresh &&
+ rxlev <= params->rxlev_meas.upper_thresh)
+ return 0;
+
+ /* How many dBs measured power should be increased (+) or decreased (-)
+ * to reach expected power. */
+ delta = CALC_TARGET(params->rxlev_meas) - rxlev;
+
+ /* Don't ever change more than PWR_{LOWER,RAISE}_MAX_DBM during one loop
+ * iteration, i.e. reduce the speed at which the MS transmit power can
+ * change. A higher value means a lower level (and vice versa) */
+ if (delta > params->inc_step_size_db)
+ delta = params->inc_step_size_db;
+ else if (delta < -params->red_step_size_db)
+ delta = -params->red_step_size_db;
+
+ return delta;
+}
+
+/* Shall we skip current block based on configured interval? */
+static bool ctrl_interval_skip_block(const struct gsm_power_ctrl_params *params,
+ struct lchan_power_ctrl_state *state)
+{
+ /* Power control interval: how many blocks do we skip? */
+ if (state->skip_block_num-- > 0)
+ return true;
+
+ /* Reset the number of SACCH blocks to be skipped:
+ * ctrl_interval=0 => 0 blocks to skip,
+ * ctrl_interval=1 => 1 blocks to skip,
+ * ctrl_interval=2 => 3 blocks to skip,
+ * so basically ctrl_interval * 2 - 1. */
+ state->skip_block_num = params->ctrl_interval * 2 - 1;
+ return false;
+}
+
+static const struct gsm_power_ctrl_meas_params *lchan_get_ci_thresholds(const struct gsm_lchan *lchan)
+{
+ const struct gsm_power_ctrl_params *params = lchan->ms_power_ctrl.dpc_params;
+
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ return &params->ci_sdcch_meas;
+ case GSM_LCHAN_PDTCH:
+ return &params->ci_gprs_meas;
+ case GSM_LCHAN_TCH_F:
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
+ return &params->ci_amr_fr_meas;
+ else
+ return &params->ci_fr_meas;
+ case GSM_LCHAN_TCH_H:
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
+ return &params->ci_amr_hr_meas;
+ else
+ return &params->ci_hr_meas;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+/*! compute the new MS POWER LEVEL communicated to the MS and store it in lchan.
+ * \param lchan logical channel for which to compute (and in which to store) new power value.
+ * \param[in] ms_power_lvl MS Power Level received from Uplink L1 SACCH Header in SACCH block.
+ * \param[in] ul_rssi_dbm Signal level of the received SACCH block, in dBm.
+ * \param[in] ul_lqual_cb C/I of the received SACCH block, in dB.
*/
int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
- const uint8_t ms_power, const int rxLevel)
+ const uint8_t ms_power_lvl,
+ const int8_t ul_rssi_dbm,
+ const int16_t ul_lqual_cb)
{
- int rx;
- int cur_dBm, new_dBm, new_pwr;
- struct gsm_bts *bts = lchan->ts->trx->bts;
- const enum gsm_band band = bts->band;
+ struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;
+ const struct gsm_power_ctrl_params *params = state->dpc_params;
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+ struct gsm_bts *bts = trx->bts;
+ enum gsm_band band = bts->band;
+ int8_t new_power_lvl; /* TS 05.05 power level */
+ int8_t ms_dbm, new_dbm, current_dbm, bsc_max_dbm;
+ uint8_t rxlev_avg;
+ int16_t ul_lqual_cb_avg;
+ const struct gsm_power_ctrl_meas_params *ci_meas;
+ bool ignore, ci_on;
- if (!trx_ms_pwr_ctrl_is_osmo(lchan->ts->trx))
+ if (!trx_ms_pwr_ctrl_is_osmo(trx))
return 0;
- if (lchan->ms_power_ctrl.fixed)
+ if (params == NULL)
return 0;
- /* The phone hasn't reached the power level yet */
- if (lchan->ms_power_ctrl.current != ms_power)
+ /* Shall we skip current block based on configured interval? */
+ if (ctrl_interval_skip_block(params, state))
return 0;
- /* What is the difference between what we want and received? */
- rx = bts->ul_power_target - rxLevel;
+ ms_dbm = ms_pwr_dbm(band, ms_power_lvl);
+ if (ms_dbm < 0) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE,
+ "Failed to calculate dBm for power ctl level %" PRIu8 " on band %s\n",
+ ms_power_lvl, gsm_band_name(band));
+ return 0;
+ }
+ bsc_max_dbm = ms_pwr_dbm(band, state->max);
+ if (bsc_max_dbm < 0) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE,
+ "Failed to calculate dBm for power ctl level %" PRIu8 " on band %s\n",
+ state->max, gsm_band_name(band));
+ return 0;
+ }
- cur_dBm = ms_pwr_dbm(band, ms_power);
- new_dBm = cur_dBm + rx;
+ ci_meas = lchan_get_ci_thresholds(lchan);
- /* Clamp negative values and do it depending on the band */
- if (new_dBm < 0)
- new_dBm = 0;
+ /* Is C/I based algo enabled by config?
+ * FIXME: this can later be generalized when properly implementing P & N counting. */
+ ci_on = ci_meas->lower_cmp_n && ci_meas->upper_cmp_n;
- switch (band) {
- case GSM_BAND_1800:
- /* If MS_TX_PWR_MAX_CCH is set the values 29,
- * 30, 31 are not used. Avoid specifying a dBm
- * that would lead to these power levels. The
- * phone might not be able to reach them. */
- if (new_dBm > 30)
- new_dBm = 30;
- break;
- default:
- break;
+ ul_lqual_cb_avg = do_avg_algo(ci_meas, &state->ci_meas_proc, ul_lqual_cb);
+ rxlev_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, dbm2rxlev(ul_rssi_dbm));
+
+ /* If computed C/I is enabled and out of acceptable thresholds: */
+ if (ci_on && ul_lqual_cb_avg < ci_meas->lower_thresh * 10) {
+ new_dbm = ms_dbm + params->inc_step_size_db;
+ } else if (ci_on && ul_lqual_cb_avg > ci_meas->upper_thresh * 10) {
+ new_dbm = ms_dbm - params->red_step_size_db;
+ } else {
+ /* Calculate the new Tx power value (in dBm) */
+ new_dbm = ms_dbm + calc_delta_rxlev(params, rxlev_avg);
}
- new_pwr = ms_pwr_ctl_lvl(band, new_dBm);
- if (lchan->ms_power_ctrl.current != new_pwr) {
- lchan->ms_power_ctrl.current = new_pwr;
- bts_model_adjst_ms_pwr(lchan);
- return 1;
+ /* Make sure new_dbm is never negative. ms_pwr_ctl_lvl() can later on
+ cope with any unsigned dbm value, regardless of band minimal value. */
+ if (new_dbm < 0)
+ new_dbm = 0;
+
+ /* Don't ask for smaller ms power level than the one set by BSC upon RSL CHAN ACT */
+ if (new_dbm > bsc_max_dbm)
+ new_dbm = bsc_max_dbm;
+
+ new_power_lvl = ms_pwr_ctl_lvl(band, new_dbm);
+ if (new_power_lvl < 0) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE,
+ "Failed to retrieve power level for %" PRId8 " dBm on band %d\n",
+ new_dbm, band);
+ return 0;
}
- return 0;
+ current_dbm = ms_pwr_dbm(band, state->current);
+
+ /* In this Power Control Loop, we infer a new good MS Power Level based
+ * on the previous MS Power Level announced by the MS (not the previous
+ * one we requested!) together with the related computed measurements.
+ * Hence, and since we allow for several good MS Power Levels falling into our
+ * thresholds, we could finally converge into an oscillation loop where
+ * the MS bounces between 2 different correct MS Power levels all the
+ * time, due to the fact that we "accept" and "request back" whatever
+ * good MS Power Level we received from the MS, but at that time the MS
+ * will be transmitting using the previous MS Power Level we
+ * requested, which we will later "accept" and "request back" on next loop
+ * iteration. As a result MS effectively bounces between those 2 MS
+ * Power Levels.
+ * In order to fix this permanent oscillation, if current MS_PWR used/announced
+ * by MS is good ("ms_dbm == new_dbm", hence within thresholds and no change
+ * required) but has higher Tx power than the one we last requested, we ignore
+ * it and keep requesting for one with lower Tx power. This way we converge to
+ * the lowest good Tx power avoiding oscillating over values within thresholds.
+ */
+ ignore = (ms_dbm == new_dbm && ms_dbm > current_dbm);
+
+ if (state->current == new_power_lvl || ignore) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS power at control level %d (%d dBm): "
+ "ms-pwr-lvl[curr %" PRIu8 ", max %" PRIu8 "], RSSI[curr %d, avg %d, thresh %d..%d] dBm,"
+ " C/I[curr %d, avg %d, thresh %d..%d] dB\n",
+ new_power_lvl, new_dbm, ms_power_lvl, state->max, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
+ rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
+ ul_lqual_cb/10, ul_lqual_cb_avg/10, ci_meas->lower_thresh, ci_meas->upper_thresh);
+ return 0;
+ }
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "%s MS power control level %d (%d dBm) => %d (%d dBm): "
+ "ms-pwr-lvl[curr %" PRIu8 ", max %" PRIu8 "], RSSI[curr %d, avg %d, thresh %d..%d] dBm,"
+ " C/I[curr %d, avg %d, thresh %d..%d] dB\n",
+ (new_dbm > current_dbm) ? "Raising" : "Lowering",
+ state->current, current_dbm, new_power_lvl, new_dbm, ms_power_lvl,
+ state->max, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
+ rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
+ ul_lqual_cb/10, ul_lqual_cb_avg/10, ci_meas->lower_thresh, ci_meas->upper_thresh);
+
+ /* store the resulting new MS power level in the lchan */
+ state->current = new_power_lvl;
+ bts_model_adjst_ms_pwr(lchan);
+
+ return 1;
+}
+
+/*! compute the new Downlink attenuation value for the given logical channel.
+ * \param lchan logical channel for which to compute (and in which to store) new power value.
+ * \param[in] mr pointer to a *valid* Measurement Report.
+ */
+int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
+ const struct gsm48_meas_res *mr)
+{
+ struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl;
+ const struct gsm_power_ctrl_params *params = state->dpc_params;
+ uint8_t rxqual, rxqual_avg, rxlev, rxlev_avg;
+ int new_att;
+
+ /* Check if dynamic BS Power Control is enabled */
+ if (params == NULL)
+ return 0;
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Rx DL Measurement Report: "
+ "RXLEV-FULL(%02u), RXQUAL-FULL(%u), "
+ "RXLEV-SUB(%02u), RXQUAL-SUB(%u), "
+ "DTx is %s => using %s\n",
+ mr->rxlev_full, mr->rxqual_full,
+ mr->rxlev_sub, mr->rxqual_sub,
+ lchan->tch.dtx.dl_active ? "enabled" : "disabled",
+ lchan->tch.dtx.dl_active ? "SUB" : "FULL");
+
+ /* Shall we skip current block based on configured interval? */
+ if (ctrl_interval_skip_block(params, state))
+ return 0;
+
+ /* If DTx is active on Downlink, use the '-SUB' */
+ if (lchan->tch.dtx.dl_active) {
+ rxqual = mr->rxqual_sub;
+ rxlev = mr->rxlev_sub;
+ } else { /* ... otherwise use the '-FULL' */
+ rxqual = mr->rxqual_full;
+ rxlev = mr->rxlev_full;
+ }
+
+ rxlev_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, rxlev);
+ rxqual_avg = do_avg_algo(&params->rxqual_meas, &state->rxqual_meas_proc, rxqual);
+ /* If RxQual > L_RXQUAL_XX_P, try to increase Tx power */
+ if (rxqual_avg > params->rxqual_meas.lower_thresh) {
+ /* Increase Tx power by reducing Tx attenuation */
+ new_att = state->current - params->inc_step_size_db;
+ } else if (rxqual_avg < params->rxqual_meas.upper_thresh) {
+ /* Increase Tx power by Increasing Tx attenuation */
+ new_att = state->current + params->red_step_size_db;
+ } else {
+ /* Basic signal transmission / reception formula:
+ *
+ * RxLev = TxPwr - (PathLoss + TxAtt)
+ *
+ * Here we want to change RxLev at the MS side, so:
+ *
+ * RxLev + Delta = TxPwr - (PathLoss + TxAtt) + Delta
+ *
+ * The only parameter we can change here is TxAtt, so:
+ *
+ * RxLev + Delta = TxPwr - PathLoss - TxAtt + Delta
+ * RxLev + Delta = TxPwr - PathLoss - (TxAtt - Delta)
+ */
+ new_att = state->current - calc_delta_rxlev(params, rxlev_avg);
+ }
+
+ /* Make sure new TxAtt is never negative: */
+ if (new_att < 0)
+ new_att = 0;
+
+ /* Don't ask for higher TxAtt than permitted: */
+ if (new_att > state->max)
+ new_att = state->max;
+
+ if (state->current == new_att) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping DL attenuation at %u dB: "
+ "max %u dB, RSSI[curr %d, avg %d, thresh %d..%d] dBm, "
+ "RxQual[curr %d, avg %d, thresh %d..%d]\n",
+ state->current, state->max, rxlev2dbm(rxlev), rxlev2dbm(rxlev_avg),
+ rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
+ rxqual, rxqual_avg, params->rxqual_meas.lower_thresh, params->rxqual_meas.upper_thresh);
+ return 0;
+ }
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "%s DL attenuation %u dB => %u dB:"
+ "max %u dB, RSSI[curr %d, avg %d, thresh %d..%d] dBm, "
+ "RxQual[curr %d, avg %d, thresh %d..%d]\n",
+ (new_att > state->current) ? "Raising" : "Lowering",
+ state->current, new_att, state->max, rxlev2dbm(rxlev), rxlev2dbm(rxlev_avg),
+ rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
+ rxqual, rxqual_avg, params->rxqual_meas.lower_thresh, params->rxqual_meas.upper_thresh);
+ state->current = new_att;
+ return 1;
+}
+
+/* Default MS/BS Power Control parameters (see 3GPP TS 45.008, table A.1) */
+const struct gsm_power_ctrl_params power_ctrl_params_def = {
+ /* Power increasing/reducing step size (optimal defaults) */
+ .inc_step_size_db = 4, /* quickly increase MS/BS power */
+ .red_step_size_db = 2, /* slowly decrease MS/BS power */
+
+ /* RxLev measurement parameters */
+ .rxlev_meas = {
+ /* Thresholds for RxLev (see 3GPP TS 45.008, A.3.2.1) */
+ .lower_thresh = 32, /* L_RXLEV_XX_P (-78 dBm) */
+ .upper_thresh = 38, /* U_RXLEV_XX_P (-72 dBm) */
+
+ /* NOTE: only Osmocom specific EWMA is supported */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,
+ .ewma.alpha = 50, /* Smoothing factor 50% */
+ },
+
+ /* RxQual measurement parameters */
+ .rxqual_meas = {
+ /* Thresholds for RxQual (see 3GPP TS 45.008, A.3.2.1) */
+ .lower_thresh = 3, /* L_RXQUAL_XX_P (0.8% <= BER < 1.6%) */
+ .upper_thresh = 0, /* U_RXQUAL_XX_P (BER < 0.2%) */
+
+ /* No averaging (filtering) by default.
+ * NOTE: only Osmocom specific EWMA is supported */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+ },
+
+ /* C/I measurement parameters.
+ * Target C/I retrieved from "GSM/EDGE: Evolution and Performance" Table 10.3.
+ * Set lower and upper so that (lower + upper) / 2 is equal or slightly
+ * above the target.
+ */
+ .ci_fr_meas = { /* FR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
+ .lower_thresh = 13,
+ .upper_thresh = 17,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_FR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_FR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_hr_meas = { /* HR: Target C/I = 18 dB, Soft blocking threshold = 13 dB */
+ .lower_thresh = 16,
+ .upper_thresh = 21,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_HR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_HR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_amr_fr_meas = { /* AMR-FR: Target C/I = 9 dB, Soft blocking threshold = 4 dB */
+ .lower_thresh = 7,
+ .upper_thresh = 11,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_AMR_FR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_AMR_FR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_amr_hr_meas = { /* AMR-HR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
+ .lower_thresh = 13,
+ .upper_thresh = 17,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_AMR_HR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_AMR_HR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_sdcch_meas = { /* SDCCH: Target C/I = 14 dB, Soft blocking threshold = 9 dB */
+ .lower_thresh = 12,
+ .upper_thresh = 16,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_SDCCH_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_SDCCH_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_gprs_meas = { /* GPRS: Target C/I = 20 dB, Soft blocking threshold = 15 dB */
+ .lower_thresh = 18,
+ .upper_thresh = 24,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_GPRS_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_GPRS_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+};
+
+void power_ctrl_params_def_reset(struct gsm_power_ctrl_params *params, bool is_bs_pwr)
+{
+ *params = power_ctrl_params_def;
+
+ /* Trigger loop every N-th SACCH block. See 3GPP TS 45.008 section 4.7.1. */
+ if (!is_bs_pwr)
+ params->ctrl_interval = 2; /* N=4 (1.92s) */
+ else
+ params->ctrl_interval = 1; /* N=2 (0.960) */
}
diff --git a/src/common/probes.d b/src/common/probes.d
new file mode 100644
index 00000000..aaf9030e
--- /dev/null
+++ b/src/common/probes.d
@@ -0,0 +1,2 @@
+provider osmo_bts {
+};
diff --git a/src/common/rsl.c b/src/common/rsl.c
index c0d43d0e..40690f05 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -2,6 +2,7 @@
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2011-2019 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -13,19 +14,18 @@
* 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.
+ * GNU Affero 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 "btsconfig.h" /* for PACKAGE_VERSION */
-
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <stdbool.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <arpa/inet.h>
@@ -56,9 +56,39 @@
#include <osmo-bts/l1sap.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/pcuif_proto.h>
+#include <osmo-bts/notification.h>
+#include <osmo-bts/asci.h>
//#define FAKE_CIPH_MODE_COMPL
+/* Parse power attenuation (in dB) from BS Power IE (see 9.3.4) */
+#define BS_POWER2DB(bs_power) \
+ ((bs_power & 0x0f) * 2)
+
+bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt)
+{
+ switch (chan_rt) {
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ case RSL_CMOD_CRT_TCH_BCAST_Bm:
+ case RSL_CMOD_CRT_TCH_BCAST_Lm:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt)
+{
+ switch (chan_rt) {
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause, const uint8_t *chan_nr,
const uint8_t *link_id, const struct msgb *orig_msg);
@@ -69,6 +99,7 @@ static const unsigned int rsl_sacch_sitypes[] = {
RSL_SYSTEM_INFO_6,
RSL_SYSTEM_INFO_5bis,
RSL_SYSTEM_INFO_5ter,
+ RSL_SYSTEM_INFO_10,
RSL_EXT_MEAS_ORDER,
RSL_MEAS_INFO,
};
@@ -85,19 +116,6 @@ int osmo_in_array(unsigned int search, const unsigned int *arr, unsigned int siz
}
#define OSMO_IN_ARRAY(search, arr) osmo_in_array(search, arr, ARRAY_SIZE(arr))
-int msgb_queue_flush(struct llist_head *list)
-{
- struct msgb *msg, *msg2;
- int count = 0;
-
- llist_for_each_entry_safe(msg, msg2, list, list) {
- msgb_free(msg);
- count++;
- }
-
- return count;
-}
-
/* FIXME: move this to libosmocore */
void gsm48_gen_starting_time(uint8_t *out, struct gsm_time *gtime)
{
@@ -106,33 +124,236 @@ void gsm48_gen_starting_time(uint8_t *out, struct gsm_time *gtime)
out[1] = (gtime->t3 << 5) | gtime->t2;
}
-/* compute lchan->rsl_cmode and lchan->tch_mode from RSL CHAN MODE IE */
-static void lchan_tchmode_from_cmode(struct gsm_lchan *lchan,
- struct rsl_ie_chan_mode *cm)
+/* Handle RSL Channel Mode IE (see section 9.3.6) */
+static int rsl_handle_chan_mod_ie(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp,
+ uint8_t *cause)
{
+ const struct rsl_ie_chan_mode *cm;
+
+ if (!TLVP_PRES_LEN(tp, RSL_IE_CHAN_MODE, sizeof(*cm))) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Channel Mode IE is not present\n");
+ *cause = RSL_ERR_MAND_IE_ERROR;
+ return -ENODEV;
+ }
+
+ cm = (const struct rsl_ie_chan_mode *) TLVP_VAL(tp, RSL_IE_CHAN_MODE);
lchan->rsl_cmode = cm->spd_ind;
+ lchan->rsl_chan_rt = cm->chan_rt;
lchan->ts->trx->bts->dtxd = (cm->dtx_dtu & RSL_CMOD_DTXd) ? true : false;
- switch (cm->chan_rate) {
- case RSL_CMOD_SP_GSM1:
+ /* Octet 5: Channel rate and type */
+ switch (cm->chan_rt) {
+ case RSL_CMOD_CRT_SDCCH:
+ case RSL_CMOD_CRT_TCH_Bm:
+ case RSL_CMOD_CRT_TCH_Lm:
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ case RSL_CMOD_CRT_TCH_BCAST_Bm:
+ case RSL_CMOD_CRT_TCH_BCAST_Lm:
+ break;
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
+ case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
+ /* Make sure that Osmocom specific TSC IE is present */
+ if (!TLVP_PRES_LEN(tp, RSL_IE_OSMO_TRAINING_SEQUENCE, 2)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR,
+ "Training Sequence IE is not present\n");
+ *cause = RSL_ERR_MAND_IE_ERROR;
+ return -ENODEV;
+ }
+ break;
+ default:
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Channel Mode IE contains "
+ "unknown 'Channel rate and type' value 0x%02x\n",
+ cm->chan_rt);
+ *cause = RSL_ERR_IE_CONTENT;
+ return -ENOTSUP;
+ }
+
+#define RSL_CMODE(spd_ind, chan_rate) \
+ ((spd_ind << 8) | chan_rate)
+
+ /* Octet 6: Speech coding algorithm/data rate + transparency indicator.
+ * NOTE: coding of this octet depends on 'Speech or data indicator' */
+ switch (RSL_CMODE(cm->spd_ind, cm->chan_rate)) {
+ /* If octet 4 indicates signalling */
+ case RSL_CMODE(RSL_CMOD_SPD_SIGN, 0x00):
+ /* No resources required, all other values are reserved */
+ lchan->tch_mode = GSM48_CMODE_SIGN;
+ break;
+
+ /* If octet 4 indicates speech */
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM1):
lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
break;
- case RSL_CMOD_SP_GSM2:
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM2):
lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
break;
- case RSL_CMOD_SP_GSM3:
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM3):
lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
break;
- case RSL_CMOD_SP_NT_14k5:
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM4):
+ lchan->tch_mode = GSM48_CMODE_SPEECH_V4;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM5):
+ lchan->tch_mode = GSM48_CMODE_SPEECH_V5;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_SPEECH, RSL_CMOD_SP_GSM6):
+ lchan->tch_mode = GSM48_CMODE_SPEECH_V6;
+ break;
+
+ /* If octet 4 indicates non-transparent data */
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NT_14k5):
lchan->tch_mode = GSM48_CMODE_DATA_14k5;
break;
- case RSL_CMOD_SP_NT_12k0:
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NT_12k0):
lchan->tch_mode = GSM48_CMODE_DATA_12k0;
break;
- case RSL_CMOD_SP_NT_6k0:
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NT_6k0):
lchan->tch_mode = GSM48_CMODE_DATA_6k0;
break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NT_43k5):
+ lchan->tch_mode = GSM48_CMODE_DATA_43k5;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NT_28k8):
+ /* 28.8 kbit/s services, 29.0 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_29k0;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_43k5_14k5):
+ lchan->tch_mode = GSM48_CMODE_DATA_43k5_14k5;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_29k0_14k5):
+ lchan->tch_mode = GSM48_CMODE_DATA_29k0_14k5;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_43k5_29k0):
+ lchan->tch_mode = GSM48_CMODE_DATA_43k5_29k0;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_14k5_43k5):
+ lchan->tch_mode = GSM48_CMODE_DATA_14k5_43k5;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_14k5_29k0):
+ lchan->tch_mode = GSM48_CMODE_DATA_14k5_29k0;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_NTA_29k0_43k5):
+ lchan->tch_mode = GSM48_CMODE_DATA_29k0_43k5;
+ break;
+
+ /* If octet 4 indicates transparent data */
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_32k0):
+ /* 32.0 kbit/s services, 32.0 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_32k0;
+ lchan->csd_mode = LCHAN_CSD_M_T_32000;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_29k0):
+ /* 29.0 kbit/s services, 29.0 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_29k0;
+ lchan->csd_mode = LCHAN_CSD_M_T_29000;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_14k4):
+ /* 14.4 kbit/s services, 14.5 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_14k5;
+ lchan->csd_mode = LCHAN_CSD_M_T_14400;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_9k6):
+ /* 9.6 kbit/s services, 12.0 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_12k0;
+ lchan->csd_mode = LCHAN_CSD_M_T_9600;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_4k8):
+ /* 4.8 kbit/s services, 6.0 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_6k0;
+ lchan->csd_mode = LCHAN_CSD_M_T_4800;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_2k4):
+ /* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_3k6;
+ lchan->csd_mode = LCHAN_CSD_M_T_2400;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_1k2):
+ /* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_3k6;
+ lchan->csd_mode = LCHAN_CSD_M_T_1200;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_600):
+ /* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_3k6;
+ lchan->csd_mode = LCHAN_CSD_M_T_600;
+ break;
+ case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_1200_75):
+ /* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
+ lchan->tch_mode = GSM48_CMODE_DATA_3k6;
+ lchan->csd_mode = LCHAN_CSD_M_T_1200_75;
+ break;
+
+ default:
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Channel Mode IE contains "
+ "an unknown/unhandled combination of "
+ "'Speech or data indicator' 0x%02x and "
+ "'Speech coding algorithm/data rate' 0x%02x\n",
+ cm->spd_ind, cm->chan_rate);
+ *cause = RSL_ERR_IE_CONTENT;
+ return -ENOPROTOOPT;
+ }
+
+#undef RSL_CMODE
+
+ if (!bts_supports_cm(lchan->ts->trx->bts, cm)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Channel type=0x%02x/mode=%s "
+ "is not supported by the PHY\n", cm->chan_rt,
+ gsm48_chan_mode_name(lchan->tch_mode));
+ *cause = RSL_ERR_SERV_OPT_UNAVAIL;
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/* Handle RSL Channel Identification IE (see section 9.3.5) */
+static int rsl_handle_chan_ident_ie(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp,
+ uint8_t *cause)
+{
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+ const struct gsm_bts *bts = ts->trx->bts;
+ const struct gsm48_chan_desc *cd;
+
+ if (TLVP_PRES_LEN(tp, RSL_IE_CHAN_IDENT, sizeof(*cd) + 1)) {
+ /* Channel Description IE comes together with its IEI (see 9.3.5) */
+ cd = (const struct gsm48_chan_desc *) (TLVP_VAL(tp, RSL_IE_CHAN_IDENT) + 1);
+
+ /* The PHY may not support using different TSCs */
+ if (!osmo_bts_has_feature(bts->features, BTS_FEAT_MULTI_TSC)
+ && cd->h0.tsc != BTS_TSC(bts)) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "This PHY does not support "
+ "lchan TSC %u != BSIC-TSC %u, sending NACK\n",
+ cd->h0.tsc, BTS_TSC(bts));
+ *cause = RSL_ERR_SERV_OPT_UNIMPL;
+ return -ENOTSUP;
+ }
+ }
+
+ return 0;
+}
+
+/* Handle Osmocom specific TSC IE */
+static int rsl_handle_osmo_tsc_ie(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp,
+ uint8_t *cause)
+{
+ /* Osmocom specific IE indicating Training Sequence Code and Set */
+ if (TLVP_PRES_LEN(tp, RSL_IE_OSMO_TRAINING_SEQUENCE, 2)) {
+ const uint8_t *ie = TLVP_VAL(tp, RSL_IE_OSMO_TRAINING_SEQUENCE);
+ lchan->ts->tsc_set = ie[0] & 0x03; /* Range: 0..3 */
+ lchan->ts->tsc_rsl = ie[1] & 0x07; /* Range: 0..7 */
+ lchan->ts->tsc_rsl_configured = true;
+ } else {
+ lchan->ts->tsc_rsl_configured = false;
+ lchan->ts->tsc_rsl = 0xff;
+ lchan->ts->tsc_set = 0;
}
+ gsm_ts_apply_configured_tsc(lchan->ts);
+
+ return 0;
}
@@ -150,6 +371,16 @@ static bool chan_nr_is_dchan(uint8_t chan_nr)
return true;
}
+static struct gsm_bts_trx *trx_lookup_by_arfcn(struct llist_head *trx_list, uint16_t arfcn)
+{
+ struct gsm_bts_trx *trx;
+ llist_for_each_entry(trx, trx_list, list) {
+ if (trx->arfcn == arfcn)
+ return trx;
+ }
+ return NULL;
+}
+
static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
const char *log_name)
{
@@ -269,6 +500,7 @@ static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause, const uin
/* 8.6.1 sending RF RESOURCE INDICATION */
int rsl_tx_rf_res(struct gsm_bts_trx *trx)
{
+ unsigned int tn, ln;
struct msgb *nmsg;
LOGP(DRSL, LOGL_INFO, "Tx RSL RF RESource INDication\n");
@@ -276,8 +508,48 @@ int rsl_tx_rf_res(struct gsm_bts_trx *trx)
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
- // FIXME: add interference levels of TRX
- msgb_tlv_put(nmsg, RSL_IE_RESOURCE_INFO, 0, NULL);
+
+ /* Add interference levels for each logical channel */
+ uint8_t *len = msgb_tl_put(nmsg, RSL_IE_RESOURCE_INFO);
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
+ if (ts->mo.nm_state.availability != NM_AVSTATE_OK)
+ continue;
+
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ const struct gsm_lchan *lchan = &ts->lchan[ln];
+
+ /* No average interference value => no band */
+ if (lchan->meas.interf_meas_avg_dbm == 0)
+ continue;
+
+ /* Only for GSM_LCHAN_{SDCCH,TCH_F,TCH_H,PDTCH} */
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ case GSM_LCHAN_TCH_F:
+ case GSM_LCHAN_TCH_H:
+ /* We're not interested in active CS lchans */
+ if (lchan->state == LCHAN_S_ACTIVE)
+ continue;
+ break;
+ case GSM_LCHAN_PDTCH:
+ break;
+ default:
+ continue;
+ }
+
+ msgb_v_put(nmsg, gsm_lchan2chan_nr_rsl(lchan));
+ msgb_v_put(nmsg, (lchan->meas.interf_band & 0x07) << 5);
+ }
+ }
+
+ /* Calculate length of the V part */
+ *len = msgb_l3len(nmsg) - 2;
+
rsl_trx_push_hdr(nmsg, RSL_MT_RF_RES_IND);
nmsg->trx = trx;
@@ -285,7 +557,7 @@ int rsl_tx_rf_res(struct gsm_bts_trx *trx)
}
/*
- * common channel releated messages
+ * common channel related messages
*/
/* 8.5.1 BCCH INFOrmation is received */
@@ -298,7 +570,13 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
enum osmo_sysinfo_type osmo_si;
struct gsm48_system_information_type_2quater *si2q;
struct bitvec bv;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ const uint8_t *si_buf;
+ uint8_t prev_bs_ag_blks_res = 0xff; /* 0xff = unknown */
+
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
/* 9.3.30 System Info Type */
if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE))
@@ -325,7 +603,8 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s, %u bytes)\n",
get_value_string(osmo_sitype_strs, osmo_si), len);
- if (SYSINFO_TYPE_2quater == osmo_si) {
+ switch (osmo_si) {
+ case SYSINFO_TYPE_2quater:
si2q = (struct gsm48_system_information_type_2quater *) TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO);
bv.data = si2q->rest_octets;
bv.data_len = GSM_MACBLOCK_LEN;
@@ -353,32 +632,68 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
memset(GSM_BTS_SI2Q(bts, bts->si2q_index), GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
memcpy(GSM_BTS_SI2Q(bts, bts->si2q_index), TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len);
- } else {
+ break;
+ case SYSINFO_TYPE_3:
+ /* Keep previous BS_AG_BLKS_RES, used below */
+ if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_3)) {
+ const struct gsm48_system_information_type_3 *si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+ prev_bs_ag_blks_res = si3->control_channel_desc.bs_ag_blks_res;
+ }
+ /* fall-through */
+ default:
memset(bts->si_buf[osmo_si], GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
memcpy(bts->si_buf[osmo_si], TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len);
}
bts->si_valid |= (1 << osmo_si);
- if (SYSINFO_TYPE_3 == osmo_si) {
- if (trx->nr == 0 && num_agch(trx, "RSL") != 1) {
- lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]);
- /* will be reactivated by sapi_deactivate_cb() */
+ switch (osmo_si) {
+ case SYSINFO_TYPE_3:
+ /* If CCCH config on TS0 changed, reactivate the chan with the new config: */
+ if (trx->nr == 0 && trx->bts->c0->ts[0].lchan[CCCH_LCHAN].state != LCHAN_S_NONE &&
+ num_agch(trx, "RSL") != prev_bs_ag_blks_res) {
trx->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
LCHAN_REL_ACT_REACT;
+ lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]);
+ /* will be reactivated by (see OS#1575):
+ * - bts-trx: lchan_deactivate()
+ * - sysmo,lc15,oc2g: lchan_deactivate()....[async]...sapi_deactivate_cb() */
}
/* decode original SI3 Rest Octets as sent by BSC */
- const uint8_t *si3_ro_buf = (uint8_t *) GSM_BTS_SI(bts, osmo_si);
- si3_ro_buf += offsetof(struct gsm48_system_information_type_3, rest_octets);
- osmo_gsm48_rest_octets_si3_decode(&bts->si3_ro_decoded, si3_ro_buf);
+ si_buf = (const uint8_t *) GSM_BTS_SI(bts, osmo_si);
+ si_buf += offsetof(struct gsm48_system_information_type_3, rest_octets);
+ osmo_gsm48_rest_octets_si3_decode(&bts->si3_ro_decoded, si_buf);
/* patch out GPRS indicator from binary if PCU is not connected; will be enabled
* after PCU connects */
regenerate_si3_restoctets(bts);
+ pcu_tx_si(trx->bts, SYSINFO_TYPE_3, true);
+ break;
+ case SYSINFO_TYPE_4:
+ /* decode original SI4 Rest Octets as sent by BSC */
+ si_buf = (const uint8_t *) GSM_BTS_SI(bts, osmo_si);
+ int si4_ro_offset = get_si4_ro_offset(si_buf);
+ if (si4_ro_offset > 0) {
+ osmo_gsm48_rest_octets_si4_decode(&bts->si4_ro_decoded,
+ si_buf + si4_ro_offset,
+ GSM_MACBLOCK_LEN - si4_ro_offset);
+ /* patch out GPRS indicator from binary if PCU is not connected; will be
+ * enabled after PCU connects */
+ regenerate_si4_restoctets(bts);
+ }
+ break;
+ case SYSINFO_TYPE_1:
+ /* Get the position of the NCH, if enabled. */
+ trx->bts->asci.pos_nch = pos_nch(trx, "BCCH INFO");
+ pcu_tx_si(trx->bts, SYSINFO_TYPE_1, true);
+ break;
+ case SYSINFO_TYPE_2:
+ case SYSINFO_TYPE_13:
+ pcu_tx_si(trx->bts, osmo_si, true);
+ break;
+ default:
+ break;
}
- if (SYSINFO_TYPE_13 == osmo_si)
- pcu_tx_si13(trx->bts, true);
-
} else if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
uint16_t len = TLVP_LEN(&tp, RSL_IE_L3_INFO);
if (len > sizeof(sysinfo_buf_t))
@@ -393,10 +708,20 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
bts->si_valid &= ~(1 << osmo_si);
LOGP(DRSL, LOGL_INFO, " RX RSL Disabling BCCH INFO (SI%s)\n",
get_value_string(osmo_sitype_strs, osmo_si));
- if (SYSINFO_TYPE_13 == osmo_si)
- pcu_tx_si13(trx->bts, false);
- if (SYSINFO_TYPE_3 == osmo_si)
+ switch (osmo_si) {
+ case SYSINFO_TYPE_13:
+ pcu_tx_si(trx->bts, SYSINFO_TYPE_13, false);
+ break;
+ case SYSINFO_TYPE_3:
memset(&bts->si3_ro_decoded, 0, sizeof(bts->si3_ro_decoded));
+ pcu_tx_si(trx->bts, SYSINFO_TYPE_3, false);
+ break;
+ case SYSINFO_TYPE_1:
+ pcu_tx_si(trx->bts, SYSINFO_TYPE_1, false);
+ break;
+ default:
+ break;
+ }
}
osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts);
@@ -465,7 +790,10 @@ static int rsl_rx_paging_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
const uint8_t *identity_lv;
int rc;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
if (!TLVP_PRESENT(&tp, RSL_IE_PAGING_GROUP) ||
!TLVP_PRESENT(&tp, RSL_IE_MS_IDENTITY))
@@ -500,7 +828,10 @@ static int rsl_rx_sms_bcast_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
bool extended_cbch = false;
int rc;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
if (!TLVP_PRESENT(&tp, RSL_IE_CB_CMD_TYPE) ||
!TLVP_PRESENT(&tp, RSL_IE_SMSCB_MSG))
@@ -522,6 +853,100 @@ static int rsl_rx_sms_bcast_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
return 0;
}
+/* Broadcast notification about new VGCS/VBS call on every dedicated channel.
+ * This is required for MSs that are currently in dedicated mode that there is an ongoing call and on which channel
+ * the call is active. Most MSs in dedicated mode may not be able to receive the NCH otherwise.
+ * MSs that do not support ASCI will ignore it, as it is an unsupported message for them.
+ */
+static int asci_broadcast_facch(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
+ uint8_t chan_desc_len, unsigned int count)
+{
+ uint8_t notif[23];
+ struct msgb *msg, *cmsg;
+ struct gsm_bts_trx *trx;
+ struct gsm_lchan *lchan;
+ unsigned int tn, ln, n;
+ int rc;
+
+ rc = bts_asci_notify_facch_gen_msg(bts, notif, group_call_ref, chan_desc, chan_desc_len);
+ if (rc < 0)
+ return rc;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ for (ln = 0; ln < ARRAY_SIZE(trx->ts[tn].lchan); ln++) {
+ lchan = &trx->ts[tn].lchan[ln];
+ if (!lchan_is_dcch(lchan))
+ continue;
+ if (lchan->state != LCHAN_S_ACTIVE)
+ continue;
+ msg = rsl_rll_simple(RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), 0x00, 0);
+ msg->l3h = msg->tail; /* emulate rsl_rx_rll() behaviour */
+ msgb_tl16v_put(msg, RSL_IE_L3_INFO, sizeof(notif), (uint8_t *) &notif);
+ for (n = 1; n < count; n++) {
+ cmsg = msgb_copy(msg, "FACCH copy");
+ lapdm_rslms_recvmsg(cmsg, &lchan->lapdm_ch);
+ }
+ lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Number of times to broadcast ASCI call on every dedicated channel. */
+#define ASCI_BROADCAST_NUM 3
+
+/* 8.5.10 NOTIFICATION COMMAND */
+static int rsl_rx_notification_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
+{
+ struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
+ struct tlv_parsed tp;
+ uint8_t command_indicator;
+ int rc;
+
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
+
+ if (cch->chan_nr != RSL_CHAN_PCH_AGCH) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): chan nr is not Downlink CCCH\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, &cch->chan_nr, NULL, msg);
+ }
+
+ if (!TLVP_PRES_LEN(&tp, RSL_IE_CMD_INDICATOR, 1))
+ return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &cch->chan_nr, NULL, msg);
+ command_indicator = *TLVP_VAL(&tp, RSL_IE_CMD_INDICATOR);
+
+ switch (command_indicator) {
+ case RSL_CMD_INDICATOR_START:
+ /* we need at least a Group Call Reference to start notification */
+ if (!TLVP_PRES_LEN(&tp, RSL_IE_GROUP_CALL_REF, 5))
+ return rsl_tx_error_report(trx, RSL_ERR_OPT_IE_ERROR, &cch->chan_nr, NULL, msg);
+ rc = bts_asci_notification_add(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF),
+ TLVP_VAL(&tp, RSL_IE_CHAN_DESC), TLVP_LEN(&tp, RSL_IE_CHAN_DESC),
+ (struct rsl_ie_nch_drx_info *) TLVP_VAL(&tp, RSL_IE_NCH_DRX_INFO));
+ /* Broadcast to FACCH */
+ asci_broadcast_facch(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF), TLVP_VAL(&tp, RSL_IE_CHAN_DESC),
+ TLVP_LEN(&tp, RSL_IE_CHAN_DESC), ASCI_BROADCAST_NUM);
+ break;
+ case RSL_CMD_INDICATOR_STOP:
+ if (!TLVP_PRES_LEN(&tp, RSL_IE_GROUP_CALL_REF, 5)) {
+ /* interpret this as stopping of all notification */
+ rc = bts_asci_notification_reset(trx->bts);
+ } else {
+ rc = bts_asci_notification_del(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF));
+ }
+ break;
+ default:
+ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, &cch->chan_nr, NULL, msg);
+ }
+
+ return rc;
+}
+
/* OSMO_ETWS_CMD - proprietary extension as TS 48.058 has no standardized way to do this :( */
static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
{
@@ -529,7 +954,10 @@ static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
struct gsm_bts *bts = trx->bts;
struct tlv_parsed tp;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
if (!TLVP_PRESENT(&tp, RSL_IE_SMSCB_MSG))
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &cch->chan_nr, NULL, msg);
@@ -571,10 +999,19 @@ static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
* \param[out] buf Output buffer, must be caller-allocated and hold at least len + 2 or sizeof(sysinfo_buf_t) bytes
* \param[out] valid pointer to bit-mask of 'valid' System information types
* \param[in] current input data (L3 without L2/L1 header)
- * \param[in] osmo_si Sytstem Infrormation Type (SYSINFO_TYPE_*)
+ * \param[in] osmo_si Sytstem Information Type (SYSINFO_TYPE_*)
* \param[in] len length of \a current in octets */
static inline void lapdm_ui_prefix(uint8_t *buf, uint32_t *valid, const uint8_t *current, uint8_t osmo_si, uint16_t len)
{
+ /* Special case for short header SI. Do not pre-fix the two-byte UI header. */
+ switch (osmo_si) {
+ case SYSINFO_TYPE_10:
+ (*valid) |= (1 << osmo_si);
+ memset(buf, GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
+ memcpy(buf, current, len);
+ return;
+ }
+
/* We have to pre-fix with the two-byte LAPDM UI header */
if (len > sizeof(sysinfo_buf_t) - 2) {
LOGP(DRSL, LOGL_ERROR, "Truncating received SI%s (%u -> %zu) to prepend LAPDM UI header (2 bytes)\n",
@@ -593,7 +1030,7 @@ static inline void lapdm_ui_prefix(uint8_t *buf, uint32_t *valid, const uint8_t
/*! Prefix a given SACCH frame with a L2/LAPDm UI header and store it in given BTS SACCH buffer
* \param[out] bts BTS in whose System Information State we shall store
* \param[in] current input data (L3 without L2/L1 header)
- * \param[in] osmo_si Sytstem Infrormation Type (SYSINFO_TYPE_*)
+ * \param[in] osmo_si Sytstem Information Type (SYSINFO_TYPE_*)
* \param[in] len length of \a current in octets */
static inline void lapdm_ui_prefix_bts(struct gsm_bts *bts, const uint8_t *current, uint8_t osmo_si, uint16_t len)
{
@@ -603,7 +1040,7 @@ static inline void lapdm_ui_prefix_bts(struct gsm_bts *bts, const uint8_t *curre
/*! Prefix a given SACCH frame with a L2/LAPDm UI header and store it in given lchan SACCH buffer
* \param[out] lchan Logical Channel in whose System Information State we shall store
* \param[in] current input data (L3 without L2/L1 header)
- * \param[in] osmo_si Sytstem Infrormation Type (SYSINFO_TYPE_*)
+ * \param[in] osmo_si Sytstem Information Type (SYSINFO_TYPE_*)
* \param[in] len length of \a current in octets */
static inline void lapdm_ui_prefix_lchan(struct gsm_lchan *lchan, const uint8_t *current, uint8_t osmo_si, uint16_t len)
{
@@ -618,7 +1055,10 @@ static int rsl_rx_sacch_fill(struct gsm_bts_trx *trx, struct msgb *msg)
uint8_t rsl_si;
enum osmo_sysinfo_type osmo_si;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, NULL, NULL, msg);
+ }
/* 9.3.30 System Info Type */
if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE))
@@ -682,13 +1122,256 @@ static int rsl_rx_sacch_fill(struct gsm_bts_trx *trx, struct msgb *msg)
}
+/* Parser for ip.access specific MS/BS Power parameters */
+static int parse_power_ctrl_params(struct gsm_power_ctrl_params *params,
+ const uint8_t *data, size_t data_len)
+{
+ const struct tlv_p_entry *ie;
+ struct tlv_parsed tp[3];
+ unsigned int i;
+ int rc;
+
+ /* There can be multiple RSL_IPAC_EIE_MEAS_AVG_CFG, so we use tlv_parse2() */
+ rc = tlv_parse2(&tp[0], ARRAY_SIZE(tp), &rsl_ipac_eie_tlvdef,
+ data, data_len, 0, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Either of RSL_IPAC_EIE_{BS,MS}_PWR_CTL must be present */
+ if (TLVP_PRESENT(&tp[0], RSL_IPAC_EIE_BS_PWR_CTL) &&
+ TLVP_PRESENT(&tp[0], RSL_IPAC_EIE_MS_PWR_CTL))
+ return -EINVAL;
+
+ /* (TV) Thresholds: {L,U}_RXLEV_XX_P and {L,U}_RXQUAL_XX_P */
+ if ((ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_BS_PWR_CTL)) != NULL ||
+ (ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_MS_PWR_CTL)) != NULL) {
+ const struct ipac_preproc_pc_thresh *thresh;
+
+ thresh = (const struct ipac_preproc_pc_thresh *) ie->val;
+
+ params->rxlev_meas.lower_thresh = thresh->l_rxlev;
+ params->rxlev_meas.upper_thresh = thresh->u_rxlev;
+
+ params->rxqual_meas.lower_thresh = thresh->l_rxqual;
+ params->rxqual_meas.upper_thresh = thresh->u_rxqual;
+ }
+
+ /* Osmocom extension, C/I related thresholds: */
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_MS_PWR_CTL, sizeof(struct osmo_preproc_pc_thresh))) {
+ const struct osmo_preproc_pc_thresh *osmo_thresh;
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_MS_PWR_CTL);
+ osmo_thresh = (const struct osmo_preproc_pc_thresh *) ie->val;
+ params->ci_fr_meas.lower_thresh = osmo_thresh->l_ci_fr;
+ params->ci_fr_meas.upper_thresh = osmo_thresh->u_ci_fr;
+
+ params->ci_hr_meas.lower_thresh = osmo_thresh->l_ci_hr;
+ params->ci_hr_meas.upper_thresh = osmo_thresh->u_ci_hr;
+
+ params->ci_amr_fr_meas.lower_thresh = osmo_thresh->l_ci_amr_fr;
+ params->ci_amr_fr_meas.upper_thresh = osmo_thresh->u_ci_amr_fr;
+
+ params->ci_amr_hr_meas.lower_thresh = osmo_thresh->l_ci_amr_hr;
+ params->ci_amr_hr_meas.upper_thresh = osmo_thresh->u_ci_amr_hr;
+
+ params->ci_sdcch_meas.lower_thresh = osmo_thresh->l_ci_sdcch;
+ params->ci_sdcch_meas.upper_thresh = osmo_thresh->u_ci_sdcch;
+
+ params->ci_gprs_meas.lower_thresh = osmo_thresh->l_ci_gprs;
+ params->ci_gprs_meas.upper_thresh = osmo_thresh->u_ci_gprs;
+ }
+
+ /* (TV) PC Threshold Comparators */
+ if ((ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_PC_THRESH_COMP)) != NULL) {
+ const struct ipac_preproc_pc_comp *thresh_comp;
+
+ thresh_comp = (const struct ipac_preproc_pc_comp *) ie->val;
+
+ /* RxLev: P1, N1, P2, N2 (see 3GPP TS 45.008, A.3.2.1, a & b) */
+ params->rxlev_meas.lower_cmp_p = thresh_comp->p1;
+ params->rxlev_meas.lower_cmp_n = thresh_comp->n1;
+ params->rxlev_meas.upper_cmp_p = thresh_comp->p2;
+ params->rxlev_meas.upper_cmp_n = thresh_comp->n2;
+
+ /* RxQual: P3, N3, P4, N4 (see 3GPP TS 45.008, A.3.2.1, c & d) */
+ params->rxqual_meas.lower_cmp_p = thresh_comp->p3;
+ params->rxqual_meas.lower_cmp_n = thresh_comp->n3;
+ params->rxqual_meas.upper_cmp_p = thresh_comp->p4;
+ params->rxqual_meas.upper_cmp_n = thresh_comp->n4;
+
+ /* Minimum interval between power level changes (P_Con_INTERVAL) */
+ params->ctrl_interval = thresh_comp->pc_interval;
+
+ /* Power increase / reduce step size: POWER_{INC,RED}_STEP_SIZE */
+ params->inc_step_size_db = thresh_comp->inc_step_size;
+ params->red_step_size_db = thresh_comp->red_step_size;
+ }
+
+ /* Osmocom extension, C/I related thresholds: */
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_PC_THRESH_COMP, sizeof(struct osmo_preproc_pc_thresh))) {
+ const struct osmo_preproc_pc_comp *osmo_thresh_comp;
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_PC_THRESH_COMP);
+ osmo_thresh_comp = (const struct osmo_preproc_pc_comp *) ie->val;
+ #define SET_PREPROC_PC(PARAMS, FROM, TYPE) \
+ (PARAMS)->TYPE##_meas.lower_cmp_p = (FROM)->TYPE.lower_p; \
+ (PARAMS)->TYPE##_meas.lower_cmp_n = (FROM)->TYPE.lower_n; \
+ (PARAMS)->TYPE##_meas.upper_cmp_p = (FROM)->TYPE.upper_p; \
+ (PARAMS)->TYPE##_meas.upper_cmp_n = (FROM)->TYPE.upper_n
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_fr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_hr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_amr_fr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_amr_hr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_sdcch);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_gprs);
+ #undef SET_PREPROC_PC
+ }
+
+ /* (TLV) Measurement Averaging parameters for RxLev/RxQual */
+ for (i = 0; i < ARRAY_SIZE(tp); i++) {
+ const struct ipac_preproc_ave_cfg *ave_cfg;
+ struct gsm_power_ctrl_meas_params *mp;
+
+ ie = TLVP_GET(&tp[i], RSL_IPAC_EIE_MEAS_AVG_CFG);
+ if (ie == NULL)
+ break;
+
+ if (ie->len < sizeof(*ave_cfg))
+ return -EINVAL;
+
+ ave_cfg = (const struct ipac_preproc_ave_cfg *) ie->val;
+
+ switch (ave_cfg->param_id) {
+ case IPAC_RXQUAL_AVE:
+ mp = &params->rxqual_meas;
+ break;
+ case IPAC_RXLEV_AVE:
+ mp = &params->rxlev_meas;
+ break;
+ default:
+ /* Skip unknown parameters */
+ continue;
+ }
+
+ mp->h_reqave = ave_cfg->h_reqave;
+ mp->h_reqt = ave_cfg->h_reqt;
+
+ mp->algo = ave_cfg->ave_method + 1;
+ switch (ave_cfg->ave_method) {
+ case IPAC_OSMO_EWMA_AVE:
+ if (ie->len > sizeof(*ave_cfg))
+ mp->ewma.alpha = ave_cfg->params[0];
+ break;
+
+ /* FIXME: not implemented */
+ case IPAC_UNWEIGHTED_AVE:
+ case IPAC_WEIGHTED_AVE:
+ case IPAC_MEDIAN_AVE:
+ break;
+ }
+ }
+
+ /* (TLV) Measurement Averaging parameters for C/I (Osmocom extension)*/
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG, sizeof(struct osmo_preproc_ave_cfg))) {
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG);
+ const struct osmo_preproc_ave_cfg *cfg = (const struct osmo_preproc_ave_cfg *) ie->val;
+ unsigned params_offset = 0;
+ #define SET_AVE_CFG(PARAMS, FROM, TYPE, PARAM_OFFSET) do {\
+ if ((FROM)->TYPE.ave_enabled) { \
+ (PARAMS)->TYPE##_meas.h_reqave = (FROM)->TYPE.h_reqave; \
+ (PARAMS)->TYPE##_meas.h_reqt = (FROM)->TYPE.h_reqt; \
+ (PARAMS)->TYPE##_meas.algo = (FROM)->TYPE.ave_method + 1; \
+ switch ((FROM)->TYPE.ave_method) { \
+ case IPAC_OSMO_EWMA_AVE: \
+ if (ie->len > sizeof(*cfg) + (PARAM_OFFSET)) { \
+ (PARAMS)->TYPE##_meas.ewma.alpha = (FROM)->params[PARAM_OFFSET]; \
+ (PARAM_OFFSET)++; \
+ } \
+ break; \
+ /* FIXME: not implemented */ \
+ case IPAC_UNWEIGHTED_AVE: \
+ case IPAC_WEIGHTED_AVE: \
+ case IPAC_MEDIAN_AVE: \
+ break; \
+ } \
+ } else { \
+ (PARAMS)->TYPE##_meas.algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE; \
+ } \
+ } while(0)
+ SET_AVE_CFG(params, cfg, ci_fr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_hr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_amr_fr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_amr_hr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_sdcch, params_offset);
+ SET_AVE_CFG(params, cfg, ci_gprs, params_offset);
+ #undef SET_AVE_CFG
+ }
+
+ return 0;
+}
+
+/* ip.access specific Measurement Pre-processing Defaults for MS/BS Power control */
+static int rsl_rx_meas_preproc_dft(struct gsm_bts_trx *trx, struct msgb *msg)
+{
+ const struct gsm_bts *bts = trx->bts;
+ struct gsm_power_ctrl_params *params;
+ const struct tlv_p_entry *ie;
+ struct tlv_parsed tp;
+
+ LOGPTRX(trx, DRSL, LOGL_INFO, "Rx Measurement Pre-processing Defaults\n");
+
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, NULL, NULL, msg);
+ }
+
+ /* TLV (O) BS Power Parameters IE */
+ if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) {
+ /* Allocate a new chunk and initialize with default values */
+ params = talloc(trx, struct gsm_power_ctrl_params);
+ power_ctrl_params_def_reset(params, true);
+
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) == 0) {
+ /* Initially it points to the global defaults */
+ if (trx->bs_dpc_params != &bts->bs_dpc_params)
+ talloc_free(trx->bs_dpc_params);
+ trx->bs_dpc_params = params;
+ } else {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "Failed to parse BS Power Parameters IE\n");
+ rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, NULL, NULL, msg);
+ talloc_free(params);
+ }
+ }
+
+ /* TLV (O) MS Power Parameters IE */
+ if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) {
+ /* Allocate a new chunk and initialize with default values */
+ params = talloc(trx, struct gsm_power_ctrl_params);
+ power_ctrl_params_def_reset(params, false);
+
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) == 0) {
+ /* Initially it points to the global defaults */
+ if (trx->ms_dpc_params != &bts->ms_dpc_params)
+ talloc_free(trx->ms_dpc_params);
+ trx->ms_dpc_params = params;
+ } else {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "Failed to parse MS Power Parameters IE\n");
+ rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, NULL, NULL, msg);
+ talloc_free(params);
+ }
+ }
+
+ return 0;
+}
+
/* 8.5.6 IMMEDIATE ASSIGN COMMAND is received */
static int rsl_rx_imm_ass(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
struct tlv_parsed tp;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
+ }
if (!TLVP_PRESENT(&tp, RSL_IE_FULL_IMM_ASS_INFO))
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &cch->chan_nr, NULL, msg);
@@ -701,6 +1384,45 @@ static int rsl_rx_imm_ass(struct gsm_bts_trx *trx, struct msgb *msg)
msg->l2h = NULL;
msg->len = TLVP_LEN(&tp, RSL_IE_FULL_IMM_ASS_INFO);
+ /* Early Immediate Assignment: when there is a lot of latency on Abis, the Abis roundtrip of Chan Activ -> Chan
+ * Activ ACK -> Immediate Assignment may take so long that each MS sends a second RACH for Chan Rqd, reserving
+ * two SDCCH for each request but using only one. To help with that, the Early IA feature in osmo-bsc sends the
+ * Immediate Assignment without waiting for the Channel Activation ACK. This may then be too early, and the MS
+ * may not be able to establish a channel. So to help with Early IA, look up whether the target lchan is already
+ * active. If not, then hold back the RR Immediate Assignment message, and send it once L1 has confirmed that
+ * the channel is active. Hence we still wait for the activation, but don't need the Abis roundtrip of Activ ACK
+ * -> Immediate Assignment via the BSC.
+ * If anything is wrong with the sizes or the lchan lookup, behave normally, i.e. do not do the RR IA caching,
+ * but just send the RR message to the MS as-is.
+ * 'trx' here is the TRX of the BCCH channel. To find the correct TRX for the IMM ASS target, we need to look up
+ * the ARFCN that is contained in the IMM ASS message. When frequency hopping is enabled, there will not be an
+ * ARFCN, so we cannot support early-IA with frequency hopping enabled. */
+ if (msg->len >= sizeof(struct gsm48_imm_ass)) {
+ struct gsm48_imm_ass *rr_ia = (void*)msg->data;
+ if (rr_ia->chan_desc.h0.h == 0) {
+ /* hopping is disabled. */
+ struct gsm_bts_trx *ia_target_trx;
+ uint16_t arfcn;
+ arfcn = (rr_ia->chan_desc.h0.arfcn_high << 8) + rr_ia->chan_desc.h0.arfcn_low;
+
+ ia_target_trx = trx_lookup_by_arfcn(&trx->bts->trx_list, arfcn);
+ if (ia_target_trx) {
+ /* found the ARFCN's trx */
+ struct gsm_lchan *ia_target_lchan;
+ ia_target_lchan = lchan_lookup(ia_target_trx, rr_ia->chan_desc.chan_nr, "Early IA check: ");
+ if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) {
+ /* Target lchan is not yet active. Cache the IA.
+ * If a previous IA is still lingering, free it. */
+ msgb_free(ia_target_lchan->early_rr_ia);
+ ia_target_lchan->early_rr_ia = msg;
+
+ /* return 1 means: don't msgb_free() the msg */
+ return 1;
+ }
+ }
+ }
+ }
+
/* put into the AGCH queue of the BTS */
if (bts_agch_enqueue(trx->bts, msg) < 0) {
/* if there is no space in the queue: send DELETE IND */
@@ -738,7 +1460,7 @@ static int tx_rf_rel_ack(struct gsm_lchan *lchan, uint8_t chan_nr)
/* 8.4.19 sending RF CHANnel RELease ACKnowledge */
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
{
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
bool send_rel_ack;
switch (lchan->rel_act_kind) {
@@ -748,26 +1470,40 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
case LCHAN_REL_ACT_PCU:
switch (lchan->ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
if (lchan->ts->dyn.pchan_is != GSM_PCHAN_PDCH) {
LOGP(DRSL, LOGL_ERROR, "%s (ss=%d) PDCH release: not in PDCH mode\n",
gsm_ts_and_pchan_name(lchan->ts), lchan->nr);
/* well, what to do about it ... carry on and hope it's fine. */
}
- /* remember the fact that the TS is now released */
- lchan->ts->dyn.pchan_is = GSM_PCHAN_NONE;
- /* Continue to ack the release below. (This is a non-standard rel ack invented
- * specifically for GSM_PCHAN_TCH_F_TCH_H_PDCH). */
- send_rel_ack = true;
+ if (lchan->ts->dyn.pchan_want != GSM_PCHAN_PDCH) {
+ /* Continue to ack the release below. (This is a non-standard rel ack invented
+ * specifically for GSM_PCHAN_OSMO_DYN). */
+ /* remember the fact that the TS is now released */
+ lchan->ts->dyn.pchan_is = GSM_PCHAN_NONE;
+ send_rel_ack = true;
+ } else {
+ /* Administrteively locked TRX, no need to
+ inform BSC. Keep pchan_is for when we are
+ unlocked again, since lower layers are stil
+ lconfigured for PDCH but we simply annonced
+ non-availability to PCU */
+ send_rel_ack = false;
+ }
break;
case GSM_PCHAN_TCH_F_PDCH:
/* GSM_PCHAN_TCH_F_PDCH, does not require a rel ack. The caller
* l1sap_info_rel_cnf() will continue with bts_model_ts_disconnect(). */
send_rel_ack = false;
break;
+ case GSM_PCHAN_PDCH:
+ /* Release was instructed by the BTS, for instance because the TRX is
+ * administrateively Locked */
+ send_rel_ack = false;
+ break;
default:
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "PCU rel ack for unexpected lchan kind %s\n",
- gsm_pchan_name(lchan->rel_act_kind));
+ gsm_pchan_name(lchan->ts->pchan));
/* Release certainly was not requested by the BSC via RSL, so don't ack. */
send_rel_ack = false;
break;
@@ -782,20 +1518,14 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
}
if (!send_rel_ack) {
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "%s not sending REL ACK\n", gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "not sending REL ACK\n");
return 0;
}
- LOGP(DRSL, LOGL_NOTICE, "%s (ss=%d) %s Tx CHAN REL ACK\n",
+ LOGP(DRSL, LOGL_INFO, "%s (ss=%d) %s Tx CHAN REL ACK\n",
gsm_ts_and_pchan_name(lchan->ts), lchan->nr,
gsm_lchant_name(lchan->type));
- /*
- * Free the LAPDm resources now that the BTS
- * has released all the resources.
- */
- lapdm_channel_exit(&lchan->lapdm_ch);
-
return tx_rf_rel_ack(lchan, chan_nr);
}
@@ -804,10 +1534,10 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
{
struct gsm_time *gtime = get_time(lchan->ts->trx->bts);
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
uint8_t ie[2];
- LOGP(DRSL, LOGL_NOTICE, "%s (ss=%d) %s Tx CHAN ACT ACK\n",
+ LOGP(DRSL, LOGL_INFO, "%s (ss=%d) %s Tx CHAN ACT ACK\n",
gsm_ts_and_pchan_name(lchan->ts), lchan->nr,
gsm_lchant_name(lchan->type));
@@ -826,28 +1556,50 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
return abis_bts_rsl_sendmsg(msg);
}
-/* 8.4.7 sending HANDOver DETection */
-int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
+/* common helper function for *_DETECT */
+static int _rsl_tx_detect(struct gsm_lchan *lchan, uint8_t msg_type, uint8_t *acc_delay)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
-
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
if (!msg)
return -ENOMEM;
/* 9.3.17 Access Delay */
- if (ho_delay)
- msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *ho_delay);
+ if (acc_delay)
+ msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *acc_delay);
- rsl_dch_push_hdr(msg, RSL_MT_HANDO_DET, chan_nr);
+ rsl_dch_push_hdr(msg, msg_type, chan_nr);
msg->trx = lchan->ts->trx;
return abis_bts_rsl_sendmsg(msg);
}
+/* 8.4.7 sending HANDOver DETection */
+int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_HANDO_DET, ho_delay);
+}
+
+/* 8.4.22 sending LISTENER DETection */
+int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending LISTENER DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_LISTENER_DET, acc_delay);
+}
+
+/* 8.4.21 sending TALKER DETection */
+int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending TALKER DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_TALKER_DET, acc_delay);
+}
+
/* 8.4.3 sending CHANnel ACTIVation Negative ACK */
static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8_t cause,
struct gsm_lchan *lchan)
@@ -855,7 +1607,7 @@ static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8
struct msgb *msg;
if (lchan)
- LOGP(DRSL, LOGL_NOTICE, "%s: ", gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "");
else
LOGP(DRSL, LOGL_NOTICE, "0x%02x: ", chan_nr);
LOGPC(DRSL, LOGL_NOTICE, "Sending Channel Activated NACK: cause = 0x%02x\n", cause);
@@ -872,14 +1624,14 @@ static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8
return abis_bts_rsl_sendmsg(msg);
}
static int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) {
- return _rsl_tx_chan_act_nack(lchan->ts->trx, gsm_lchan2chan_nr(lchan), cause, lchan);
+ return _rsl_tx_chan_act_nack(lchan->ts->trx, gsm_lchan2chan_nr_rsl(lchan), cause, lchan);
}
/* Send an RSL Channel Activation Ack if cause is zero, a Nack otherwise. */
int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause)
{
if (lchan->rel_act_kind != LCHAN_REL_ACT_RSL) {
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "not sending CHAN ACT %s\n",
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "not sending CHAN ACT %s\n",
cause ? "NACK" : "ACK");
return 0;
}
@@ -890,10 +1642,10 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause)
}
/* 8.4.4 sending CONNection FAILure */
-int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause)
+int rsl_tx_conn_fail(const struct gsm_lchan *lchan, uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Sending Connection Failure: cause = 0x%02x\n", cause);
@@ -996,17 +1748,13 @@ static void clear_lchan_for_pdch_activ(struct gsm_lchan *lchan)
{
/* These values don't apply to PDCH, just clear them. Particularly the encryption must be
* cleared, or we would enable encryption on PDCH with parameters remaining from the TCH. */
- lchan->ms_power = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0);
- lchan->ms_power_ctrl.current = lchan->ms_power;
- lchan->ms_power_ctrl.fixed = 0;
lchan->rsl_cmode = 0;
lchan->tch_mode = 0;
memset(&lchan->encr, 0, sizeof(lchan->encr));
memset(&lchan->ho, 0, sizeof(lchan->ho));
- lchan->bs_power = 0;
- lchan->ms_power = 0;
memset(&lchan->ms_power_ctrl, 0, sizeof(lchan->ms_power_ctrl));
- lchan->rqd_ta = 0;
+ memset(&lchan->bs_power_ctrl, 0, sizeof(lchan->bs_power_ctrl));
+ lchan->ta_ctrl.current = 0;
copy_sacch_si_to_lchan(lchan);
memset(&lchan->tch, 0, sizeof(lchan->tch));
}
@@ -1015,13 +1763,14 @@ static void clear_lchan_for_pdch_activ(struct gsm_lchan *lchan)
* Store the CHAN_ACTIV msg, connect the L1 timeslot in the proper type and
* then invoke rsl_rx_chan_activ() with msg.
*/
-static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts, struct msgb *msg)
+static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts)
{
DEBUGP(DRSL, "%s dyn_ts_l1_reconnect\n", gsm_ts_and_pchan_name(ts));
switch (ts->dyn.pchan_want) {
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
+ case GSM_PCHAN_SDCCH8_SACCH8C:
break;
case GSM_PCHAN_PDCH:
/* Only the first lchan matters for PDCH */
@@ -1035,9 +1784,6 @@ static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts, struct msgb *msg)
return -EINVAL;
}
- /* We will feed this back to rsl_rx_chan_activ() later */
- ts->dyn.pending_chan_activ = msg;
-
/* Disconnect, continue connecting from cb_ts_disconnected(). */
DEBUGP(DRSL, "%s Disconnect\n", gsm_ts_and_pchan_name(ts));
return bts_model_ts_disconnect(ts);
@@ -1045,14 +1791,23 @@ static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts, struct msgb *msg)
static enum gsm_phys_chan_config dyn_pchan_from_chan_nr(uint8_t chan_nr)
{
- uint8_t cbits = chan_nr & RSL_CHAN_NR_MASK;
+ uint8_t cbits = chan_nr >> 3;
switch (cbits) {
- case RSL_CHAN_Bm_ACCHs:
+ case ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs:
return GSM_PCHAN_TCH_F;
- case RSL_CHAN_Lm_ACCHs:
- case (RSL_CHAN_Lm_ACCHs + RSL_CHAN_NR_1):
+ case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(0):
+ case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(1):
return GSM_PCHAN_TCH_H;
- case RSL_CHAN_OSMO_PDCH:
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(0):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(1):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(2):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(3):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(4):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(5):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(6):
+ case ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(7):
+ return GSM_PCHAN_SDCCH8_SACCH8C;
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH:
return GSM_PCHAN_PDCH;
default:
LOGP(DRSL, LOGL_ERROR,
@@ -1062,24 +1817,145 @@ static enum gsm_phys_chan_config dyn_pchan_from_chan_nr(uint8_t chan_nr)
}
}
+/* Parse RSL_IE_OSMO_REP_ACCH_CAP */
+static int parse_repeated_acch_capability(struct gsm_lchan *lchan, struct tlv_parsed *tp)
+{
+ /* 3GPP TS 24.008, section 10.5.1.7 defines a Repeated ACCH Capability
+ * bit that indicates if REPEATED FACCH/SACCH is supported or not.
+ * Unfortunately there is not 3gpp spec that describes how this bit
+ * should be communicated in the RSL CHANNEL ACTIVATION. For osmo-bts
+ * we will use a propritary IE. */
+
+ memset(&lchan->rep_acch_cap, 0, sizeof(lchan->rep_acch_cap));
+
+ if (!TLVP_PRES_LEN(tp, RSL_IE_OSMO_REP_ACCH_CAP, sizeof(lchan->rep_acch_cap)))
+ return 0;
+
+ if (!osmo_bts_has_feature(lchan->ts->trx->bts->features, BTS_FEAT_ACCH_REP))
+ return -RSL_ERR_OPT_IE_ERROR;
+
+ memcpy(&lchan->rep_acch_cap, TLVP_VAL(tp, RSL_IE_OSMO_REP_ACCH_CAP),
+ sizeof(lchan->rep_acch_cap));
+
+ return 0;
+}
+
+/* Parse RSL_IE_OSMO_TOP_ACCH_CAP */
+static int parse_temporary_overpower_acch_capability(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp)
+{
+ memset(&lchan->top_acch_cap, 0, sizeof(lchan->top_acch_cap));
+
+ if (!TLVP_PRES_LEN(tp, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP, sizeof(lchan->top_acch_cap)))
+ return 0;
+
+ if (!osmo_bts_has_feature(lchan->ts->trx->bts->features, BTS_FEAT_ACCH_TEMP_OVP))
+ return -RSL_ERR_OPT_IE_ERROR;
+
+ memcpy(&lchan->top_acch_cap,
+ TLVP_VAL(tp, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP),
+ sizeof(lchan->top_acch_cap));
+
+ /* Simplify checking whether the overpower is enabled at all: allow
+ * testing just one parameter (overpower_db > 0) instead of all three. */
+ if (!lchan->top_acch_cap.sacch_enable && !lchan->top_acch_cap.facch_enable)
+ lchan->top_acch_cap.overpower_db = 0;
+
+ return 0;
+}
+
+/* Parse (O) MultiRate configuration IE (see 9.3.52) */
+static int parse_multirate_config(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp)
+{
+ int rc;
+
+ if (!TLVP_PRESENT(tp, RSL_IE_MR_CONFIG)) {
+ /* Included if the Channel Mode indicates that a multi-rate codec is used */
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Missing MultiRate conf IE "
+ "(TCH mode is %s)\n", gsm48_chan_mode_name(lchan->tch_mode));
+ /* Init lchan->tch.amr_mr with hard-coded default values */
+ amr_init_mr_conf_def(lchan);
+ goto parsed;
+ }
+ return 0;
+ }
+
+ /* Included if the Channel Mode indicates that a multi-rate codec is used */
+ if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Unexpected MultiRate conf IE "
+ "(TCH mode is %s)\n", gsm48_chan_mode_name(lchan->tch_mode));
+ return -RSL_ERR_OPT_IE_ERROR;
+ }
+
+ rc = amr_parse_mr_conf(&lchan->tch.amr_mr,
+ TLVP_VAL(tp, RSL_IE_MR_CONFIG),
+ TLVP_LEN(tp, RSL_IE_MR_CONFIG));
+ if (rc < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Error parsing MultiRate conf IE\n");
+ return -RSL_ERR_IE_CONTENT;
+ }
+
+parsed:
+ amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), &lchan->tch.amr_mr);
+ lchan->tch.last_cmr = AMR_CMR_NONE;
+ return 0;
+}
+
/* 8.4.1 CHANnel ACTIVation is received */
static int rsl_rx_chan_activ(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
struct gsm_bts_trx_ts *ts = lchan->ts;
- struct rsl_ie_chan_mode *cm;
+ struct gsm_bts_trx_ts *primary_ts;
struct tlv_parsed tp;
- uint8_t type;
+ const struct tlv_p_entry *ie;
+ uint8_t type, cause;
+ bool reactivation = false;
int rc;
- if (lchan->state != LCHAN_S_NONE) {
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_PROTO);
+ }
+
+ /* 9.3.3 Activation Type */
+ if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Activation Type\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR);
+ }
+ type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
+ if ((type & RSL_ACT_TYPE_REACT)) {
+ type -= RSL_ACT_TYPE_REACT;
+ reactivation = true;
+ }
+
+ /* If Activation Type is IMMEDIATE ASSIGNMENT, we expect L3 info with establishment. */
+ lchan->l3_info_estab = (type == RSL_ACT_INTRA_IMM_ASS);
+
+ if (!reactivation && lchan->state != LCHAN_S_NONE) {
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "error: lchan is not available, but in state: %s.\n",
gsm_lchans_name(lchan->state));
return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
}
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ if (reactivation && lchan->state == LCHAN_S_NONE) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "error: reactivation on inactive lchan.\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ }
+
+ /* We need to pick the real TS here to check NM state: */
+ primary_ts = ts->vamos.is_shadow ? ts->vamos.peer : ts;
+ if (primary_ts->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
+ primary_ts->mo.nm_state.availability != NM_AVSTATE_OK) {
+ LOGP(DRSL, LOGL_ERROR, "%s rx chan activ but TS not in nm_state oper=ENABLED avail=OK, nack!\n",
+ gsm_ts_and_pchan_name(ts));
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_RR_UNAVAIL);
+ }
+
+ if (ts->pchan == GSM_PCHAN_OSMO_DYN) {
ts->dyn.pchan_want = dyn_pchan_from_chan_nr(dch->chan_nr);
DEBUGP(DRSL, "%s rx chan activ\n", gsm_ts_and_pchan_name(ts));
@@ -1089,39 +1965,37 @@ static int rsl_rx_chan_activ(struct msgb *msg)
* mode than this activation needs it to be.
* Re-connect, then come back to rsl_rx_chan_activ().
*/
- rc = dyn_ts_l1_reconnect(ts, msg);
+ rc = dyn_ts_l1_reconnect(ts);
if (rc)
return rsl_tx_chan_act_nack(lchan, RSL_ERR_NORMAL_UNSPEC);
+ /* will be fed back to rsl_rx_chan_activ() later */
+ OSMO_ASSERT(lchan->pending_chan_activ == NULL);
+ lchan->pending_chan_activ = msg;
/* indicate that the msgb should not be freed. */
return 1;
}
}
- LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "rx Channel Activation in state: %s.\n",
- gsm_lchans_name(lchan->state));
-
- /* Initialize channel defaults */
- lchan->ms_power = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0);
- lchan->ms_power_ctrl.current = lchan->ms_power;
- lchan->ms_power_ctrl.fixed = 0;
-
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ /* Initialize MS Power Control defaults */
+ lchan->ms_power_ctrl = (struct lchan_power_ctrl_state) {
+ .max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0),
+ .current = lchan->ms_power_ctrl.max,
+ };
- /* 9.3.3 Activation Type */
- if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Activation Type\n");
- return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR);
- }
- type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
+ /* Initialize BS Power Control defaults */
+ lchan->bs_power_ctrl = (struct lchan_power_ctrl_state) {
+ .max = 2 * 15, /* maximum defined in 9.3.4 */
+ .current = 0,
+ };
/* 9.3.6 Channel Mode */
if (type != RSL_ACT_OSMO_PDCH) {
- if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) {
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Channel Mode\n");
- return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR);
- }
- cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
- lchan_tchmode_from_cmode(lchan, cm);
+ if (rsl_handle_chan_mod_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_chan_act_nack(lchan, cause);
+ if (rsl_handle_chan_ident_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_chan_act_nack(lchan, cause);
+ if (rsl_handle_osmo_tsc_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_chan_act_nack(lchan, cause);
}
/* 9.3.7 Encryption Information */
@@ -1149,28 +2023,73 @@ static int rsl_rx_chan_activ(struct msgb *msg)
}
/* 9.3.4 BS Power */
- if (TLVP_PRES_LEN(&tp, RSL_IE_BS_POWER, 1))
- lchan->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER);
+ if (TLVP_PRES_LEN(&tp, RSL_IE_BS_POWER, 1)) {
+ if (*TLVP_VAL(&tp, RSL_IE_BS_POWER) & (1 << 4)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE,
+ "Fast Power Control is not supported\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_SERV_OPT_UNIMPL);
+ }
+
+ uint8_t red = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));
+
+ /* BS power reduction is generally not allowed on BCCH/CCCH carrier.
+ * However, we allow it in the BCCH carrier power reduction operation.
+ * Constrain BS power value by the maximum reduction for this timeslot. */
+ if (ts->trx->bts->c0 == ts->trx)
+ red = OSMO_MIN(red, ts->c0_power_red_db);
+
+ lchan->bs_power_ctrl.max = red;
+ lchan->bs_power_ctrl.current = red;
+
+ LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "BS Power attenuation %u dB\n",
+ lchan->bs_power_ctrl.current);
+ }
+
/* 9.3.13 MS Power */
if (TLVP_PRES_LEN(&tp, RSL_IE_MS_POWER, 1)) {
- lchan->ms_power = *TLVP_VAL(&tp, RSL_IE_MS_POWER);
- lchan->ms_power_ctrl.current = lchan->ms_power;
- lchan->ms_power_ctrl.fixed = 0;
+ lchan->ms_power_ctrl.max = *TLVP_VAL(&tp, RSL_IE_MS_POWER) & 0x1F;
+ lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
}
/* 9.3.24 Timing Advance */
if (TLVP_PRES_LEN(&tp, RSL_IE_TIMING_ADVANCE, 1))
- lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
+ lchan->ta_ctrl.current = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
+
+ /* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */
+ if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) {
+ struct gsm_power_ctrl_params *params = &lchan->ms_dpc_params;
+
+ /* Parsed parameters will override per-TRX defaults */
+ memcpy(params, ts->trx->ms_dpc_params, sizeof(*params));
+
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse MS Power Parameters IE\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT);
+ }
- /* 9.3.32 BS Power Parameters */
- /* 9.3.31 MS Power Parameters */
- if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM))
- lchan->ms_power_ctrl.fixed = 0;
- else {
/* Spec explicitly states BTS should only perform
* autonomous MS power control loop in BTS if 'MS Power
* Parameters' IE is present! */
- lchan->ms_power_ctrl.fixed = 1;
+ lchan->ms_power_ctrl.dpc_params = params;
+ }
+
+ /* 9.3.32 (TLV) BS Power Parameters IE (vendor specific) */
+ if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) {
+ struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params;
+
+ /* Parsed parameters will override per-TRX defaults */
+ memcpy(params, ts->trx->bs_dpc_params, sizeof(*params));
+
+ /* Parsed parameters will override per-TRX defaults */
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse BS Power Parameters IE\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT);
+ }
+
+ /* NOTE: it's safer to start from 0 */
+ lchan->bs_power_ctrl.current = 0;
+ lchan->bs_power_ctrl.dpc_params = params;
}
+
/* 9.3.16 Physical Context */
/* 9.3.29 SACCH Information */
@@ -1213,29 +2132,22 @@ static int rsl_rx_chan_activ(struct msgb *msg)
/* use standard SACCH filling of the BTS */
copy_sacch_si_to_lchan(lchan);
}
+
/* 9.3.52 MultiRate Configuration */
- if (TLVP_PRESENT(&tp, RSL_IE_MR_CONFIG)) {
- if (TLVP_LEN(&tp, RSL_IE_MR_CONFIG) > sizeof(lchan->mr_bts_lv) - 1) {
- LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Error parsing MultiRate conf IE\n");
- rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT, &dch->chan_nr, NULL, msg);
- return rsl_tx_chan_act_acknack(lchan, RSL_ERR_IE_CONTENT);
- }
- memcpy(lchan->mr_bts_lv, TLVP_VAL(&tp, RSL_IE_MR_CONFIG) - 1,
- TLVP_LEN(&tp, RSL_IE_MR_CONFIG) + 1);
- amr_parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG),
- TLVP_LEN(&tp, RSL_IE_MR_CONFIG));
- amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan),
- &lchan->tch.amr_mr);
- lchan->tch.last_cmr = AMR_CMR_NONE;
- }
+ rc = parse_multirate_config(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_chan_act_acknack(lchan, -rc);
+
/* 9.3.53 MultiRate Control */
/* 9.3.54 Supported Codec Types */
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "chan_nr=%s type=0x%02x mode=%s\n",
- rsl_chan_nr_str(dch->chan_nr), type, gsm48_chan_mode_name(lchan->tch_mode));
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "chan_nr=%s type=0x%02x=%s mode=%s\n",
+ rsl_chan_nr_str(dch->chan_nr),
+ type, get_value_string(rsl_act_type_names, type),
+ gsm48_chan_mode_name(lchan->tch_mode));
/* Connecting PDCH on dyn TS goes via PCU instead. */
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
+ if (ts->pchan == GSM_PCHAN_OSMO_DYN
&& ts->dyn.pchan_want == GSM_PCHAN_PDCH) {
/*
* We ack the activation to the BSC right away, regardless of
@@ -1281,48 +2193,75 @@ static int rsl_rx_chan_activ(struct msgb *msg)
return 0;
}
+ /* Indicate which SAPIs should be enabled before the first RACH is received, for handover. See 3GPP TS 48.058
+ * 4.1.3 and 4.1.4.
+ *
+ * | | Timing || transmit | activate | This implementation
+ * | MS Power | Advance || on main channel | dl SACCH | activates DL SACCH
+ * -----------------------------------------------------------------------------------------
+ * async ho no * --> yes no no
+ * async ho yes * --> yes may be started no
+ * async ho yes yes --> yes may be started yes
+ * sync ho no no --> yes no no
+ * sync ho yes no --> yes may be started no
+ * sync ho yes yes --> yes shall be started yes
+ */
+ switch (type) {
+ case RSL_ACT_INTER_ASYNC:
+ case RSL_ACT_INTER_SYNC:
+ lchan->want_dl_sacch_active = (TLVP_PRES_LEN(&tp, RSL_IE_MS_POWER, 1)
+ && TLVP_PRES_LEN(&tp, RSL_IE_TIMING_ADVANCE, 1));
+ break;
+ default:
+ lchan->want_dl_sacch_active = true;
+ break;
+ }
+
/* Remember to send an RSL ACK once the lchan is active */
lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
- /* actually activate the channel in the BTS */
- rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr, &tp);
+ rc = parse_repeated_acch_capability(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_chan_act_acknack(lchan, -rc);
+ rc = parse_temporary_overpower_acch_capability(lchan, &tp);
if (rc < 0)
return rsl_tx_chan_act_acknack(lchan, -rc);
- return 0;
-}
-
-static int dyn_ts_pdch_release(struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
+ /* Take the first ACCH overpower decision (if allowed): it can be
+ * enabled immediately if the RxQual threshold is disabled (0). */
+ if (lchan->top_acch_cap.overpower_db > 0)
+ lchan->top_acch_active = !lchan->top_acch_cap.rxqual;
+ else
+ lchan->top_acch_active = false;
- if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
- LOGP(DRSL, LOGL_ERROR, "%s: PDCH release requested but already"
- " in switchover\n", gsm_ts_and_pchan_name(ts));
- return -EINVAL;
+ /* set ASCI channel into right state */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
+ if (reactivation)
+ vgcs_lchan_react(lchan);
+ else
+ vgcs_lchan_activate(lchan);
}
- /*
- * Indicate PDCH Disconnect in dyn_pdch.want, let pcu_tx_info_ind()
- * pick it up and wait for PCU to disable the channel.
- */
- ts->dyn.pchan_want = GSM_PCHAN_NONE;
-
- if (!pcu_connected()) {
- /* PCU not connected yet. Just record the new type and done,
- * the PCU will pick it up once connected. */
- ts->dyn.pchan_is = GSM_PCHAN_NONE;
- return 1;
+ /* on reactivation, the channel is already activated */
+ if (reactivation) {
+ rc = rsl_tx_chan_act_ack(lchan);
+ if (rc < 0)
+ LOGP(DRSL, LOGL_ERROR, "%s Cannot send act ack: %d\n",
+ gsm_ts_and_pchan_name(ts), rc);
+ return 0;
}
- return pcu_tx_info_ind();
+ /* actually activate the channel in the BTS */
+ rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr);
+ if (rc < 0)
+ return rsl_tx_chan_act_acknack(lchan, -rc);
+
+ return 0;
}
/* 8.4.14 RF CHANnel RELease is received */
static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr)
{
- int rc;
-
if (lchan->state == LCHAN_S_NONE) {
LOGP(DRSL, LOGL_ERROR,
"%s ss=%d state=%s Rx RSL RF Channel Release, but is already inactive;"
@@ -1333,38 +2272,7 @@ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr)
* not necessarily reflecting the current lchan state. */
return tx_rf_rel_ack(lchan, chan_nr);
}
-
- if (lchan->abis_ip.rtp_socket) {
- rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
- osmo_rtp_socket_log_stats(lchan->abis_ip.rtp_socket, DRTP, LOGL_INFO,
- "Closing RTP socket on Channel Release ");
- osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- msgb_queue_flush(&lchan->dl_tch_queue);
- }
-
- /* release handover state */
- handover_reset(lchan);
-
- lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
-
- /* Dynamic channel in PDCH mode is released via PCU */
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
- && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) {
- rc = dyn_ts_pdch_release(lchan);
- if (rc == 1) {
- /* If the PCU is not connected, continue to rel ack right away. */
- lchan->rel_act_kind = LCHAN_REL_ACT_PCU;
- return rsl_tx_rf_rel_ack(lchan);
- }
- /* Waiting for PDCH release */
- return rc;
- }
-
- l1sap_chan_rel(lchan->ts->trx, chan_nr);
-
- lapdm_channel_exit(&lchan->lapdm_ch);
-
+ gsm_lchan_release(lchan, LCHAN_REL_ACT_RSL);
return 0;
}
@@ -1398,7 +2306,7 @@ static int tx_ciph_mod_compl_hack(struct gsm_lchan *lchan, uint8_t link_id,
}
}
- rsl_rll_push_l3(fake_msg, RSL_MT_DATA_IND, gsm_lchan2chan_nr(lchan),
+ rsl_rll_push_l3(fake_msg, RSL_MT_DATA_IND, gsm_lchan2chan_nr_rsl(lchan),
link_id, 1);
fake_msg->lchan = lchan;
@@ -1443,7 +2351,8 @@ static int rsl_rx_encr_cmd(struct msgb *msg)
uint8_t link_id;
if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
- return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT, &dch->chan_nr, NULL, msg);
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(msg->trx, RSL_ERR_PROTO, &dch->chan_nr, NULL, msg);
}
if (!TLVP_PRESENT(&tp, RSL_IE_ENCR_INFO) ||
@@ -1512,7 +2421,7 @@ static int _rsl_tx_mode_modif_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uin
struct msgb *msg;
if (lchan)
- LOGP(DRSL, LOGL_NOTICE, "%s: ", gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "");
else
LOGP(DRSL, LOGL_NOTICE, "0x%02x: ", chan_nr);
LOGPC(DRSL, LOGL_NOTICE, "Tx MODE MODIFY NACK (cause = 0x%02x)\n", cause);
@@ -1533,7 +2442,7 @@ static int _rsl_tx_mode_modif_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uin
}
static int rsl_tx_mode_modif_nack(struct gsm_lchan *lchan, uint8_t cause)
{
- return _rsl_tx_mode_modif_nack(lchan->ts->trx, gsm_lchan2chan_nr(lchan), cause, lchan);
+ return _rsl_tx_mode_modif_nack(lchan->ts->trx, gsm_lchan2chan_nr_rsl(lchan), cause, lchan);
}
@@ -1541,7 +2450,7 @@ static int rsl_tx_mode_modif_nack(struct gsm_lchan *lchan, uint8_t cause)
static int rsl_tx_mode_modif_ack(struct gsm_lchan *lchan)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Tx MODE MODIF ACK\n");
@@ -1560,24 +2469,24 @@ static int rsl_rx_mode_modif(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
- struct rsl_ie_chan_mode *cm;
struct tlv_parsed tp;
+ uint8_t cause;
+ int rc;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
-
- /* 9.3.6 Channel Mode */
- if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) {
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Channel Mode\n");
- return rsl_tx_mode_modif_nack(lchan, RSL_ERR_MAND_IE_ERROR);
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_mode_modif_nack(lchan, RSL_ERR_PROTO);
}
- cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
- lchan_tchmode_from_cmode(lchan, cm);
- if (bts_supports_cm(lchan->ts->trx->bts, ts_pchan(lchan->ts), lchan->tch_mode) != 1) {
- LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s: invalid mode: %s (wrong BSC configuration?)\n",
- gsm_ts_and_pchan_name(lchan->ts), gsm48_chan_mode_name(lchan->tch_mode));
- return rsl_tx_mode_modif_nack(lchan, RSL_ERR_SERV_OPT_UNAVAIL);
- }
+ /* 9.3.6 Channel Mode */
+ if (rsl_handle_chan_mod_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_mode_modif_nack(lchan, cause);
+ /* 9.3.5 Channel Identification */
+ if (rsl_handle_chan_ident_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_mode_modif_nack(lchan, cause);
+ /* Osmocom specific TSC IE for VAMOS */
+ if (rsl_handle_osmo_tsc_ie(lchan, &tp, &cause) != 0)
+ return rsl_tx_mode_modif_nack(lchan, cause);
/* 9.3.7 Encryption Information */
if (TLVP_PRESENT(&tp, RSL_IE_ENCR_INFO)) {
@@ -1593,23 +2502,27 @@ static int rsl_rx_mode_modif(struct msgb *msg)
/* 9.3.45 Main channel reference */
/* 9.3.52 MultiRate Configuration */
- if (TLVP_PRESENT(&tp, RSL_IE_MR_CONFIG)) {
- if (TLVP_LEN(&tp, RSL_IE_MR_CONFIG) > sizeof(lchan->mr_bts_lv) - 1) {
- LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Error parsing MultiRate conf IE\n");
- rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT, &dch->chan_nr, NULL, msg);
- return rsl_tx_mode_modif_nack(lchan, RSL_ERR_IE_CONTENT);;
- }
- memcpy(lchan->mr_bts_lv, TLVP_VAL(&tp, RSL_IE_MR_CONFIG) - 1,
- TLVP_LEN(&tp, RSL_IE_MR_CONFIG) + 1);
- amr_parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG),
- TLVP_LEN(&tp, RSL_IE_MR_CONFIG));
- amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan),
- &lchan->tch.amr_mr);
- lchan->tch.last_cmr = AMR_CMR_NONE;
- }
+ rc = parse_multirate_config(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_mode_modif_nack(lchan, -rc);
+
/* 9.3.53 MultiRate Control */
/* 9.3.54 Supported Codec Types */
+ rc = parse_repeated_acch_capability(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_mode_modif_nack(lchan, -rc);
+ rc = parse_temporary_overpower_acch_capability(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_mode_modif_nack(lchan, -rc);
+
+ /* Immediately disable ACCH overpower if the value is 0 dB,
+ * or enable if the RxQual threshold becomes disabled (0). */
+ if (lchan->top_acch_cap.overpower_db == 0)
+ lchan->top_acch_active = false;
+ else if (lchan->top_acch_cap.rxqual == 0)
+ lchan->top_acch_active = true;
+
l1sap_chan_modify(lchan->ts->trx, dch->chan_nr);
/* FIXME: delay this until L1 says OK? */
@@ -1623,28 +2536,61 @@ static int rsl_rx_ms_pwr_ctrl(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ const struct tlv_p_entry *ie;
struct tlv_parsed tp;
uint8_t pwr;
+ int max_pwr, curr_pwr;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(msg->trx, RSL_ERR_PROTO, &dch->chan_nr, NULL, msg);
+ }
/* 9.3.13 MS Power (M) */
if (!TLVP_PRES_LEN(&tp, RSL_IE_MS_POWER, 1))
return rsl_tx_error_report(msg->trx, RSL_ERR_MAND_IE_ERROR, &dch->chan_nr, NULL, msg);
pwr = *TLVP_VAL(&tp, RSL_IE_MS_POWER) & 0x1F;
- lchan->ms_power_ctrl.current = pwr;
+ lchan->ms_power_ctrl.max = pwr;
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Rx MS POWER CONTROL %d\n", lchan->ms_power_ctrl.current);
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Rx MS POWER CONTROL %" PRIu8 "\n", pwr);
- /* 9.3.31 MS Power Parameters (O) */
- if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM))
- lchan->ms_power_ctrl.fixed = 0;
- else {
- /* Spec explicitly states BTS should only perform
- * autonomous MS power control loop in BTS if 'MS Power
- * Parameters' IE is present! */
- lchan->ms_power_ctrl.fixed = 1;
+ /* Spec explicitly states BTS should only perform autonomous MS Power
+ * control loop in BTS if 'MS Power Parameters' IE is present! */
+ lchan->ms_power_ctrl.dpc_params = NULL;
+
+ /* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */
+ if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) {
+ struct gsm_power_ctrl_params *params = &lchan->ms_dpc_params;
+
+ /* Parsed parameters will override per-TRX defaults */
+ memcpy(params, msg->trx->ms_dpc_params, sizeof(*params));
+
+ /* Parsed parameters will override per-TRX defaults */
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse MS Power Parameters IE\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT);
+ }
+
+ lchan->ms_power_ctrl.dpc_params = params;
+ }
+
+ /* Only set current to max if actual value of current
+ in dBm > value in dBm from max, or if fixed. */
+ if (lchan->ms_power_ctrl.dpc_params == NULL) {
+ lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
+ } else {
+ max_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.max);
+ curr_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.current);
+ if (max_pwr < 0 || curr_pwr < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR,
+ "Unable to calculate power levels to dBm: %" PRIu8 " -> %d, %" PRIu8 " -> %d\n",
+ lchan->ms_power_ctrl.max, max_pwr,
+ lchan->ms_power_ctrl.current, curr_pwr);
+ } else if (curr_pwr > max_pwr) {
+ lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
+ }
}
bts_model_adjst_ms_pwr(lchan);
@@ -1652,41 +2598,77 @@ static int rsl_rx_ms_pwr_ctrl(struct msgb *msg)
return 0;
}
-/* See TS 48.058 Section 9.3.4 */
-static int bs_power_attenuation_dB(uint8_t bs_power)
-{
- /* the lower nibble contains the number of 2dB steps that the BS power is reduced compared
- * to its nominal transmit power */
- return - ((bs_power & 0xF) *2);
-}
-
/* 8.4.16 BS POWER CONTROL */
static int rsl_rx_bs_pwr_ctrl(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
+ struct gsm_bts_trx *trx = msg->trx;
+ const struct tlv_p_entry *ie;
struct tlv_parsed tp;
- uint8_t new_bs_power;
+ uint8_t old, new;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(trx, RSL_ERR_PROTO, &dch->chan_nr, NULL, msg);
+ }
/* 9.3.4 BS Power (M) */
if (!TLVP_PRES_LEN(&tp, RSL_IE_BS_POWER, 1))
- return rsl_tx_error_report(msg->trx, RSL_ERR_MAND_IE_ERROR, &dch->chan_nr, NULL, msg);
+ return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &dch->chan_nr, NULL, msg);
+
+ if (*TLVP_VAL(&tp, RSL_IE_BS_POWER) & (1 << 4)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Fast Power Control is not supported\n");
+ return rsl_tx_error_report(trx, RSL_ERR_SERV_OPT_UNIMPL, &dch->chan_nr, NULL, msg);
+ }
+
+ new = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));
+ old = lchan->bs_power_ctrl.current;
+
+ /* Osmocom specific extension for BCCH carrier power reduction */
+ if (dch->chan_nr == RSL_CHAN_BCCH) {
+ int rc = bts_set_c0_pwr_red(trx->bts, new);
+ if (rc != 0) {
+ const uint8_t cause = (rc == -ENOTSUP) ?
+ RSL_ERR_SERV_OPT_UNIMPL : RSL_ERR_IE_CONTENT;
+ return rsl_tx_error_report(trx, cause, &dch->chan_nr, NULL, msg);
+ }
- new_bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER);
+ return 0;
+ }
+
+ /* BS power reduction is generally not allowed on BCCH/CCCH carrier.
+ * However, we allow it in the BCCH carrier power reduction operation.
+ * Constrain BS power value by the maximum reduction for this timeslot. */
+ if (trx->bts->c0 == trx)
+ new = OSMO_MIN(new, lchan->ts->c0_power_red_db);
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL Attenuation %d -> %d dB\n",
- bs_power_attenuation_dB(lchan->bs_power), bs_power_attenuation_dB(new_bs_power));
+ /* 9.3.32 (TLV) BS Power Parameters IE (vendor specific) */
+ if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) {
+ struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params;
- lchan->bs_power = new_bs_power;
+ /* Parsed parameters will override per-TRX defaults */
+ memcpy(params, trx->bs_dpc_params, sizeof(*params));
+
+ /* Parsed parameters will override per-TRX defaults */
+ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse BS Power Parameters IE\n");
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT);
+ }
- /* 9.3.31 MS Power Parameters (O) */
- if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER_PARAM)) {
- /* Spec explicitly states BTS should perform autonomous
- * BS power control loop in BTS if 'BS Power Parameters'
- * IE is present! WE don't support that. */
- return rsl_tx_error_report(msg->trx, RSL_ERR_OPT_IE_ERROR, &dch->chan_nr, NULL, msg);
+ /* NOTE: it's safer to start from 0 */
+ lchan->bs_power_ctrl.current = 0;
+ lchan->bs_power_ctrl.max = new;
+ lchan->bs_power_ctrl.dpc_params = params;
+ } else {
+ lchan->bs_power_ctrl.dpc_params = NULL;
+ lchan->bs_power_ctrl.current = new;
+ }
+
+ if (lchan->bs_power_ctrl.current != old) {
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL: "
+ "attenuation change %u -> %u dB\n",
+ old, lchan->bs_power_ctrl.current);
}
return 0;
@@ -1702,7 +2684,10 @@ static int rsl_rx_sacch_inf_mod(struct msgb *msg)
struct tlv_parsed tp;
uint8_t rsl_si, osmo_si;
- rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_error_report(msg->trx, RSL_ERR_PROTO, &dch->chan_nr, NULL, msg);
+ }
if (TLVP_PRESENT(&tp, RSL_IE_STARTNG_TIME)) {
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Starting time not supported\n");
@@ -1758,7 +2743,7 @@ int rsl_tx_cbch_load_indication(struct gsm_bts *bts, bool ext_cbch, bool overflo
return -ENOMEM;
/* 9.3.1 Channel Number */
- rsl_cch_push_hdr(msg, RSL_MT_CBCH_LOAD_IND, gsm_lchan2chan_nr(lchan));
+ rsl_cch_push_hdr(msg, RSL_MT_CBCH_LOAD_IND, gsm_lchan2chan_nr_rsl(lchan));
/* 9.3.43 CBCH Load Information */
load_info = ((overflow & 1) << 7) | (amount & 0x0F);
@@ -1810,7 +2795,9 @@ int rsl_tx_ipac_dlcx_ind(struct gsm_lchan *lchan, uint8_t cause)
{
struct msgb *nmsg;
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Sending RTP delete indication: cause = %s\n",
+ LOGPLCHAN(lchan, DRSL,
+ (cause == RSL_ERR_NORMAL_UNSPEC) ? LOGL_INFO : LOGL_NOTICE,
+ "Sending RTP delete indication: cause = %s\n",
rsl_err_name(cause));
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
@@ -1820,7 +2807,7 @@ int rsl_tx_ipac_dlcx_ind(struct gsm_lchan *lchan, uint8_t cause)
msgb_tv16_put(nmsg, RSL_IE_IPAC_CONN_ID, htons(lchan->abis_ip.conn_id));
rsl_add_rtp_stats(lchan, nmsg);
msgb_tlv_put(nmsg, RSL_IE_CAUSE, 1, &cause);
- rsl_ipa_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND, gsm_lchan2chan_nr(lchan));
+ rsl_ipa_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND, gsm_lchan2chan_nr_rsl(lchan));
nmsg->trx = lchan->ts->trx;
@@ -1832,7 +2819,7 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
uint8_t orig_msgt)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
const char *name;
struct in_addr ia;
@@ -1870,6 +2857,11 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
lchan->abis_ip.rtp_payload2);
}
+ /* Osmocom Extension: Osmux CID */
+ if (lchan->abis_ip.osmux.use)
+ msgb_tlv_put(msg, RSL_IE_OSMO_OSMUX_CID, 1,
+ &lchan->abis_ip.osmux.local_cid);
+
/* push the header in front */
rsl_ipa_push_hdr(msg, orig_msgt + 1, chan_nr);
msg->trx = lchan->ts->trx;
@@ -1880,7 +2872,7 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
static int rsl_tx_ipac_dlcx_ack(struct gsm_lchan *lchan, int inc_conn_id)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "RSL Tx IPAC_DLCX_ACK\n");
@@ -1903,7 +2895,7 @@ static int rsl_tx_ipac_dlcx_nack(struct gsm_lchan *lchan, int inc_conn_id,
uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "RSL Tx IPAC_DLCX_NACK\n");
@@ -1924,15 +2916,15 @@ static int rsl_tx_ipac_dlcx_nack(struct gsm_lchan *lchan, int inc_conn_id,
}
-/* transmit an CRCX NACK for the lchan */
+/* Send an xxCX NACK for the given xxCX message type and lchan */
static int tx_ipac_XXcx_nack(struct gsm_lchan *lchan, uint8_t cause,
int inc_ipport, uint8_t orig_msgtype)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
+ uint8_t msg_type = orig_msgtype + 2;
- /* FIXME: allocate new msgb and copy old over */
- LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "RSL Tx IPAC_BIND_NACK\n");
+ LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "RSL Tx %s\n", rsl_ipac_msg_name(msg_type));
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
if (!msg)
@@ -1952,7 +2944,7 @@ static int tx_ipac_XXcx_nack(struct gsm_lchan *lchan, uint8_t cause,
msgb_tlv_put(msg, RSL_IE_CAUSE, 1, &cause);
/* push the header in front */
- rsl_ipa_push_hdr(msg, orig_msgtype + 2, chan_nr);
+ rsl_ipa_push_hdr(msg, msg_type, chan_nr);
msg->trx = lchan->ts->trx;
return abis_bts_rsl_sendmsg(msg);
@@ -1960,7 +2952,7 @@ static int tx_ipac_XXcx_nack(struct gsm_lchan *lchan, uint8_t cause,
static char *get_rsl_local_ip(struct gsm_bts_trx *trx)
{
- struct e1inp_ts *ts = trx->rsl_link->ts;
+ struct e1inp_ts *ts = trx->bb_transc.rsl.link->ts;
struct sockaddr_storage ss;
socklen_t sa_len = sizeof(ss);
static char hostbuf[256];
@@ -1980,42 +2972,21 @@ static char *get_rsl_local_ip(struct gsm_bts_trx *trx)
return hostbuf;
}
-static int bind_rtp(struct gsm_bts *bts, struct osmo_rtp_socket *rs, const char *ip)
-{
- int rc;
- unsigned int i;
- unsigned int tries;
-
- tries = (bts->rtp_port_range_end - bts->rtp_port_range_start) / 2;
- for (i = 0; i < tries; i++) {
-
- if (bts->rtp_port_range_next >= bts->rtp_port_range_end)
- bts->rtp_port_range_next = bts->rtp_port_range_start;
-
- rc = osmo_rtp_socket_bind(rs, ip, bts->rtp_port_range_next);
-
- bts->rtp_port_range_next += 2;
-
- if (rc == 0)
- return 0;
- }
-
- return -1;
-}
-
static int rsl_rx_ipac_XXcx(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
struct gsm_lchan *lchan = msg->lchan;
struct gsm_bts *bts = lchan->ts->trx->bts;
- const uint8_t *payload_type, *speech_mode, *payload_type2;
+ const uint8_t *payload_type, *speech_mode, *payload_type2, *csd_fmt;
+ const uint8_t *osmux_cid = NULL;
uint32_t connect_ip = 0;
uint16_t connect_port = 0;
- int rc, inc_ip_port = 0, port;
+ int rc, inc_ip_port = 0;
char *name;
struct in_addr ia;
- struct in_addr addr;
+ enum rsl_ipac_rtp_csd_format_d csd_fmt_d;
+ enum rsl_ipac_rtp_csd_format_ir csd_fmt_ir;
if (dch->c.msg_type == RSL_MT_IPAC_CRCX)
name = "CRCX";
@@ -2027,22 +2998,22 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
return tx_ipac_XXcx_nack(lchan, 0x52,
0, dch->c.msg_type);
- rc = rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
- if (rc < 0)
- return tx_ipac_XXcx_nack(lchan, RSL_ERR_MAND_IE_ERROR,
- 0, dch->c.msg_type);
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_PROTO, 0, dch->c.msg_type);
+ }
LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "IPAC_%s: ", name);
if (TLVP_PRES_LEN(&tp, RSL_IE_IPAC_REMOTE_IP, 4)) {
+ struct in_addr addr;
connect_ip = tlvp_val32_unal(&tp, RSL_IE_IPAC_REMOTE_IP);
addr.s_addr = connect_ip;
LOGPC(DRSL, LOGL_DEBUG, "connect_ip=%s ", inet_ntoa(addr));
}
if (TLVP_PRES_LEN(&tp, RSL_IE_IPAC_REMOTE_PORT, 2)) {
- connect_port = tlvp_val16_unal(&tp, RSL_IE_IPAC_REMOTE_PORT);
- LOGPC(DRSL, LOGL_DEBUG, "connect_port=%u ",
- ntohs(connect_port));
+ connect_port = tlvp_val16be(&tp, RSL_IE_IPAC_REMOTE_PORT);
+ LOGPC(DRSL, LOGL_DEBUG, "connect_port=%u ", connect_port);
}
speech_mode = TLVP_VAL(&tp, RSL_IE_IPAC_SPEECH_MODE);
@@ -2056,6 +3027,14 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
LOGPC(DRSL, LOGL_DEBUG, "\n");
payload_type2 = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD2);
+ if (payload_type2)
+ LOGPC(DRSL, LOGL_DEBUG, "payload_type2=%u ", *payload_type2);
+
+ /* this IE has TLV format when TV would have been good enough */
+ if (TLVP_PRES_LEN(&tp, RSL_IE_OSMO_OSMUX_CID, 1))
+ osmux_cid = TLVP_VAL(&tp, RSL_IE_OSMO_OSMUX_CID);
+ if (osmux_cid)
+ LOGPC(DRSL, LOGL_DEBUG, "osmux_cid=%u ", *osmux_cid);
if (dch->c.msg_type == RSL_MT_IPAC_CRCX && connect_ip && connect_port)
inc_ip_port = 1;
@@ -2067,116 +3046,107 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
inc_ip_port, dch->c.msg_type);
}
- if (dch->c.msg_type == RSL_MT_IPAC_CRCX) {
- char cname[32];
- char *ipstr = NULL;
- if (lchan->abis_ip.rtp_socket) {
- LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC CRCX, "
- "but we already have socket!\n");
- return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
- inc_ip_port, dch->c.msg_type);
+ if ((csd_fmt = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_CSD_FMT))) {
+ csd_fmt_d = *csd_fmt & 0xf;
+ csd_fmt_ir = *csd_fmt >> 4;
+ LOGPC(DRSL, LOGL_DEBUG, "csd_fmt_d=%d csd_fmt_ir=%d ", csd_fmt_d, csd_fmt_ir);
+ if (csd_fmt_d != RSL_IPAC_RTP_CSD_TRAU_BTS) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC %s, csd_fmt_d=%d is not supported\n",
+ name, csd_fmt_d);
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_SERV_OPT_UNIMPL, inc_ip_port, dch->c.msg_type);
}
- /* FIXME: select default value depending on speech_mode */
- //if (!payload_type)
- lchan->tch.last_fn = LCHAN_FN_DUMMY;
- lchan->abis_ip.rtp_socket = osmo_rtp_socket_create(lchan->ts->trx,
- OSMO_RTP_F_POLL);
- if (!lchan->abis_ip.rtp_socket) {
- LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC Failed to create RTP/RTCP sockets\n");
- oml_tx_failure_event_rep(&lchan->ts->trx->mo,
- NM_SEVER_MINOR, OSMO_EVT_CRIT_RTP_TOUT,
- "%s IPAC Failed to create RTP/RTCP sockets",
- gsm_lchan_name(lchan));
+ }
+
+ if (!osmux_cid) { /* Regular RTP */
+ if (bts->osmux.use == OSMUX_USAGE_ONLY) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC XXcx without Osmux CID"
+ "goes against configured Osmux policy 'only'\n");
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
- rc = osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket,
- bts->rtp_jitter_adaptive ?
- OSMO_RTP_P_JIT_ADAP :
- OSMO_RTP_P_JITBUF,
- bts->rtp_jitter_buf_ms);
- if (rc < 0)
- LOGPLCHAN(lchan, DRTP, LOGL_ERROR,
- "IPAC Failed to set RTP socket parameters: %s\n", strerror(-rc));
- else
- LOGPLCHAN(lchan, DRTP, LOGL_INFO, "IPAC set RTP socket parameters: %d\n", rc);
- lchan->abis_ip.rtp_socket->priv = lchan;
- lchan->abis_ip.rtp_socket->rx_cb = &l1sap_rtp_rx_cb;
-
- if (connect_ip && connect_port) {
- /* if CRCX specifies a remote IP, we can bind()
- * here to 0.0.0.0 and wait for the connect()
- * below, after which the kernel will have
- * selected the local IP address. */
- ipstr = "0.0.0.0";
- } else {
- /* if CRCX does not specify a remote IP, we will
- * not do any connect() below, and thus the
- * local socket will remain bound to 0.0.0.0 -
- * which however we cannot legitimately report
- * back to the BSC in the CRCX_ACK */
- ipstr = get_rsl_local_ip(lchan->ts->trx);
+
+ if (dch->c.msg_type == RSL_MT_IPAC_CRCX) { /* CRCX */
+ char *ipstr = NULL;
+ if (connect_ip && connect_port) {
+ /* if CRCX specifies a remote IP, we can bind()
+ * here to 0.0.0.0 and wait for the connect()
+ * below, after which the kernel will have
+ * selected the local IP address. */
+ ipstr = "0.0.0.0";
+ } else {
+ /* if CRCX does not specify a remote IP, we will
+ * not do any connect() below, and thus the
+ * local socket will remain bound to 0.0.0.0 -
+ * which however we cannot legitimately report
+ * back to the BSC in the CRCX_ACK */
+ ipstr = get_rsl_local_ip(lchan->ts->trx);
+ }
+ rc = lchan_rtp_socket_create(lchan, ipstr);
+ if (rc < 0)
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
+ inc_ip_port, dch->c.msg_type);
+ } else { /* MDCX */
+ if (!lchan->abis_ip.rtp_socket) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC MDCX, "
+ "but we have no RTP socket!\n");
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
+ inc_ip_port, dch->c.msg_type);
+ }
}
- rc = bind_rtp(bts, lchan->abis_ip.rtp_socket, ipstr);
+
+ /* Special rule: If connect_ip == 0.0.0.0, use RSL IP
+ * address */
+ if (connect_ip == 0) {
+ struct e1inp_sign_link *sign_link =
+ lchan->ts->trx->bb_transc.rsl.link;
+
+ ia.s_addr = htonl(get_signlink_remote_ip(sign_link));
+ } else
+ ia.s_addr = connect_ip;
+ rc = lchan_rtp_socket_connect(lchan, &ia, connect_port);
if (rc < 0) {
- LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC Failed to bind RTP/RTCP sockets\n");
- oml_tx_failure_event_rep(&lchan->ts->trx->mo,
- NM_SEVER_MINOR, OSMO_EVT_CRIT_RTP_TOUT,
- "%s IPAC Failed to bind RTP/RTCP sockets",
- gsm_lchan_name(lchan));
- osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- msgb_queue_flush(&lchan->dl_tch_queue);
+ lchan_rtp_socket_free(lchan);
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
- /* Ensure RTCP SDES contains some useful information */
- snprintf(cname, sizeof(cname), "bts@%s", ipstr);
- osmo_rtp_set_source_desc(lchan->abis_ip.rtp_socket, cname,
- gsm_lchan_name(lchan), NULL, NULL,
- gsm_trx_unit_id(lchan->ts->trx),
- "OsmoBTS-" PACKAGE_VERSION, NULL);
- /* FIXME: multiplex connection, BSC proxy */
- } else {
- /* MDCX */
- if (!lchan->abis_ip.rtp_socket) {
- LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC MDCX, "
- "but we have no RTP socket!\n");
+
+ } else { /* Osmux */
+ if (bts->osmux.use == OSMUX_USAGE_OFF) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC XXcx with Osmux CID"
+ "goes against configured Osmux policy 'off'\n");
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
- }
-
- /* Special rule: If connect_ip == 0.0.0.0, use RSL IP
- * address */
- if (connect_ip == 0) {
- struct e1inp_sign_link *sign_link =
- lchan->ts->trx->rsl_link;
+ if (dch->c.msg_type == RSL_MT_IPAC_CRCX) { /* CRCX */
+ rc = lchan_osmux_init(lchan, payload_type ? *payload_type : 0);
+ if (rc < 0)
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
+ inc_ip_port, dch->c.msg_type);
+ } else { /* MDCX */
+ if (!lchan->abis_ip.osmux.use) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC MDCX with Osmux CID, "
+ "CRCX was configured as RTP!\n");
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
+ inc_ip_port, dch->c.msg_type);
+ }
+ }
- ia.s_addr = htonl(get_signlink_remote_ip(sign_link));
- } else
- ia.s_addr = connect_ip;
- rc = osmo_rtp_socket_connect(lchan->abis_ip.rtp_socket,
- inet_ntoa(ia), ntohs(connect_port));
- if (rc < 0) {
- LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "Failed to connect RTP/RTCP sockets\n");
- osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- msgb_queue_flush(&lchan->dl_tch_queue);
- return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
- inc_ip_port, dch->c.msg_type);
+ if (connect_ip != 0)
+ lchan->abis_ip.connect_ip = connect_ip;
+ if (connect_port != 0)
+ lchan->abis_ip.connect_port = connect_port;
+ lchan->abis_ip.osmux.remote_cid = *osmux_cid;
+ if (lchan->abis_ip.connect_ip && lchan->abis_ip.connect_port &&
+ !lchan_osmux_connected(lchan)) {
+ rc = lchan_osmux_connect(lchan);
+ if (rc < 0) {
+ lchan_osmux_release(lchan);
+ return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
+ inc_ip_port, dch->c.msg_type);
+ }
+ }
}
- /* save IP address and port number */
- lchan->abis_ip.connect_ip = ntohl(ia.s_addr);
- lchan->abis_ip.connect_port = ntohs(connect_port);
-
- rc = osmo_rtp_get_bound_ip_port(lchan->abis_ip.rtp_socket,
- &lchan->abis_ip.bound_ip,
- &port);
- if (rc < 0)
- LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "IPAC cannot obtain locally bound IP/port: %d\n", rc);
- lchan->abis_ip.bound_port = port;
/* Everything has succeeded, we can store new values in lchan */
if (payload_type) {
@@ -2206,9 +3176,10 @@ static int rsl_rx_ipac_dlcx(struct msgb *msg)
struct gsm_lchan *lchan = msg->lchan;
int rc, inc_conn_id = 0;
- rc = rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
- if (rc < 0)
- return rsl_tx_ipac_dlcx_nack(lchan, 0, RSL_ERR_MAND_IE_ERROR);
+ if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
+ return rsl_tx_ipac_dlcx_nack(lchan, 0, RSL_ERR_PROTO);
+ }
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_CONN_ID))
inc_conn_id = 1;
@@ -2217,9 +3188,7 @@ static int rsl_rx_ipac_dlcx(struct msgb *msg)
if (lchan->abis_ip.rtp_socket) {
osmo_rtp_socket_log_stats(lchan->abis_ip.rtp_socket, DRTP, LOGL_INFO,
"Closing RTP socket on DLCX ");
- osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- msgb_queue_flush(&lchan->dl_tch_queue);
+ lchan_rtp_socket_free(lchan);
}
return rc;
}
@@ -2233,7 +3202,7 @@ static int rsl_rx_ipac_dlcx(struct msgb *msg)
static int rsl_tx_dyn_pdch_ack(struct gsm_lchan *lchan, bool pdch_act)
{
struct gsm_time *gtime = get_time(lchan->ts->trx->bts);
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
struct msgb *msg;
uint8_t ie[2];
@@ -2262,7 +3231,7 @@ static int rsl_tx_dyn_pdch_nack(struct gsm_lchan *lchan, bool pdch_act,
uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Tx PDCH %s NACK (cause = 0x%02x)\n",
pdch_act ? "ACT" : "DEACT", cause);
@@ -2371,7 +3340,6 @@ static void rsl_rx_dyn_pdch(struct msgb *msg, bool pdch_act)
if (pdch_act) {
/* Clear TCH state. Only first lchan matters for PDCH */
clear_lchan_for_pdch_activ(ts->lchan);
-
/* First, disconnect the TCH channel, to connect PDTCH later */
rc = bts_model_ts_disconnect(ts);
} else {
@@ -2400,14 +3368,12 @@ static void ipacc_dyn_pdch_ts_disconnected(struct gsm_bts_trx_ts *ts)
enum gsm_phys_chan_config as_pchan;
if (ts->flags & TS_F_PDCH_DEACT_PENDING) {
- LOGP(DRSL, LOGL_DEBUG,
- "%s PDCH DEACT operation: channel disconnected, will reconnect as TCH\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG,
+ "PDCH DEACT operation: channel disconnected, will reconnect as TCH\n");
as_pchan = GSM_PCHAN_TCH_F;
} else if (ts->flags & TS_F_PDCH_ACT_PENDING) {
- LOGP(DRSL, LOGL_DEBUG,
- "%s PDCH ACT operation: channel disconnected, will reconnect as PDTCH\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG,
+ "PDCH ACT operation: channel disconnected, will reconnect as PDTCH\n");
as_pchan = GSM_PCHAN_PDCH;
} else
/* No reconnect pending. */
@@ -2434,6 +3400,7 @@ static void osmo_dyn_ts_disconnected(struct gsm_bts_trx_ts *ts)
switch (ts->dyn.pchan_want) {
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
+ case GSM_PCHAN_SDCCH8_SACCH8C:
case GSM_PCHAN_PDCH:
break;
default:
@@ -2457,7 +3424,7 @@ void cb_ts_disconnected(struct gsm_bts_trx_ts *ts)
switch (ts->pchan) {
case GSM_PCHAN_TCH_F_PDCH:
return ipacc_dyn_pdch_ts_disconnected(ts);
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return osmo_dyn_ts_disconnected(ts);
default:
return;
@@ -2467,39 +3434,31 @@ void cb_ts_disconnected(struct gsm_bts_trx_ts *ts)
static void ipacc_dyn_pdch_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
{
if (rc) {
- LOGP(DRSL, LOGL_NOTICE, "%s PDCH ACT IPA operation failed (%d) in bts model\n",
- gsm_lchan_name(ts->lchan), rc);
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_NOTICE, "PDCH ACT IPA operation failed (%d) in bts model\n", rc);
ipacc_dyn_pdch_complete(ts, rc);
return;
}
if (ts->flags & TS_F_PDCH_DEACT_PENDING) {
- if (ts->lchan[0].type != GSM_LCHAN_TCH_F)
- LOGP(DRSL, LOGL_ERROR, "%s PDCH DEACT error:"
- " timeslot connected, so expecting"
- " lchan type TCH/F, but is %s\n",
- gsm_lchan_name(ts->lchan),
- gsm_lchant_name(ts->lchan[0].type));
+ if (ts->lchan[0].type != GSM_LCHAN_TCH_F) {
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR, "PDCH DEACT error: timeslot connected, so "
+ "expecting lchan type TCH/F, but is %s\n", gsm_lchant_name(ts->lchan[0].type));
+ }
- LOGP(DRSL, LOGL_DEBUG, "%s PDCH DEACT operation:"
- " timeslot connected as TCH/F\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "PDCH DEACT operation: timeslot connected as TCH/F\n");
/* During PDCH DEACT, we're done right after the TCH/F came
* back up. */
ipacc_dyn_pdch_complete(ts, 0);
} else if (ts->flags & TS_F_PDCH_ACT_PENDING) {
- if (ts->lchan[0].type != GSM_LCHAN_PDTCH)
- LOGP(DRSL, LOGL_ERROR, "%s PDCH ACT error:"
- " timeslot connected, so expecting"
- " lchan type PDTCH, but is %s\n",
- gsm_lchan_name(ts->lchan),
+ if (ts->lchan[0].type != GSM_LCHAN_PDTCH) {
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR, "PDCH ACT error: timeslot connected, "
+ "so expecting lchan type PDTCH, but is %s\n",
gsm_lchant_name(ts->lchan[0].type));
+ }
- LOGP(DRSL, LOGL_DEBUG, "%s PDCH ACT operation:"
- " timeslot connected as PDTCH\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "PDCH ACT operation: timeslot connected as PDTCH\n");
/* The PDTCH is connected, now tell the PCU about it. Except
* when the PCU is not connected (yet), then there's nothing
@@ -2522,30 +3481,31 @@ static void ipacc_dyn_pdch_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
static void osmo_dyn_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
{
- struct msgb *msg = ts->dyn.pending_chan_activ;
- ts->dyn.pending_chan_activ = NULL;
+ unsigned int ln;
if (rc) {
- LOGP(DRSL, LOGL_NOTICE, "%s PDCH ACT OSMO operation failed (%d) in bts model\n",
- gsm_lchan_name(ts->lchan), rc);
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_NOTICE, "PDCH ACT OSMO operation failed (%d) in bts model\n", rc);
ipacc_dyn_pdch_complete(ts, rc);
return;
}
- if (!msg) {
- LOGP(DRSL, LOGL_ERROR,
- "%s TS re-connected, but no chan activ msg pending\n",
- gsm_ts_and_pchan_name(ts));
- return;
- }
-
ts->dyn.pchan_is = ts->dyn.pchan_want;
DEBUGP(DRSL, "%s Connected\n", gsm_ts_and_pchan_name(ts));
- /* continue where we left off before re-connecting the TS. */
- rc = rsl_rx_chan_activ(msg);
- if (rc != 1)
- msgb_free(msg);
+ /* Handle postponed RSL CHANnel ACTIVation messages (if any) */
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+
+ if (lchan->pending_chan_activ == NULL)
+ continue;
+
+ struct msgb *msg = lchan->pending_chan_activ;
+ lchan->pending_chan_activ = NULL;
+
+ /* Continue where we left off before re-connecting the TS */
+ if (rsl_rx_chan_activ(msg) != 1)
+ msgb_free(msg);
+ }
}
void cb_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
@@ -2555,7 +3515,7 @@ void cb_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
switch (ts->pchan) {
case GSM_PCHAN_TCH_F_PDCH:
return ipacc_dyn_pdch_ts_connected(ts, rc);
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return osmo_dyn_ts_connected(ts, rc);
default:
return;
@@ -2569,10 +3529,10 @@ void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc)
pdch_act = ts->flags & TS_F_PDCH_ACT_PENDING;
- if ((ts->flags & TS_F_PDCH_PENDING_MASK) == TS_F_PDCH_PENDING_MASK)
- LOGP(DRSL, LOGL_ERROR,
- "%s Internal Error: both PDCH ACT and PDCH DEACT pending\n",
- gsm_lchan_name(ts->lchan));
+ if ((ts->flags & TS_F_PDCH_PENDING_MASK) == TS_F_PDCH_PENDING_MASK) {
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR,
+ "Internal Error: both PDCH ACT and PDCH DEACT pending\n");
+ }
ts->flags &= ~TS_F_PDCH_PENDING_MASK;
@@ -2588,9 +3548,8 @@ void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc)
ts->flags |= TS_F_PDCH_ACTIVE;
else
ts->flags &= ~TS_F_PDCH_ACTIVE;
- DEBUGP(DRSL, "%s %s switched to %s mode (ts->flags == %x)\n",
- gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan),
- pdch_act? "PDCH" : "TCH/F", ts->flags);
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "%s switched to %s mode (ts->flags == %x)\n",
+ gsm_pchan_name(ts->pchan), pdch_act ? "PDCH" : "TCH/F", ts->flags);
rc = rsl_tx_dyn_pdch_ack(ts->lchan, pdch_act);
if (rc)
@@ -2692,8 +3651,11 @@ static int rsl_rx_rll(struct gsm_bts_trx *trx, struct msgb *msg)
return -1;
}
- DEBUGP(DRLL, "%s Rx RLL %s Abis -> LAPDm\n", gsm_lchan_name(lchan),
- rsl_msg_name(rh->c.msg_type));
+ /* VGCS Uplink is released by MSC using REL-REQ. */
+ if (rh->c.msg_type == RSL_MT_REL_REQ)
+ vgcs_talker_reset(lchan, true);
+
+ LOGPLCHAN(lchan, DRLL, LOGL_DEBUG, "Rx RLL %s Abis -> LAPDm\n", rsl_msg_name(rh->c.msg_type));
/* make copy of RLL header, as the message will be free'd in case of erroneous return */
rh2 = *rh;
@@ -2788,15 +3750,15 @@ static int handle_gprs_susp_req(struct msgb *msg)
int rc;
if (!gh || msgb_l3len(msg) < sizeof(*gh)+sizeof(*gsr)) {
- LOGP(DRSL, LOGL_NOTICE, "%s Short GPRS SUSPEND REQ received, ignoring\n", gsm_lchan_name(msg->lchan));
+ LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "Short GPRS SUSPEND REQ received, ignoring\n");
+ msgb_free(msg);
return -EINVAL;
}
gsr = (struct gsm48_gprs_susp_req *) gh->data;
tlli = osmo_ntohl(gsr->tlli);
- LOGP(DRSL, LOGL_INFO, "%s Fwd GPRS SUSPEND REQ for TLLI=0x%08x to PCU\n",
- gsm_lchan_name(msg->lchan), tlli);
+ LOGPLCHAN(msg->lchan, DRSL, LOGL_INFO, "Fwd GPRS SUSPEND REQ for TLLI=0x%08x to PCU\n", tlli);
rc = pcu_tx_susp_req(msg->lchan, tlli, gsr->ra_id, gsr->cause);
msgb_free(msg);
@@ -2804,16 +3766,6 @@ static int handle_gprs_susp_req(struct msgb *msg)
return rc;
}
-static inline uint8_t ms_to2rsl(const struct gsm_lchan *lchan, const struct lapdm_entity *le)
-{
- return (lchan->ms_t_offs >= 0) ? lchan->ms_t_offs : (lchan->p_offs - le->ta);
-}
-
-static inline bool ms_to_valid(const struct gsm_lchan *lchan)
-{
- return (lchan->ms_t_offs >= 0) || (lchan->p_offs >= 0);
-}
-
struct osmo_bts_supp_meas_info {
int16_t toa256_mean;
int16_t toa256_min;
@@ -2821,12 +3773,12 @@ struct osmo_bts_supp_meas_info {
uint16_t toa256_std_dev;
} __attribute__((packed));
-/* 8.4.8 MEASUREMENT RESult */
-static int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, const struct lapdm_entity *le)
+/* Compose and send 8.4.8 MEASUREMENT RESult via RSL. (timing_offset=-1 -> not present) */
+int rsl_tx_meas_res(struct gsm_lchan *lchan, const uint8_t *l3, unsigned int l3_len, int timing_offset)
{
struct msgb *msg;
uint8_t meas_res[16];
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
int res_valid = lchan->meas.flags & LC_UL_M_F_RES_VALID;
struct gsm_bts *bts = lchan->ts->trx->bts;
@@ -2841,20 +3793,19 @@ static int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, con
return -ENOMEM;
LOGPLCHAN(lchan, DRSL, LOGL_DEBUG,
- "Send Meas RES: NUM:%u, RXLEV_FULL:%u, RXLEV_SUB:%u, RXQUAL_FULL:%u, RXQUAL_SUB:%u, MS_PWR:%u, UL_TA:%u, L3_LEN:%d, TimingOff:%u\n",
+ "Send Meas RES: NUM:%u, RXLEV_FULL:%u, RXLEV_SUB:%u, RXQUAL_FULL:%u, RXQUAL_SUB:%u, MS_PWR:%u, UL_TA:%u, L3_LEN:%u, TimingOff:%u\n",
lchan->meas.res_nr,
lchan->meas.ul_res.full.rx_lev,
lchan->meas.ul_res.sub.rx_lev,
lchan->meas.ul_res.full.rx_qual,
lchan->meas.ul_res.sub.rx_qual,
- lchan->meas.l1_info[0],
- lchan->meas.l1_info[1], l3_len, ms_to2rsl(lchan, le) - MEAS_MAX_TIMING_ADVANCE);
+ lchan->meas.l1_info.ms_pwr,
+ lchan->meas.l1_info.ta, l3_len, timing_offset - MEAS_MAX_TIMING_ADVANCE);
- msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, lchan->meas.res_nr++);
+ msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, lchan->meas.res_nr);
size_t ie_len = gsm0858_rsl_ul_meas_enc(&lchan->meas.ul_res,
lchan->tch.dtx.dl_active,
meas_res);
- lchan->tch.dtx.dl_active = false;
if (ie_len >= 3) {
if (bts->supp_meas_toa256 && lchan->meas.flags & LC_UL_M_F_OSMO_EXT_VALID) {
struct osmo_bts_supp_meas_info *smi;
@@ -2867,26 +3818,23 @@ static int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, con
* to know the total propagation time between MS and BTS, we need to add
* the actual TA value applied by the MS plus the respective toa256 value in
* 1/256 symbol periods. */
- int16_t ta256 = lchan_get_ta(lchan) * 256;
+ int16_t ta256 = lchan->meas.l1_info.ta * 256;
smi->toa256_mean = htons(ta256 + lchan->meas.ms_toa256);
smi->toa256_min = htons(ta256 + lchan->meas.ext.toa256_min);
smi->toa256_max = htons(ta256 + lchan->meas.ext.toa256_max);
smi->toa256_std_dev = htons(lchan->meas.ext.toa256_std_dev);
- lchan->meas.flags &= ~LC_UL_M_F_OSMO_EXT_VALID;
}
msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, ie_len, meas_res);
- lchan->meas.flags &= ~LC_UL_M_F_RES_VALID;
}
- msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->meas.bts_tx_pwr);
+ msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_ctrl.current / 2);
if (lchan->meas.flags & LC_UL_M_F_L1_VALID) {
- msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, 2, lchan->meas.l1_info);
- lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;
+ msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, sizeof(lchan->meas.l1_info), (uint8_t*)&lchan->meas.l1_info);
}
- msgb_tl16v_put(msg, RSL_IE_L3_INFO, l3_len, l3);
- if (ms_to_valid(lchan)) {
- msgb_tv_put(msg, RSL_IE_MS_TIMING_OFFSET, ms_to2rsl(lchan, le));
- lchan->ms_t_offs = -1;
- lchan->p_offs = -1;
+
+ if (l3 && l3_len > 0) {
+ msgb_tl16v_put(msg, RSL_IE_L3_INFO, l3_len, l3);
+ if (timing_offset != -1)
+ msgb_tv_put(msg, RSL_IE_MS_TIMING_OFFSET, timing_offset);
}
rsl_dch_push_hdr(msg, RSL_MT_MEAS_RES, chan_nr);
@@ -2914,22 +3862,42 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
msg->trx = lchan->ts->trx;
msg->lchan = lchan;
- /* check if this is a measurement report from SACCH which needs special
- * processing before forwarding */
- if (rslms_is_meas_rep(msg)) {
- int rc;
+ /* If DL estabishment on main signaling link and SAPI 0 with L3 info is expected. */
+ if (lchan->l3_info_estab && rh->msg_type == RSL_MT_EST_IND) {
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ if ((rllh->link_id & 0xc7) == 0) {
+ /* Reject initial establishment without L3 info. */
+ if (msgb_l2len(msg) == sizeof(struct abis_rsl_rll_hdr)) {
+ LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "RLL EST IND without contention resolution.\n");
+ /* Release normally, re-use the msgb. */
+ rh->msg_type = RSL_MT_REL_REQ;
+ msgb_tv_put(msg, RSL_IE_RELEASE_MODE, RSL_REL_NORMAL);
+ return rsl_rx_rll(lchan->ts->trx, msg);
+ }
+ /* Re-estabishment without contention resoltuion is allowed. */
+ lchan->l3_info_estab = false;
+ }
+ }
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Handing RLL msg %s from LAPDm to MEAS REP\n",
+ /* If this is a Measurement Report, then we simply ignore it,
+ * because it has already been processed in l1sap_ph_data_ind(). */
+ if (rslms_is_meas_rep(msg)) {
+ msgb_free(msg);
+ return 0;
+ } else if (rslms_is_gprs_susp_req(msg)) {
+ return handle_gprs_susp_req(msg);
+ } else {
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Fwd RLL msg %s from LAPDm to A-bis\n",
rsl_msg_name(rh->msg_type));
/* REL_IND handling */
- if (rh->msg_type == RSL_MT_REL_IND &&
- (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)) {
+ if (rh->msg_type == RSL_MT_REL_IND && lchan_is_tch(lchan)) {
+ vgcs_talker_reset(lchan, true);
LOGPLCHAN(lchan, DRSL, LOGL_INFO,
"Scheduling %s to L3 in next associated TCH-RTS.ind\n",
rsl_msg_name(rh->msg_type));
- if(lchan->pending_rel_ind_msg) {
+ if (lchan->pending_rel_ind_msg) {
LOGPLCHAN(lchan, DRSL, LOGL_INFO,
"Dropping pending release indication message\n");
msgb_free(lchan->pending_rel_ind_msg);
@@ -2939,15 +3907,6 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
return 0;
}
- rc = rsl_tx_meas_res(lchan, msgb_l3(msg), msgb_l3len(msg), le);
- msgb_free(msg);
- return rc;
- } else if (rslms_is_gprs_susp_req(msg)) {
- return handle_gprs_susp_req(msg);
- } else {
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Fwd RLL msg %s from LAPDm to A-bis\n",
- rsl_msg_name(rh->msg_type));
-
return abis_bts_rsl_sendmsg(msg);
}
}
@@ -2994,8 +3953,10 @@ static int rsl_rx_cchan(struct gsm_bts_trx *trx, struct msgb *msg)
case RSL_MT_SMS_BC_CMD:
ret = rsl_rx_sms_bcast_cmd(trx, msg);
break;
- case RSL_MT_SMS_BC_REQ:
case RSL_MT_NOT_CMD:
+ ret = rsl_rx_notification_cmd(trx, msg);
+ break;
+ case RSL_MT_SMS_BC_REQ:
LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "unimplemented RSL cchan msg_type %s\n",
rsl_msg_name(cch->c.msg_type));
rsl_tx_error_report(trx, RSL_ERR_MSG_TYPE, &cch->chan_nr, NULL, msg);
@@ -3003,6 +3964,10 @@ static int rsl_rx_cchan(struct gsm_bts_trx *trx, struct msgb *msg)
case RSL_MT_OSMO_ETWS_CMD:
ret = rsl_rx_osmo_etws_cmd(trx, msg);
break;
+ /* Osmocom specific extension for BCCH carrier power reduction */
+ case RSL_MT_BS_POWER_CONTROL:
+ ret = rsl_rx_bs_pwr_ctrl(msg);
+ break;
default:
LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "undefined RSL cchan msg_type 0x%02x\n",
cch->c.msg_type);
@@ -3113,6 +4078,9 @@ static int rsl_rx_trx(struct gsm_bts_trx *trx, struct msgb *msg)
case RSL_MT_SACCH_FILL:
ret = rsl_rx_sacch_fill(trx, msg);
break;
+ case RSL_MT_IPAC_MEAS_PREPROC_DFT:
+ ret = rsl_rx_meas_preproc_dft(trx, msg);
+ break;
default:
LOGP(DRSL, LOGL_NOTICE, "undefined RSL TRX msg_type 0x%02x\n",
th->msg_type);
@@ -3171,14 +4139,6 @@ static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg)
return ret;
}
-int lchan_deactivate(struct gsm_lchan *lchan)
-{
- OSMO_ASSERT(lchan);
-
- lchan->ciph_state = 0;
- return bts_model_lchan_deactivate(lchan);
-}
-
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh;
diff --git a/src/common/rtp_input_preen.c b/src/common/rtp_input_preen.c
new file mode 100644
index 00000000..5729229f
--- /dev/null
+++ b/src/common/rtp_input_preen.c
@@ -0,0 +1,151 @@
+/*
+ * This module implements a helper function for the RTP input path:
+ * validates incoming RTP payloads, makes the accept-or-drop decision,
+ * and for some codecs signals additional required actions such as
+ * dropping one header octet.
+ *
+ * Author: Mychaela N. Falconia <falcon@freecalypso.org>, 2023 - however,
+ * Mother Mychaela's contributions are NOT subject to copyright.
+ * No rights reserved, all rights relinquished.
+ *
+ * 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 Affero 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 <stdbool.h>
+#include <stdint.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/codec/codec.h>
+
+#include <osmo-bts/lchan.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/rtp_input_preen.h>
+
+static bool amr_is_octet_aligned(const uint8_t *rtp_pl, unsigned rtp_pl_len)
+{
+ /*
+ * Logic: If 1st bit padding is not zero, packet is either:
+ * - bandwidth-efficient AMR payload.
+ * - malformed packet.
+ * However, Bandwidth-efficient AMR 4,75 frame last in payload(F=0, FT=0)
+ * with 4th,5ht,6th AMR payload to 0 matches padding==0.
+ * Furthermore, both AMR 4,75 bw-efficient and octet alignment are 14 bytes long (AMR 4,75 encodes 95b):
+ * bw-efficient: 95b, + 4b hdr + 6b ToC = 105b, + padding = 112b = 14B.
+ * octet-aligned: 1B hdr + 1B ToC + 95b = 111b, + padding = 112b = 14B.
+ * We cannot use other fields to match since they are inside the AMR
+ * payload bits which are unknown.
+ * As a result, this function may return false positive (true) for some AMR
+ * 4,75 AMR frames, but given the length, CMR and FT read is the same as a
+ * consequence, the damage in here is harmless other than being unable to
+ * decode the audio at the other side.
+ */
+ #define AMR_PADDING1(rtp_pl) (rtp_pl[0] & 0x0f)
+ #define AMR_PADDING2(rtp_pl) (rtp_pl[1] & 0x03)
+
+ if (rtp_pl_len < 2 || AMR_PADDING1(rtp_pl) || AMR_PADDING2(rtp_pl))
+ return false;
+
+ return true;
+}
+
+static enum pl_input_decision
+input_preen_fr(const uint8_t *rtp_pl, unsigned rtp_pl_len)
+{
+ if (rtp_pl_len != GSM_FR_BYTES)
+ return PL_DECISION_DROP;
+ if ((rtp_pl[0] & 0xF0) != 0xD0)
+ return PL_DECISION_DROP;
+ return PL_DECISION_ACCEPT;
+}
+
+static enum pl_input_decision
+input_preen_efr(const uint8_t *rtp_pl, unsigned rtp_pl_len)
+{
+ if (rtp_pl_len != GSM_EFR_BYTES)
+ return PL_DECISION_DROP;
+ if ((rtp_pl[0] & 0xF0) != 0xC0)
+ return PL_DECISION_DROP;
+ return PL_DECISION_ACCEPT;
+}
+
+static enum pl_input_decision
+input_preen_hr(const uint8_t *rtp_pl, unsigned rtp_pl_len,
+ bool *rfc5993_sid_flag)
+{
+ switch (rtp_pl_len) {
+ case GSM_HR_BYTES:
+ /* RTP input matches our internal format - we are good */
+ return PL_DECISION_ACCEPT;
+ case GSM_HR_BYTES_RTP_RFC5993:
+ /* Validate ToC octet: for payload of this length to be valid,
+ * the F bit must be 0 and the FT field must be either 0 (good
+ * speech) or 2 (good SID). */
+ switch (rtp_pl[0] & 0xF0) {
+ case 0x00:
+ break;
+ case 0x20:
+ *rfc5993_sid_flag = true;
+ break;
+ default:
+ /* invalid payload */
+ return PL_DECISION_DROP;
+ }
+ /* Strip ToC octet, leaving only "pure" TS 101 318 payload. */
+ return PL_DECISION_STRIP_HDR_OCTET;
+ default:
+ /* invalid payload */
+ return PL_DECISION_DROP;
+ }
+}
+
+enum pl_input_decision
+rtp_payload_input_preen(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
+ unsigned rtp_pl_len, bool *rfc5993_sid_flag)
+{
+ /* If rtp continuous-streaming is enabled, we shall emit RTP packets
+ * with zero-length payloads as BFI markers. In a TrFO scenario such
+ * RTP packets sent by call leg A will be received by call leg B,
+ * hence we need to handle them gracefully. For the purposes of a BTS
+ * that runs on its own TDMA timing and does not need timing ticks from
+ * an incoming RTP stream, the correct action upon receiving such
+ * timing-tick-only RTP packets should be the same as when receiving
+ * no RTP packet at all. The simplest way to produce that behavior
+ * is to treat zero-length RTP payloads as invalid. */
+ if (rtp_pl_len == 0)
+ return PL_DECISION_DROP;
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (lchan->type == GSM_LCHAN_TCH_F)
+ return input_preen_fr(rtp_pl, rtp_pl_len);
+ else
+ return input_preen_hr(rtp_pl, rtp_pl_len, rfc5993_sid_flag);
+ case GSM48_CMODE_SPEECH_EFR:
+ return input_preen_efr(rtp_pl, rtp_pl_len);
+ case GSM48_CMODE_SPEECH_AMR:
+ /* Avoid forwarding bw-efficient AMR to lower layers,
+ * most bts models don't support it. */
+ if (!amr_is_octet_aligned(rtp_pl, rtp_pl_len)) {
+ LOGPLCHAN(lchan, DL1P, LOGL_NOTICE,
+ "RTP->L1: Dropping unexpected AMR encoding (bw-efficient?) %s\n",
+ osmo_hexdump(rtp_pl, rtp_pl_len));
+ return PL_DECISION_DROP;
+ }
+ return PL_DECISION_ACCEPT;
+ default:
+ return PL_DECISION_ACCEPT;
+ }
+}
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index 95a1b00e..a449d167 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -3,6 +3,7 @@
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
* (C) 2015 by Harald Welte <laforge@gnumonks.org>
+ * Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@@ -14,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -29,8 +30,12 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stats.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/gsm0502.h>
#include <osmocom/gsm/a5.h>
#include <osmo-bts/gsm_data.h>
@@ -39,17 +44,16 @@
#include <osmo-bts/l1sap.h>
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>
+#include <osmo-bts/bts.h>
extern void *tall_bts_ctx;
-static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan);
-static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan);
-static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan);
+static int rts_data_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
+static int rts_tchf_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
+static int rts_tchh_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
+
/*! \brief Dummy Burst (TS 05.02 Chapter 5.2.6) */
-static const ubit_t dummy_burst[GSM_BURST_LEN] = {
+const ubit_t _sched_dummy_burst[GSM_BURST_LEN] = {
0,0,0,
1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,1,1,0,
0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,0,
@@ -59,28 +63,51 @@ static const ubit_t dummy_burst[GSM_BURST_LEN] = {
0,0,0,
};
-/*! \brief FCCH Burst (TS 05.02 Chapter 5.2.4) */
-const ubit_t _sched_fcch_burst[GSM_BURST_LEN] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-};
-
-/*! \brief Training Sequences (TS 05.02 Chapter 5.2.3) */
-const ubit_t _sched_tsc[8][26] = {
- { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1, },
- { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1, },
- { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0, },
- { 0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,0, },
- { 0,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1, },
- { 0,1,0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,0, },
- { 1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,1,1,1, },
- { 1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0, },
+/*! Training Sequences for Normal Burst (see 3GPP TS 45.002, section 5.2.3) */
+const ubit_t _sched_train_seq_gmsk_nb[4][8][26] = {
+ { /* TSC set 1, table 5.2.3a */
+ { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1 },
+ { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1 },
+ { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0 },
+ { 0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,0 },
+ { 0,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1 },
+ { 0,1,0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,0 },
+ { 1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,1,1,1 },
+ { 1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0 },
+ },
+ { /* TSC set 2, table 5.2.3b */
+ { 0,1,1,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,1 },
+ { 0,1,0,1,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,1 },
+ { 0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,1,0,0 },
+ { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0 },
+ { 0,1,1,1,0,1,0,0,1,1,1,1,0,1,0,0,1,1,1,0,1,1,1,1,1,0 },
+ { 0,1,0,0,0,0,0,1,0,0,1,1,0,1,0,1,0,0,1,1,1,1,0,0,1,1 },
+ { 0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,0,1 },
+ { 0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,1,0,1,0,0,1 },
+ },
+ { /* TSC set 3, table 5.2.3c */
+ { 1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,0,0,0,1,0 },
+ { 0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0 },
+ { 1,1,0,0,1,0,0,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,0 },
+ { 0,0,1,1,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0 },
+ { 0,0,0,1,1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,1,0 },
+ { 1,1,0,0,1,1,1,1,0,1,0,1,0,1,1,1,1,0,0,1,0,0,0,0,0,0 },
+ { 1,0,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,0,0,0 },
+ { 1,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,0,0,1,0,0 },
+ },
+ { /* TSC set 4, table 5.2.3d */
+ { 1,1,0,0,1,1,1,0,1,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0 },
+ { 0,1,1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,0,0 },
+ { 1,1,1,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,1,1,1,0,0,0,0,0 },
+ { 0,1,1,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0 },
+ { 1,1,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0 },
+ { 1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0 },
+ { 0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0 },
+ { 0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,1,1,0 },
+ },
};
-const ubit_t _sched_egprs_tsc[8][78] = {
+const ubit_t _sched_train_seq_8psk_nb[8][78] = {
{ 1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,
1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1, },
@@ -108,7 +135,7 @@ const ubit_t _sched_egprs_tsc[8][78] = {
};
/*! \brief SCH training sequence (TS 05.02 Chapter 5.2.5) */
-const ubit_t _sched_sch_train[64] = {
+const ubit_t _sched_train_seq_gmsk_sb[64] = {
1,0,1,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,
0,0,1,0,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,1,1,0,1,1,
};
@@ -118,18 +145,12 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
[TRXC_IDLE] = {
.name = "IDLE",
.desc = "Idle channel",
-
- /* On C0, BTS needs to ensure discontinuous burst transmission.
- * Therefore we need to send dummy bursts on IDLE slots. */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
- .dl_fn = tx_idle_fn,
},
[TRXC_FCCH] = {
.name = "FCCH", /* 3GPP TS 05.02, section 3.3.2.1 */
.desc = "Frequency correction channel",
/* Tx only, frequency correction bursts */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.dl_fn = tx_fcch_fn,
},
[TRXC_SCH] = {
@@ -137,7 +158,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.desc = "Synchronization channel",
/* Tx only, synchronization bursts */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.dl_fn = tx_sch_fn,
},
[TRXC_BCCH] = {
@@ -148,7 +168,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
/* Tx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4),
* regular interleaving (3GPP TS 05.02, clause 7, table 3):
* a L2 frame is interleaved over 4 consecutive bursts. */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
@@ -158,7 +177,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.chan_nr = RSL_CHAN_RACH,
/* Rx only, RACH convolutional coding (3GPP TS 05.03, section 4.6). */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.ul_fn = rx_rach_fn,
},
[TRXC_CCCH] = {
@@ -169,7 +187,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
/* Tx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4),
* regular interleaving (3GPP TS 05.02, clause 7, table 3):
* a L2 frame is interleaved over 4 consecutive bursts. */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
@@ -200,13 +217,14 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
/* Rx and Tx, multiple convolutional coding types (3GPP TS 05.03,
* chapter 3), block diagonal interleaving (3GPP TS 05.02, clause 7):
*
- * - a traffic frame is interleaved over 6 consecutive bursts
+ * - a traffic frame is interleaved over 4 consecutive bursts
* using the even numbered bits of the first 2 bursts,
- * all bits of the middle two 2 bursts,
* and odd numbered bits of the last 2 bursts;
* - a FACCH/H frame 'steals' (replaces) two traffic frames,
- * interleaving is done over 4 consecutive bursts,
- * the same as given for a TCH/FS. */
+ * interleaving is done over 6 consecutive bursts,
+ * using the even numbered bits of the first 2 bursts,
+ * all bits of the middle two 2 bursts,
+ * and odd numbered bits of the last 2 bursts. */
.rts_fn = rts_tchh_fn,
.dl_fn = tx_tchh_fn,
.ul_fn = rx_tchh_fn,
@@ -525,10 +543,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.chan_nr = RSL_CHAN_OSMO_PDCH,
/* Rx and Tx, multiple coding schemes: CS-2..4 and MCS-1..9 (3GPP TS
- * 05.03, chapter 5), regular interleaving as specified for xCCH.
- * NOTE: the burst buffer is three times bigger because the
- * payload of EDGE bursts is three times longer. */
- .flags = TRX_CHAN_FLAG_PDCH,
+ * 05.03, chapter 5), regular interleaving as specified for xCCH. */
.rts_fn = rts_data_fn,
.dl_fn = tx_pdtch_fn,
.ul_fn = rx_pdtch_fn,
@@ -538,11 +553,14 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.desc = "Packet Timing advance control channel",
.chan_nr = RSL_CHAN_OSMO_PDCH,
- /* Same as for TRXC_BCCH (xCCH), see above. */
- .flags = TRX_CHAN_FLAG_PDCH,
+ /* On the Uplink, mobile stations transmit random Access Bursts
+ * to allow estimation of the timing advance for one MS in packet
+ * transfer mode. On Downlink, the network sends timing advance
+ * updates for several mobile stations. The coding scheme used
+ * for PTCCH/D messages is the same as for PDTCH CS-1. */
.rts_fn = rts_data_fn,
- .dl_fn = tx_data_fn,
- .ul_fn = rx_data_fn,
+ .dl_fn = tx_pdtch_fn,
+ .ul_fn = rx_rach_fn,
},
[TRXC_CBCH] = {
/* TODO: distinguish CBCH on SDCCH/4 and SDCCH/8 */
@@ -551,163 +569,203 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.chan_nr = RSL_CHAN_OSMO_CBCH4,
/* Tx only, same as for TRXC_BCCH (xCCH), see above. */
- .flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
};
+enum {
+ L1SCHED_TS_CTR_DL_LATE,
+ L1SCHED_TS_CTR_DL_NOT_FOUND,
+};
+
+static const struct rate_ctr_desc l1sched_ts_ctr_desc[] = {
+ [L1SCHED_TS_CTR_DL_LATE] = {"l1sched_ts:dl_late", "Downlink frames arrived too late to submit to lower layers"},
+ [L1SCHED_TS_CTR_DL_NOT_FOUND] = {"l1sched_ts:dl_not_found", "Downlink frames not found while scheduling"},
+};
+static const struct rate_ctr_group_desc l1sched_ts_ctrg_desc = {
+ "l1sched_ts",
+ "L1 scheduler timeslot",
+ OSMO_STATS_CLASS_GLOBAL,
+ ARRAY_SIZE(l1sched_ts_ctr_desc),
+ l1sched_ts_ctr_desc
+};
+
/*
* init / exit
*/
-int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx)
+static void trx_sched_init_ts(struct gsm_bts_trx_ts *ts,
+ const unsigned int rate_ctr_idx)
{
- uint8_t tn;
+ struct l1sched_ts *l1ts;
unsigned int i;
+ char name[128];
- if (!trx)
- return -EINVAL;
+ l1ts = talloc_zero(ts->trx, struct l1sched_ts);
+ OSMO_ASSERT(l1ts != NULL);
- l1t->trx = trx;
+ /* Link both structures */
+ ts->priv = l1ts;
+ l1ts->ts = ts;
- LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr);
+ l1ts->ctrs = rate_ctr_group_alloc(ts->trx,
+ &l1sched_ts_ctrg_desc,
+ rate_ctr_idx);
+ snprintf(name, sizeof(name), "bts%u-trx%u-ts%u%s",
+ ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ ts->vamos.is_shadow ? "-shadow" : "");
+ rate_ctr_group_set_name(l1ts->ctrs, name);
- for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ INIT_LLIST_HEAD(&l1ts->dl_prims);
- l1ts->mf_index = 0;
- INIT_LLIST_HEAD(&l1ts->dl_prims);
- for (i = 0; i < ARRAY_SIZE(l1ts->chan_state); i++) {
- struct l1sched_chan_state *chan_state;
- chan_state = &l1ts->chan_state[i];
- chan_state->active = 0;
- }
+ for (i = 0; i < ARRAY_SIZE(l1ts->chan_state); i++) {
+ struct l1sched_chan_state *chan_state;
+ chan_state = &l1ts->chan_state[i];
+ chan_state->active = false;
}
-
- return 0;
}
-void trx_sched_exit(struct l1sched_trx *l1t)
+void trx_sched_init(struct gsm_bts_trx *trx)
{
- struct gsm_bts_trx_ts *ts;
- uint8_t tn;
- int i;
+ unsigned int tn;
- LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr);
-
- for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- msgb_queue_flush(&l1ts->dl_prims);
- for (i = 0; i < _TRX_CHAN_MAX; i++) {
- struct l1sched_chan_state *chan_state;
- chan_state = &l1ts->chan_state[i];
- if (chan_state->dl_bursts) {
- talloc_free(chan_state->dl_bursts);
- chan_state->dl_bursts = NULL;
- }
- if (chan_state->ul_bursts) {
- talloc_free(chan_state->ul_bursts);
- chan_state->ul_bursts = NULL;
- }
- }
- /* clear lchan channel states */
- ts = &l1t->trx->ts[tn];
- for (i = 0; i < ARRAY_SIZE(ts->lchan); i++)
- lchan_set_state(&ts->lchan[i], LCHAN_S_NONE);
+ OSMO_ASSERT(trx != NULL);
+
+ LOGPTRX(trx, DL1C, LOGL_DEBUG, "Init scheduler structures\n");
+
+ /* Allocate shadow timeslots */
+ gsm_bts_trx_init_shadow_ts(trx);
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ unsigned int rate_ctr_idx = trx->nr * 100 + tn;
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ /* Init primary and shadow timeslots */
+ trx_sched_init_ts(ts, rate_ctr_idx);
+ trx_sched_init_ts(ts->vamos.peer, rate_ctr_idx + 10);
}
}
-/* close all logical channels and reset timeslots */
-void trx_sched_reset(struct l1sched_trx *l1t)
+static void trx_sched_clean_ts(struct gsm_bts_trx_ts *ts)
{
- trx_sched_exit(l1t);
- trx_sched_init(l1t, l1t->trx);
+ struct l1sched_ts *l1ts = ts->priv;
+ unsigned int i;
+
+ msgb_queue_free(&l1ts->dl_prims);
+ rate_ctr_group_free(l1ts->ctrs);
+ l1ts->ctrs = NULL;
+
+ /* clear lchan channel states */
+ for (i = 0; i < ARRAY_SIZE(ts->lchan); i++)
+ lchan_set_state(&ts->lchan[i], LCHAN_S_NONE);
+
+ talloc_free(l1ts);
+ ts->priv = NULL;
+}
+
+void trx_sched_clean(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ LOGPTRX(trx, DL1C, LOGL_DEBUG, "Clean scheduler structures\n");
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ /* Clean primary and shadow timeslots */
+ trx_sched_clean_ts(ts);
+ trx_sched_clean_ts(ts->vamos.peer);
+ }
+
+ /* Free previously allocated shadow timeslots */
+ gsm_bts_trx_free_shadow_ts(trx);
}
-struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn,
- enum trx_chan_type chan)
+struct msgb *_sched_dequeue_prim(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
{
struct msgb *msg, *msg2;
- struct osmo_phsap_prim *l1sap;
- uint32_t prim_fn;
+ uint32_t prim_fn, l1sap_fn;
uint8_t chan_nr, link_id;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
/* get prim of current fn from queue */
llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) {
- l1sap = msgb_l1sap_prim(msg);
- if (l1sap->oph.operation != PRIM_OP_REQUEST) {
-wrong_type:
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Prim has wrong type.\n");
-free_msg:
- /* unlink and free message */
- llist_del(&msg->list);
- msgb_free(msg);
- return NULL;
- }
+ struct osmo_phsap_prim *l1sap = msgb_l1sap_prim(msg);
switch (l1sap->oph.primitive) {
case PRIM_PH_DATA:
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
- prim_fn = ((l1sap->u.data.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME);
+ l1sap_fn = l1sap->u.data.fn;
break;
case PRIM_TCH:
chan_nr = l1sap->u.tch.chan_nr;
link_id = 0;
- prim_fn = ((l1sap->u.tch.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME);
+ l1sap_fn = l1sap->u.tch.fn;
break;
default:
- goto wrong_type;
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Prim has wrong type.\n");
+ goto free_msg;
}
- if (prim_fn > 100) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
- "Prim %u is out of range (100), or channel %s with "
+ prim_fn = GSM_TDMA_FN_SUB(l1sap_fn, br->fn);
+ if (prim_fn > 100) { /* l1sap_fn < fn */
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
+ "Prim %u is out of range (%u vs exp %u), or channel %s with "
"type %s is already disabled. If this happens in "
"conjunction with PCU, increase 'rts-advance' by 5.\n",
- prim_fn, get_lchan_by_chan_nr(l1t->trx, chan_nr)->name,
- trx_chan_desc[chan].name);
+ prim_fn, l1sap_fn, br->fn,
+ get_lchan_by_chan_nr(l1ts->ts->trx, chan_nr)->name,
+ trx_chan_desc[br->chan].name);
+ rate_ctr_inc2(l1ts->ctrs, L1SCHED_TS_CTR_DL_LATE);
/* unlink and free message */
llist_del(&msg->list);
msgb_free(msg);
continue;
}
- if (prim_fn > 0)
- continue;
+ if (prim_fn > 0) /* l1sap_fn > fn */
+ break;
- goto found_msg;
+ /* l1sap_fn == fn */
+ if ((chan_nr ^ (trx_chan_desc[br->chan].chan_nr | br->tn))
+ || ((link_id & 0xc0) ^ trx_chan_desc[br->chan].link_id)) {
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Prim has wrong chan_nr=0x%02x link_id=%02x, "
+ "expecting chan_nr=0x%02x link_id=%02x.\n", chan_nr, link_id,
+ trx_chan_desc[br->chan].chan_nr | br->tn, trx_chan_desc[br->chan].link_id);
+ goto free_msg;
+ }
+
+ /* unlink and return message */
+ llist_del(&msg->list);
+ return msg;
}
+ /* Queue was traversed with no candidate, no prim is available for current FN: */
+ rate_ctr_inc2(l1ts->ctrs, L1SCHED_TS_CTR_DL_NOT_FOUND);
return NULL;
-found_msg:
- if ((chan_nr ^ (trx_chan_desc[chan].chan_nr | tn))
- || ((link_id & 0xc0) ^ trx_chan_desc[chan].link_id)) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Prim has wrong chan_nr=0x%02x link_id=%02x, "
- "expecting chan_nr=0x%02x link_id=%02x.\n", chan_nr, link_id,
- trx_chan_desc[chan].chan_nr | tn, trx_chan_desc[chan].link_id);
- goto free_msg;
- }
-
- /* unlink and return message */
+free_msg:
+ /* unlink and free message */
llist_del(&msg->list);
- return msg;
+ msgb_free(msg);
+ return NULL;
}
-int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t *l2,
- uint8_t l2_len, float rssi,
+int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
+ enum trx_chan_type chan,
+ const uint8_t *data, size_t data_len,
+ uint16_t ber10k, float rssi,
int16_t ta_offs_256bits, int16_t link_qual_cb,
- uint16_t ber10k,
enum osmo_ph_pres_info_type presence_info)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
- uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
+
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
/* compose primitive */
- msg = l1sap_msgb_alloc(l2_len);
+ msg = l1sap_msgb_alloc(data_len);
l1sap = msgb_l1sap_prim(msg);
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA,
PRIM_OP_INDICATION, msg);
@@ -719,48 +777,53 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
l1sap->u.data.ta_offs_256bits = ta_offs_256bits;
l1sap->u.data.lqual_cb = link_qual_cb;
l1sap->u.data.pdch_presence_info = presence_info;
- msg->l2h = msgb_put(msg, l2_len);
- if (l2_len)
- memcpy(msg->l2h, l2, l2_len);
-
- if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id))
- l1ts->chan_state[chan].lost_frames = 0;
+ msg->l2h = msgb_put(msg, data_len);
+ if (data_len)
+ memcpy(msg->l2h, data, data_len);
/* forward primitive */
- l1sap_up(l1t->trx, l1sap);
+ l1sap_up(l1ts->ts->trx, l1sap);
return 0;
}
-int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len)
+int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
+ enum trx_chan_type chan,
+ const uint8_t *data, size_t data_len,
+ uint16_t ber10k, float rssi,
+ int16_t ta_offs_256bits, int16_t link_qual_cb,
+ uint8_t is_sub)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
- struct gsm_bts_trx *trx = l1t->trx;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
- struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
+ uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
+ struct gsm_lchan *lchan = &l1ts->ts->lchan[l1sap_chan2ss(chan_nr)];
+
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
/* compose primitive */
- msg = l1sap_msgb_alloc(tch_len);
+ msg = l1sap_msgb_alloc(data_len);
l1sap = msgb_l1sap_prim(msg);
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH,
PRIM_OP_INDICATION, msg);
l1sap->u.tch.chan_nr = chan_nr;
l1sap->u.tch.fn = fn;
- msg->l2h = msgb_put(msg, tch_len);
- if (tch_len)
- memcpy(msg->l2h, tch, tch_len);
-
- if (l1ts->chan_state[chan].lost_frames)
- l1ts->chan_state[chan].lost_frames--;
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, -1, l1sap->u.data.fn,
- "%s Rx -> RTP: %s\n",
- gsm_lchan_name(lchan), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
+ l1sap->u.tch.rssi = (int8_t) (rssi);
+ l1sap->u.tch.ber10k = ber10k;
+ l1sap->u.tch.ta_offs_256bits = ta_offs_256bits;
+ l1sap->u.tch.lqual_cb = link_qual_cb;
+ l1sap->u.tch.is_sub = is_sub & 1;
+
+ msg->l2h = msgb_put(msg, data_len);
+ if (data_len)
+ memcpy(msg->l2h, data, data_len);
+
+ LOGL1S(DL1P, LOGL_DEBUG, l1ts, chan, l1sap->u.tch.fn, "%s Rx -> RTP: %s\n",
+ gsm_lchan_name(lchan), msgb_hexdump_l2(msg));
/* forward primitive */
- l1sap_up(l1t->trx, l1sap);
+ l1sap_up(l1ts->ts->trx, l1sap);
return 0;
}
@@ -771,39 +834,37 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
* data request (from upper layer)
*/
-int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
+int trx_sched_ph_data_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
- uint8_t tn = l1sap->u.data.chan_nr & 7;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ uint8_t tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr);
+ struct l1sched_ts *l1ts = trx->ts[tn].priv;
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, -1, l1sap->u.data.fn,
+ LOGL1S(DL1P, LOGL_DEBUG, l1ts, -1, l1sap->u.data.fn,
"PH-DATA.req: chan_nr=0x%02x link_id=0x%02x\n",
l1sap->u.data.chan_nr, l1sap->u.data.link_id);
- if (!l1sap->oph.msg)
- abort();
-
/* ignore empty frame */
- if (!msgb_l2len(l1sap->oph.msg)) {
+ if (!l1sap->oph.msg->l2h || msgb_l2len(l1sap->oph.msg) == 0) {
msgb_free(l1sap->oph.msg);
return 0;
}
+ /* VAMOS: convert Osmocom specific channel number to a generic one */
+ if (trx->ts[tn].vamos.is_shadow)
+ l1sap->u.data.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
}
-int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
+int trx_sched_tch_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
- uint8_t tn = l1sap->u.tch.chan_nr & 7;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ uint8_t tn = L1SAP_CHAN2TS(l1sap->u.tch.chan_nr);
+ struct l1sched_ts *l1ts = trx->ts[tn].priv;
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, -1, l1sap->u.tch.fn, "TCH.req: chan_nr=0x%02x\n",
- l1sap->u.tch.chan_nr);
-
- if (!l1sap->oph.msg)
- abort();
+ LOGL1S(DL1P, LOGL_DEBUG, l1ts, -1, l1sap->u.tch.fn,
+ "TCH.req: chan_nr=0x%02x\n", l1sap->u.tch.chan_nr);
/* ignore empty frame */
if (!msgb_l2len(l1sap->oph.msg)) {
@@ -811,36 +872,43 @@ int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
return 0;
}
+ /* VAMOS: convert Osmocom specific channel number to a generic one */
+ if (trx->ts[tn].vamos.is_shadow)
+ l1sap->u.tch.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
}
-/*
+/*
* ready-to-send indication (to upper layer)
*/
/* RTS for data frame */
-static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan)
+static int rts_data_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
{
uint8_t chan_nr, link_id;
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
/* get data for RTS indication */
- chan_nr = trx_chan_desc[chan].chan_nr | tn;
- link_id = trx_chan_desc[chan].link_id;
+ chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
+ link_id = trx_chan_desc[br->chan].link_id;
- if (!chan_nr) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "RTS func with non-existing chan_nr %d\n", chan_nr);
- return -ENODEV;
- }
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn,
- "PH-RTS.ind: chan_nr=0x%02x link_id=0x%02x\n", chan_nr, link_id);
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
+ /* For handover detection, there are cases where the SACCH should remain inactive until the first RACH
+ * indicating the TA is received. */
+ if (L1SAP_IS_LINK_SACCH(link_id)
+ && !l1ts->chan_state[br->chan].lchan->want_dl_sacch_active)
+ return 0;
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "PH-RTS.ind: chan_nr=0x%02x link_id=0x%02x\n", chan_nr, link_id);
/* generate prim */
msg = l1sap_msgb_alloc(200);
@@ -851,31 +919,30 @@ static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
PRIM_OP_INDICATION, msg);
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.link_id = link_id;
- l1sap->u.data.fn = fn;
+ l1sap->u.data.fn = br->fn;
- return l1sap_up(l1t->trx, l1sap);
+ return l1sap_up(l1ts->ts->trx, l1sap);
}
-static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, int facch)
+static int rts_tch_common(const struct l1sched_ts *l1ts,
+ const struct trx_dl_burst_req *br,
+ bool facch)
{
uint8_t chan_nr, link_id;
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
int rc = 0;
/* get data for RTS indication */
- chan_nr = trx_chan_desc[chan].chan_nr | tn;
- link_id = trx_chan_desc[chan].link_id;
+ chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
+ link_id = trx_chan_desc[br->chan].link_id;
- if (!chan_nr) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "RTS func with non-existing chan_nr %d\n", chan_nr);
- return -ENODEV;
- }
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);
/* only send, if FACCH is selected */
if (facch) {
@@ -888,13 +955,13 @@ static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
PRIM_OP_INDICATION, msg);
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.link_id = link_id;
- l1sap->u.data.fn = fn;
+ l1sap->u.data.fn = br->fn;
- rc = l1sap_up(l1t->trx, l1sap);
+ rc = l1sap_up(l1ts->ts->trx, l1sap);
}
- /* dont send, if TCH is in signalling only mode */
- if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
+ /* don't send, if TCH is in signalling only mode */
+ if (l1ts->chan_state[br->chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
/* generate prim */
msg = l1sap_msgb_alloc(200);
if (!msg)
@@ -903,128 +970,259 @@ static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS,
PRIM_OP_INDICATION, msg);
l1sap->u.tch.chan_nr = chan_nr;
- l1sap->u.tch.fn = fn;
+ l1sap->u.tch.fn = br->fn;
- return l1sap_up(l1t->trx, l1sap);
+ return l1sap_up(l1ts->ts->trx, l1sap);
}
return rc;
}
/* RTS for full rate traffic frame */
-static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan)
+static int rts_tchf_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
{
/* TCH/F may include FACCH on every 4th burst */
- return rts_tch_common(l1t, tn, fn, chan, 1);
+ return rts_tch_common(l1ts, br, true);
}
+/* FACCH/H channel mapping for Downlink (see 3GPP TS 45.002, table 1).
+ * This mapping is valid for both FACCH/H(0) and FACCH/H(1). */
+const uint8_t sched_tchh_dl_facch_map[26] = {
+ [4] = 1, /* FACCH/H(0): B0(4,6,8,10,13,15) */
+ [5] = 1, /* FACCH/H(1): B0(5,7,9,11,14,16) */
+ [13] = 1, /* FACCH/H(0): B1(13,15,17,19,21,23) */
+ [14] = 1, /* FACCH/H(1): B1(14,16,18,20,22,24) */
+ [21] = 1, /* FACCH/H(0): B2(21,23,0,2,4,6) */
+ [22] = 1, /* FACCH/H(1): B2(22,24,1,3,5,7) */
+};
/* RTS for half rate traffic frame */
-static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan)
+static int rts_tchh_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
{
- /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */
- return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1);
+ return rts_tch_common(l1ts, br, sched_tchh_dl_facch_map[br->fn % 26]);
}
/* set multiframe scheduler to given pchan */
-int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
- enum gsm_phys_chan_config pchan)
+int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- int i;
-
- i = find_sched_mframe_idx(pchan, tn);
+ struct l1sched_ts *l1ts = ts->priv;
+ int i = find_sched_mframe_idx(pchan, ts->nr);
if (i < 0) {
- LOGP(DL1C, LOGL_NOTICE, "Failed to configure multiframe "
- "trx=%d ts=%d\n", l1t->trx->nr, tn);
+ LOGP(DL1C, LOGL_NOTICE, "%s Failed to configure multiframe (pchan=0x%02x)\n",
+ gsm_ts_name(ts), pchan);
return -ENOTSUP;
}
l1ts->mf_index = i;
l1ts->mf_period = trx_sched_multiframes[i].period;
l1ts->mf_frames = trx_sched_multiframes[i].frames;
- LOGP(DL1C, LOGL_NOTICE, "Configuring multiframe with %s trx=%d ts=%d\n",
- trx_sched_multiframes[i].name, l1t->trx->nr, tn);
+ if (ts->vamos.peer != NULL) {
+ l1ts = ts->vamos.peer->priv;
+ l1ts->mf_index = i;
+ l1ts->mf_period = trx_sched_multiframes[i].period;
+ l1ts->mf_frames = trx_sched_multiframes[i].frames;
+ }
+ LOGP(DL1C, LOGL_NOTICE, "%s Configured multiframe with '%s'\n",
+ gsm_ts_name(ts), trx_sched_multiframes[i].name);
return 0;
}
+/* Remove all matching (by chan_nr & link_id) primitives from the given queue */
+static void trx_sched_queue_filter(struct llist_head *q, uint8_t chan_nr, uint8_t link_id)
+{
+ struct msgb *msg, *_msg;
+
+ llist_for_each_entry_safe(msg, _msg, q, list) {
+ struct osmo_phsap_prim *l1sap = msgb_l1sap_prim(msg);
+ switch (l1sap->oph.primitive) {
+ case PRIM_PH_DATA:
+ if (l1sap->u.data.chan_nr != chan_nr)
+ continue;
+ if (l1sap->u.data.link_id != link_id)
+ continue;
+ break;
+ case PRIM_TCH:
+ if (l1sap->u.tch.chan_nr != chan_nr)
+ continue;
+ if (link_id != 0x00)
+ continue;
+ break;
+ default:
+ /* Shall not happen */
+ OSMO_ASSERT(0);
+ }
+
+ /* Unlink and free() */
+ llist_del(&msg->list);
+ talloc_free(msg);
+ }
+}
+
+static void _trx_sched_set_lchan(struct gsm_lchan *lchan,
+ enum trx_chan_type chan,
+ bool active)
+{
+ struct l1sched_ts *l1ts = lchan->ts->priv;
+ struct l1sched_chan_state *chan_state;
+
+ OSMO_ASSERT(l1ts != NULL);
+ chan_state = &l1ts->chan_state[chan];
+
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s %s\n",
+ (active) ? "Activating" : "Deactivating",
+ trx_chan_desc[chan].name);
+
+ if (active) {
+ /* Clean up everything */
+ memset(chan_state, 0, sizeof(*chan_state));
+
+ /* Bind to generic 'struct gsm_lchan' */
+ chan_state->lchan = lchan;
+
+ /* Allocate memory for Rx/Tx burst buffers. Use the maximim size
+ * of 24 * (2 * 58) bytes, which is sufficient to store up to 24 GMSK
+ * modulated bursts for CSD or up to 8 8PSK modulated bursts for EGPRS. */
+ const size_t buf_size = 24 * GSM_NBITS_NB_GMSK_PAYLOAD;
+ if (trx_chan_desc[chan].dl_fn != NULL)
+ chan_state->dl_bursts = talloc_zero_size(l1ts, buf_size);
+ if (trx_chan_desc[chan].ul_fn != NULL)
+ chan_state->ul_bursts = talloc_zero_size(l1ts, buf_size);
+ } else {
+ chan_state->ho_rach_detect = 0;
+
+ /* Remove pending Tx prims belonging to this lchan */
+ trx_sched_queue_filter(&l1ts->dl_prims,
+ trx_chan_desc[chan].chan_nr,
+ trx_chan_desc[chan].link_id);
+
+ /* Release memory used by Rx/Tx burst buffers */
+ TALLOC_FREE(chan_state->dl_bursts);
+ TALLOC_FREE(chan_state->ul_bursts);
+ }
+
+ chan_state->active = active;
+}
+
/* setting all logical channels given attributes to active/inactive */
-int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id,
- int active)
+int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active)
{
+ struct l1sched_ts *l1ts = lchan->ts->priv;
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
uint8_t ss = l1sap_chan2ss(chan_nr);
- int i;
- int rc = -EINVAL;
+ bool found = false;
+
+ if (!l1ts) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "%s lchan with uninitialized scheduler structure\n",
+ (active) ? "Activating" : "Deactivating");
+ return -EINVAL;
+ }
+
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
/* look for all matching chan_nr/link_id */
- for (i = 0; i < _TRX_CHAN_MAX; i++) {
- struct l1sched_chan_state *chan_state;
- chan_state = &l1ts->chan_state[i];
- /* Skip if pchan type does not match pdch flag.
- * FIXME: Is it possible at all? Clarify if so. */
- if ((trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
- && !(trx_chan_desc[i].flags & TRX_CHAN_FLAG_PDCH))
+ for (enum trx_chan_type chan = 0; chan < _TRX_CHAN_MAX; chan++) {
+ if (trx_chan_desc[chan].chan_nr != (chan_nr & RSL_CHAN_NR_MASK))
continue;
- if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
- && trx_chan_desc[i].link_id == link_id) {
- rc = 0;
- if (chan_state->active == active)
- continue;
- LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n",
- (active) ? "Activating" : "Deactivating",
- trx_chan_desc[i].name, l1t->trx->nr, tn);
- if (active)
- memset(chan_state, 0, sizeof(*chan_state));
- chan_state->active = active;
- /* free burst memory, to cleanly start with burst 0 */
- if (chan_state->dl_bursts) {
- talloc_free(chan_state->dl_bursts);
- chan_state->dl_bursts = NULL;
- }
- if (chan_state->ul_bursts) {
- talloc_free(chan_state->ul_bursts);
- chan_state->ul_bursts = NULL;
- }
- if (!active)
- chan_state->ho_rach_detect = 0;
- }
+ if (trx_chan_desc[chan].link_id != link_id)
+ continue;
+ if (l1ts->chan_state[chan].active == active)
+ continue;
+ found = true;
+ _trx_sched_set_lchan(lchan, chan, active);
}
/* disable handover detection (on deactivation) */
if (!active)
- _sched_act_rach_det(l1t, tn, ss, 0);
+ _sched_act_rach_det(lchan->ts->trx, tn, ss, 0);
- return rc;
+ return found ? 0 : -EINVAL;
+}
+
+int trx_sched_set_ul_access(struct gsm_lchan *lchan, uint8_t chan_nr, bool active)
+{
+ struct l1sched_ts *l1ts = lchan->ts->priv;
+ uint8_t tn = L1SAP_CHAN2TS(chan_nr);
+ uint8_t ss = l1sap_chan2ss(chan_nr);
+ int i;
+
+ if (!l1ts) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "%s UL access on lchan with uninitialized scheduler structure.\n",
+ (active) ? "Activating" : "Deactivating");
+ return -EINVAL;
+ }
+
+ /* look for all matching chan_nr */
+ for (i = 0; i < _TRX_CHAN_MAX; i++) {
+ if (trx_chan_desc[i].chan_nr == (chan_nr & RSL_CHAN_NR_MASK)) {
+ struct l1sched_chan_state *l1cs = &l1ts->chan_state[i];
+
+ l1cs->ho_rach_detect = active;
+ }
+ }
+
+ _sched_act_rach_det(lchan->ts->trx, tn, ss, active);
+
+ return 0;
+}
+
+int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active)
+{
+ struct l1sched_ts *l1ts = lchan->ts->priv;
+ static const enum trx_chan_type chans[] = {
+ TRXC_FCCH,
+ TRXC_SCH,
+ TRXC_BCCH,
+ TRXC_RACH,
+ TRXC_CCCH,
+ };
+
+ if (!l1ts)
+ return -EINVAL;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(chans); i++) {
+ enum trx_chan_type chan = chans[i];
+
+ if (l1ts->chan_state[chan].active == active)
+ continue;
+ _trx_sched_set_lchan(lchan, chan, active);
+ }
+
+ return 0;
}
/* setting all logical channels given attributes to active/inactive */
-int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
+int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
uint8_t codec2, uint8_t codec3, uint8_t initial_id, uint8_t handover)
{
+ struct l1sched_ts *l1ts = ts->priv;
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
uint8_t ss = l1sap_chan2ss(chan_nr);
int i;
int rc = -EINVAL;
- struct l1sched_chan_state *chan_state;
/* no mode for PDCH */
- if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
+ if (ts->pchan == GSM_PCHAN_PDCH)
return 0;
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
&& trx_chan_desc[i].link_id == 0x00) {
- chan_state = &l1ts->chan_state[i];
- LOGP(DL1C, LOGL_NOTICE, "Set mode %u, %u, handover %u "
- "on %s of trx=%d ts=%d\n", rsl_cmode, tch_mode,
- handover, trx_chan_desc[i].name, l1t->trx->nr,
- tn);
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[i];
+
+ LOGP(DL1C, LOGL_INFO,
+ "%s Set mode for %s (rsl_cmode=%u, tch_mode=%u, handover=%u)\n",
+ gsm_ts_name(ts), trx_chan_desc[i].name,
+ rsl_cmode, tch_mode, handover);
+
chan_state->rsl_cmode = rsl_cmode;
chan_state->tch_mode = tch_mode;
chan_state->ho_rach_detect = handover;
@@ -1039,8 +1237,8 @@ int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmo
chan_state->dl_ft = initial_id;
chan_state->ul_cmr = initial_id;
chan_state->dl_cmr = initial_id;
- chan_state->ber_sum = 0;
- chan_state->ber_num = 0;
+ chan_state->lqual_cb_sum = 0;
+ chan_state->lqual_cb_num = 0;
}
rc = 0;
}
@@ -1051,53 +1249,54 @@ int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmo
* of transceiver link).
* disable handover, if state is still set, since we might not know
* the actual state of transceiver (due to loss of link) */
- _sched_act_rach_det(l1t, tn, ss, handover);
+ _sched_act_rach_det(ts->trx, tn, ss, handover);
return rc;
}
/* setting cipher on logical channels */
-int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
- int algo, uint8_t *key, int key_len)
+int trx_sched_set_cipher(struct gsm_lchan *lchan, uint8_t chan_nr, bool downlink)
{
- uint8_t tn = L1SAP_CHAN2TS(chan_nr);
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- int i;
- int rc = -EINVAL;
- struct l1sched_chan_state *chan_state;
+ int algo = lchan->encr.alg_id - 1;
+ int i, rc = -EINVAL;
/* no cipher for PDCH */
- if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
+ if (ts_pchan(lchan->ts) == GSM_PCHAN_PDCH)
return 0;
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
/* no algorithm given means a5/0 */
if (algo <= 0)
algo = 0;
- else if (key_len != 8) {
- LOGP(DL1C, LOGL_ERROR, "Algo A5/%d not supported with given "
- "key len=%d\n", algo, key_len);
+ else if (lchan->encr.key_len != 8 && lchan->encr.key_len != 16) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR,
+ "Algo A5/%d not supported with given key_len=%u\n",
+ algo, lchan->encr.key_len);
return -ENOTSUP;
}
/* look for all matching chan_nr */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
- /* skip if pchan type */
- if (trx_chan_desc[i].flags & TRX_CHAN_FLAG_PDCH)
- continue;
- if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)) {
- chan_state = &l1ts->chan_state[i];
- LOGP(DL1C, LOGL_NOTICE, "Set a5/%d %s for %s on trx=%d "
- "ts=%d\n", algo,
- (downlink) ? "downlink" : "uplink",
- trx_chan_desc[i].name, l1t->trx->nr, tn);
+ if (trx_chan_desc[i].chan_nr == (chan_nr & RSL_CHAN_NR_MASK)) {
+ struct l1sched_ts *l1ts = lchan->ts->priv;
+ struct l1sched_chan_state *l1cs = &l1ts->chan_state[i];
+
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Set A5/%d %s for %s\n",
+ algo, (downlink) ? "downlink" : "uplink",
+ trx_chan_desc[i].name);
+
if (downlink) {
- chan_state->dl_encr_algo = algo;
- memcpy(chan_state->dl_encr_key, key, key_len);
- chan_state->dl_encr_key_len = key_len;
+ l1cs->dl_encr_algo = algo;
+ memcpy(l1cs->dl_encr_key, lchan->encr.key, lchan->encr.key_len);
+ l1cs->dl_encr_key_len = lchan->encr.key_len;
} else {
- chan_state->ul_encr_algo = algo;
- memcpy(chan_state->ul_encr_key, key, key_len);
- chan_state->ul_encr_key_len = key_len;
+ l1cs->ul_encr_algo = algo;
+ memcpy(l1cs->ul_encr_key, lchan->encr.key, lchan->encr.key_len);
+ l1cs->ul_encr_key_len = lchan->encr.key_len;
}
rc = 0;
}
@@ -1107,9 +1306,8 @@ int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
}
/* process ready-to-send */
-int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
+int _sched_rts(const struct l1sched_ts *l1ts, uint32_t fn)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
trx_sched_rts_func *func;
@@ -1137,87 +1335,99 @@ int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
return 0;
/* check if channel is active */
- if (!TRX_CHAN_IS_ACTIVE(&l1ts->chan_state[chan], chan))
+ if (!l1ts->chan_state[chan].active)
return -EINVAL;
- return func(l1t, tn, fn, frame->dl_chan);
+ /* There is no burst, just for logging */
+ struct trx_dl_burst_req dbr = {
+ .fn = fn,
+ .tn = l1ts->ts->nr,
+ .bid = bid,
+ .chan = chan,
+ };
+
+ return func(l1ts, &dbr);
+}
+
+static void trx_sched_apply_att(const struct gsm_lchan *lchan,
+ struct trx_dl_burst_req *br)
+{
+ const struct trx_chan_desc *desc = &trx_chan_desc[br->chan];
+
+ /* Current BS power reduction value in dB */
+ br->att = lchan->bs_power_ctrl.current;
+
+ /* Temporary Overpower for SACCH/FACCH bursts */
+ if (!lchan->top_acch_active)
+ return;
+ if ((lchan->top_acch_cap.sacch_enable && desc->link_id == LID_SACCH) ||
+ (lchan->top_acch_cap.facch_enable && br->flags & TRX_BR_F_FACCH)) {
+ if (br->att > lchan->top_acch_cap.overpower_db)
+ br->att -= lchan->top_acch_cap.overpower_db;
+ else
+ br->att = 0;
+ }
}
/* process downlink burst */
-const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
- uint32_t fn, uint16_t *nbits)
+void _sched_dl_burst(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct l1sched_chan_state *l1cs;
+ const struct l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
- uint8_t offset, period, bid;
+ uint8_t offset, period;
trx_sched_dl_func *func;
- enum trx_chan_type chan;
- ubit_t *bits = NULL;
if (!l1ts->mf_index)
- goto no_data;
+ return;
/* get frame from multiframe */
period = l1ts->mf_period;
- offset = fn % period;
+ offset = br->fn % period;
frame = l1ts->mf_frames + offset;
- chan = frame->dl_chan;
- bid = frame->dl_bid;
- func = trx_chan_desc[chan].dl_fn;
+ br->chan = frame->dl_chan;
+ br->bid = frame->dl_bid;
+ func = trx_chan_desc[br->chan].dl_fn;
- l1cs = &l1ts->chan_state[chan];
+ l1cs = &l1ts->chan_state[br->chan];
/* check if channel is active */
- if (!TRX_CHAN_IS_ACTIVE(l1cs, chan)) {
- if (nbits)
- *nbits = GSM_BURST_LEN;
- goto no_data;
- }
+ if (!l1cs->active)
+ return;
+
+ /* Training Sequence Code and Set */
+ br->tsc_set = l1ts->ts->tsc_set;
+ br->tsc = l1ts->ts->tsc;
/* get burst from function */
- bits = func(l1t, tn, fn, chan, bid, nbits);
+ if (func(l1ts, br) != 0)
+ return;
+
+ /* Modulation is indicated by func() */
+ br->mod = l1cs->dl_mod_type;
+
+ /* BS Power reduction (in dB) per logical channel */
+ if (l1cs->lchan != NULL)
+ trx_sched_apply_att(l1cs->lchan, br);
/* encrypt */
- if (bits && l1cs->dl_encr_algo) {
+ if (br->burst_len && l1cs->dl_encr_algo) {
ubit_t ks[114];
int i;
- osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL);
+ osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, br->fn, ks, NULL);
for (i = 0; i < 57; i++) {
- bits[i + 3] ^= ks[i];
- bits[i + 88] ^= ks[i + 57];
+ br->burst[i + 3] ^= ks[i];
+ br->burst[i + 88] ^= ks[i + 57];
}
}
-
-no_data:
- /* in case of C0, we need a dummy burst to maintain RF power */
- if (bits == NULL && l1t->trx == l1t->trx->bts->c0) {
-#if 0
- if (chan != TRXC_IDLE) // hack
- LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u "
- "burst=%d on C0, so filling with dummy burst\n",
- trx_chan_desc[chan].name, fn, tn, bid);
-#endif
- bits = (ubit_t *) dummy_burst;
- }
-
- return bits;
}
-#define TDMA_FN_SUM(a, b) \
- ((a + GSM_HYPERFRAME + b) % GSM_HYPERFRAME)
-
-#define TDMA_FN_SUB(a, b) \
- ((a + GSM_HYPERFRAME - b) % GSM_HYPERFRAME)
-
-static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
- struct l1sched_chan_state *l1cs, uint8_t tn, uint32_t fn)
+static int trx_sched_calc_frame_loss(struct l1sched_ts *l1ts,
+ struct l1sched_chan_state *l1cs,
+ const struct trx_ul_burst_ind *bi)
{
- const struct trx_sched_frame *frame_head;
const struct trx_sched_frame *frame;
- struct l1sched_ts *l1ts;
uint32_t elapsed_fs;
uint8_t offset, i;
uint32_t fn_i;
@@ -1230,13 +1440,8 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
if (l1cs->proc_tdma_fs == 0)
return 0;
- /* Get current TDMA frame info */
- l1ts = l1sched_trx_get_ts(l1t, tn);
- offset = fn % l1ts->mf_period;
- frame_head = l1ts->mf_frames + offset;
-
/* Not applicable for some logical channels */
- switch (frame_head->ul_chan) {
+ switch (bi->chan) {
case TRXC_IDLE:
case TRXC_RACH:
case TRXC_PDTCH:
@@ -1249,9 +1454,9 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
}
/* How many frames elapsed since the last one? */
- elapsed_fs = TDMA_FN_SUB(fn, l1cs->last_tdma_fn);
+ elapsed_fs = GSM_TDMA_FN_SUB(bi->fn, l1cs->last_tdma_fn);
if (elapsed_fs > l1ts->mf_period) { /* Too many! */
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, frame_head->ul_chan, fn,
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
"Too many (>%u) contiguous TDMA frames=%u elapsed "
"since the last processed fn=%u\n", l1ts->mf_period,
elapsed_fs, l1cs->last_tdma_fn);
@@ -1263,21 +1468,21 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
* There are several TDMA frames between the last processed
* frame and currently received one. Let's walk through this
* path and count potentially lost frames, i.e. for which
- * we didn't receive the corresponsing UL bursts.
+ * we didn't receive the corresponding UL bursts.
*
* Start counting from the last_fn + 1.
*/
for (i = 1; i < elapsed_fs; i++) {
- fn_i = TDMA_FN_SUM(l1cs->last_tdma_fn, i);
+ fn_i = GSM_TDMA_FN_SUM(l1cs->last_tdma_fn, i);
offset = fn_i % l1ts->mf_period;
frame = l1ts->mf_frames + offset;
- if (frame->ul_chan == frame_head->ul_chan)
+ if (frame->ul_chan == bi->chan)
l1cs->lost_tdma_fs++;
}
if (l1cs->lost_tdma_fs > 0) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, frame_head->ul_chan, fn,
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
"At least %u TDMA frames were lost since the last "
"processed fn=%u\n", l1cs->lost_tdma_fs, l1cs->last_tdma_fn);
@@ -1290,31 +1495,33 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
trx_sched_ul_func *func;
/* Prepare dummy burst indication */
- struct trx_ul_burst_ind bi = {
+ struct trx_ul_burst_ind dbi = {
.flags = TRX_BI_F_NOPE_IND,
.burst_len = GSM_BURST_LEN,
.burst = { 0 },
.rssi = -128,
.toa256 = 0,
+ .chan = bi->chan,
/* TDMA FN is set below */
- .tn = tn,
+ .tn = bi->tn,
};
for (i = 1; i < elapsed_fs; i++) {
- fn_i = TDMA_FN_SUM(l1cs->last_tdma_fn, i);
+ fn_i = GSM_TDMA_FN_SUM(l1cs->last_tdma_fn, i);
offset = fn_i % l1ts->mf_period;
frame = l1ts->mf_frames + offset;
func = trx_chan_desc[frame->ul_chan].ul_fn;
- if (frame->ul_chan != frame_head->ul_chan)
+ if (frame->ul_chan != bi->chan)
continue;
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, frame->ul_chan, fn,
- "Substituting lost TDMA frame=%u by all-zero "
- "dummy burst\n", fn_i);
+ dbi.bid = frame->ul_bid;
+ dbi.fn = fn_i;
- bi.fn = fn_i;
- func(l1t, frame->ul_chan, frame->ul_bid, &bi);
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, &dbi,
+ "Substituting lost burst with NOPE.ind\n");
+
+ func(l1ts, &dbi);
l1cs->lost_tdma_fs--;
}
@@ -1323,15 +1530,42 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
return 0;
}
+/* Process a single noise measurement for an inactive timeslot. */
+static void trx_sched_noise_meas(struct l1sched_chan_state *l1cs,
+ const struct trx_ul_burst_ind *bi)
+{
+ int *Avg = &l1cs->meas.interf_avg;
+
+ /* EWMA (Exponentially Weighted Moving Average):
+ *
+ * Avg[n] = a * Val[n] + (1 - a) * Avg[n - 1]
+ *
+ * Implemented using the '+=' operator:
+ *
+ * Avg += a * Val - a * Avg
+ * Avg += a * (Val - Avg)
+ *
+ * We use constant 'a' = 0.5, what is equal to:
+ *
+ * Avg += (Val - Avg) / 2
+ *
+ * We don't really need precisity here, so no scaling.
+ */
+
+ *Avg += (bi->rssi - *Avg) / 2;
+}
+
/* Process an Uplink burst indication */
-int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
+int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
struct l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
- uint8_t offset, period, bid;
+ uint8_t offset, period;
trx_sched_ul_func *func;
- enum trx_chan_type chan;
+
+ /* VAMOS: redirect to the shadow timeslot */
+ if (bi->flags & TRX_BI_F_SHADOW_IND)
+ l1ts = l1ts->ts->vamos.peer->priv;
if (!l1ts->mf_index)
return -EINVAL;
@@ -1341,26 +1575,37 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
offset = bi->fn % period;
frame = l1ts->mf_frames + offset;
- chan = frame->ul_chan;
- bid = frame->ul_bid;
- l1cs = &l1ts->chan_state[chan];
- func = trx_chan_desc[chan].ul_fn;
+ bi->chan = frame->ul_chan;
+ bi->bid = frame->ul_bid;
+ l1cs = &l1ts->chan_state[bi->chan];
+ func = trx_chan_desc[bi->chan].ul_fn;
/* check if channel is active */
- if (!TRX_CHAN_IS_ACTIVE(l1cs, chan))
- return -EINVAL;
+ if (!l1cs->active) {
+ /* handle noise measurements on dedicated and idle channels */
+ if (TRX_CHAN_IS_DEDIC(bi->chan) || bi->chan == TRXC_IDLE)
+ trx_sched_noise_meas(l1cs, bi);
+ return 0;
+ }
/* omit bursts which have no handler, like IDLE bursts */
if (!func)
return -EINVAL;
/* calculate how many TDMA frames were potentially lost */
- trx_sched_calc_frame_loss(l1t, l1cs, bi->tn, bi->fn);
+ trx_sched_calc_frame_loss(l1ts, l1cs, bi);
/* update TDMA frame counters */
l1cs->last_tdma_fn = bi->fn;
l1cs->proc_tdma_fs++;
+ /* handle NOPE indications */
+ if (bi->flags & TRX_BI_F_NOPE_IND) {
+ /* NOTE: Uplink burst handler must check bi->burst_len before
+ * accessing bi->burst to avoid uninitialized memory access. */
+ return func(l1ts, bi);
+ }
+
/* decrypt */
if (bi->burst_len && l1cs->ul_encr_algo) {
ubit_t ks[114];
@@ -1376,13 +1621,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
}
/* Invoke the logical channel handler */
- func(l1t, chan, bid, bi);
+ func(l1ts, bi);
return 0;
}
-
-struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn)
-{
- OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts));
- return &l1t->ts[tn];
-}
diff --git a/src/common/scheduler_mframe.c b/src/common/scheduler_mframe.c
index b969407c..60b63531 100644
--- a/src/common/scheduler_mframe.c
+++ b/src/common/scheduler_mframe.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -1000,14 +1000,14 @@ int find_sched_mframe_idx(enum gsm_phys_chan_config pchan, uint8_t tn)
}
/* Determine if given frame number contains SACCH (true) or other (false) burst */
-bool trx_sched_is_sacch_fn(struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink)
+bool trx_sched_is_sacch_fn(const struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink)
{
int i;
const struct trx_sched_multiframe *sched;
const struct trx_sched_frame *frame;
enum trx_chan_type ch_type;
- i = find_sched_mframe_idx(ts->pchan, ts->nr);
+ i = find_sched_mframe_idx(ts_pchan(ts), ts->nr);
if (i < 0)
return -EINVAL;
sched = &trx_sched_multiframes[i];
diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c
index c41f9d6e..48b1a19e 100644
--- a/src/common/sysinfo.c
+++ b/src/common/sysinfo.c
@@ -1,4 +1,4 @@
-/* (C) 2011-2019 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2011-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -18,6 +18,7 @@
*/
#include <stdint.h>
+#include <errno.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/sysinfo.h>
@@ -25,6 +26,8 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_trx.h>
/* properly increment SI2q index and return SI2q data for scheduling */
static inline uint8_t *get_si2q_inc_index(struct gsm_bts *bts)
@@ -96,7 +99,7 @@ uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time)
tc4_sub[tc4_cnt] = SYSINFO_TYPE_2quater;
tc4_cnt += 1;
}
- if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_13)) {
+ if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_13) && pcu_connected()) {
tc4_sub[tc4_cnt] = SYSINFO_TYPE_13;
tc4_cnt += 1;
}
@@ -148,33 +151,37 @@ uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time)
return 0;
}
-uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg)
+uint8_t num_agch(const struct gsm_bts_trx *trx, const char * arg)
{
- struct gsm_bts *b = trx->bts;
- struct gsm48_system_information_type_3 *si3;
+ const struct gsm_bts *b = trx->bts;
+ const struct gsm48_system_information_type_3 *si3;
if (GSM_BTS_HAS_SI(b, SYSINFO_TYPE_3)) {
si3 = GSM_BTS_SI(b, SYSINFO_TYPE_3);
return si3->control_channel_desc.bs_ag_blks_res;
}
- LOGP(DL1P, LOGL_ERROR, "%s: Unable to determine actual BS_AG_BLKS_RES "
+ LOGP(DL1P, LOGL_NOTICE, "%s: Unable to determine actual BS_AG_BLKS_RES "
"value as SI3 is not available yet, fallback to 1\n", arg);
return 1;
}
-/* obtain the next to-be transmitted dowlink SACCH frame (L2 hdr + L3); returns pointer to lchan->si buffer */
-uint8_t *lchan_sacch_get(struct gsm_lchan *lchan)
+/* Returns position of the NCH accroding to SI1 rest octets. See Table 10.5.2.32.1 of TS 44.018.
+ * Returns < 0, if not present. */
+int pos_nch(const struct gsm_bts_trx *trx, const char *arg)
{
- uint32_t tmp, i;
-
- for (i = 0; i < _MAX_SYSINFO_TYPE; i++) {
- tmp = (lchan->si.last + 1 + i) % _MAX_SYSINFO_TYPE;
- if (!(lchan->si.valid & (1 << tmp)))
- continue;
- lchan->si.last = tmp;
- return GSM_LCHAN_SI(lchan, tmp);
+ const struct gsm_bts *b = trx->bts;
+ const struct gsm48_system_information_type_1 *si1;
+
+ if (GSM_BTS_HAS_SI(b, SYSINFO_TYPE_1)) {
+ si1 = GSM_BTS_SI(b, SYSINFO_TYPE_1);
+ if (si1->rest_octets[0] & 0x80) {
+ /* H <NCH Position : bit (5)> */
+ return (si1->rest_octets[0] >> 2) & 0x1f;
+ }
+ return -ENOTSUP;
}
- LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "SACCH no SI available\n");
- return NULL;
+ LOGP(DL1P, LOGL_NOTICE, "%s: Unable to determine actual NCH Position "
+ "value as SI1 is not available yet.\n", arg);
+ return -EINVAL;
}
/* re-generate SI3 restoctets with GPRS indicator depending on the PCU socket connection state */
@@ -195,17 +202,79 @@ void regenerate_si3_restoctets(struct gsm_bts *bts)
/* Create a temporary copy and patch that, if no PCU is around */
si3ro_tmp = bts->si3_ro_decoded;
if (!pcu_connected()) {
- if (!bts->si3_gprs_ind_disabled)
- LOGP(DPCU, LOGL_NOTICE, "Disabling GPRS Indicator in SI3 (No PCU connected)\n");
- bts->si3_gprs_ind_disabled = true;
+ if (!bts->si_gprs_ind_disabled)
+ LOGP(DPCU, LOGL_NOTICE, "Disabling GPRS Indicator in SI (No PCU connected)\n");
+ bts->si_gprs_ind_disabled = true;
si3ro_tmp.gprs_ind.present = 0;
} else {
- if (bts->si3_gprs_ind_disabled)
- LOGP(DPCU, LOGL_NOTICE, "Enabling GPRS Indicator in SI3 (PCU connected)\n");
- bts->si3_gprs_ind_disabled = false;
+ if (bts->si_gprs_ind_disabled)
+ LOGP(DPCU, LOGL_NOTICE, "Enabling GPRS Indicator in SI (PCU connected)\n");
+ bts->si_gprs_ind_disabled = false;
si3ro_tmp.gprs_ind.present = 1; /* is a no-op as we copy from bts->si3_ro_decoded */
}
/* re-generate the binary SI3 rest octets */
osmo_gsm48_rest_octets_si3_encode(si3_buf + si3_size, &si3ro_tmp);
}
+
+/* get the offset of the SI4 rest octets */
+int get_si4_ro_offset(const uint8_t *si4_buf)
+{
+ const struct gsm48_system_information_type_4 *si4 =
+ (const struct gsm48_system_information_type_4 *) si4_buf;
+ int si4_size;
+
+ /* start with the length of the mandatory part */
+ si4_size = offsetof(struct gsm48_system_information_type_4, data);
+ /* then add optional parts, if any */
+ if (si4->data[0] == GSM48_IE_CBCH_CHAN_DESC) {
+ /* fixed 4-byte TV IE, see Table 9.1.36.1 of TS 44.018 */
+ si4_size += 4;
+ if (si4->data[4] == GSM48_IE_CBCH_MOB_AL)
+ si4_size += TLV_GROSS_LEN(si4->data[5]);
+ }
+
+ if (si4_size >= GSM_MACBLOCK_LEN)
+ return -EINVAL;
+
+ return si4_size;
+}
+
+/* re-generate SI4 restoctets with GPRS indicator depending on the PCU socket connection state */
+void regenerate_si4_restoctets(struct gsm_bts *bts)
+{
+ uint8_t *si4_buf = GSM_BTS_SI(bts, SYSINFO_TYPE_4);
+ struct osmo_gsm48_si_ro_info si4ro_tmp;
+ int si4_size;
+
+ /* If BSC has never set SI4, there's nothing to patch */
+ if (!GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_4))
+ return;
+
+ /* If SI4 from BSC doesn't have a GPRS indicator, we won't have anything to patch */
+ if (!bts->si4_ro_decoded.gprs_ind.present)
+ return;
+
+ si4_size = get_si4_ro_offset(si4_buf);
+ if (si4_size < 0) {
+ LOGP(DPCU, LOGL_ERROR, "Cannot parse SI4, hence not patching GPRS indicator\n");
+ return;
+ }
+
+ /* Create a temporary copy and patch that, if no PCU is around */
+ si4ro_tmp = bts->si4_ro_decoded;
+ if (!pcu_connected()) {
+ if (!bts->si_gprs_ind_disabled)
+ LOGP(DPCU, LOGL_NOTICE, "Disabling GPRS Indicator in SI (No PCU connected)\n");
+ bts->si_gprs_ind_disabled = true;
+ si4ro_tmp.gprs_ind.present = 0;
+ } else {
+ if (bts->si_gprs_ind_disabled)
+ LOGP(DPCU, LOGL_NOTICE, "Enabling GPRS Indicator in SI (PCU connected)\n");
+ bts->si_gprs_ind_disabled = false;
+ si4ro_tmp.gprs_ind.present = 1; /* is a no-op as we copy from bts->si4_ro_decoded */
+ }
+
+ /* re-generate the binary SI4 rest octets */
+ osmo_gsm48_rest_octets_si4_encode(si4_buf + si4_size, &si4ro_tmp, GSM_MACBLOCK_LEN - si4_size);
+}
diff --git a/src/common/ta_control.c b/src/common/ta_control.c
new file mode 100644
index 00000000..6fe409a2
--- /dev/null
+++ b/src/common/ta_control.c
@@ -0,0 +1,102 @@
+/* Loop control for Timing Advance */
+
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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/>.
+ *
+ */
+
+/* Related specs: 3GPP TS 45.010 sections 5.5, 5.6 */
+
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_trx.h>
+#include <osmo-bts/logging.h>
+
+/* 3GPP TS 45.010 sec 5.6.3 Delay assessment error:
+ * 75% of one bit duration in 1/256 symbols: 256*0.75 */
+#define TOA256_THRESH 192
+
+/* rqd_ta value range */
+#define TA_MIN 0
+#define TA_MAX 63
+
+/* TODO: make configurable over osmo-bts VTY? Pass it BSC->BTS? */
+#define TA_MAX_INC_STEP 2
+#define TA_MAX_DEC_STEP 2
+
+
+/*! compute the new "Ordered Timing Advance" communicated to the MS and store it in lchan.
+ * \param lchan logical channel for which to compute (and in which to store) new power value.
+ * \param[in] ms_tx_ta The TA used by the MS and reported in L1SACCH, see struct gsm_sacch_l1_hdr field "ta".
+ * \param[in] toa256 Time of Arrival (in 1/256th bits) computed at Rx side
+ */
+void lchan_ms_ta_ctrl(struct gsm_lchan *lchan, uint8_t ms_tx_ta, int16_t toa256)
+{
+ int16_t new_ta;
+ /* Shall we skip current block based on configured interval? */
+
+ /* TA control interval: how many blocks do we skip? */
+ if (lchan->ta_ctrl.skip_block_num-- > 0)
+ return;
+
+ /* Reset the number of SACCH blocks to be skipped:
+ * ctrl_interval=0 => 0 blocks to skip,
+ * ctrl_interval=1 => 1 blocks to skip,
+ * ctrl_interval=2 => 3 blocks to skip,
+ * so basically ctrl_interval * 2 - 1. */
+ lchan->ta_ctrl.skip_block_num = lchan->ts->trx->ta_ctrl_interval * 2 - 1;
+
+ int16_t delta_ta = toa256/256;
+ if (toa256 >= 0) {
+ if ((toa256 - (256 * delta_ta)) > TOA256_THRESH)
+ delta_ta++;
+ if (delta_ta > TA_MAX_INC_STEP)
+ delta_ta = TA_MAX_INC_STEP;
+ } else {
+ if ((toa256 - (256 * delta_ta)) < -TOA256_THRESH)
+ delta_ta--;
+ if (delta_ta < -TA_MAX_DEC_STEP)
+ delta_ta = -TA_MAX_DEC_STEP;
+ }
+
+ new_ta = ms_tx_ta + delta_ta;
+
+ /* Make sure new_ta is never negative: */
+ if (new_ta < TA_MIN)
+ new_ta = TA_MIN;
+
+ /* Don't ask for out of range TA: */
+ if (new_ta > TA_MAX)
+ new_ta = TA_MAX;
+
+ if (lchan->ta_ctrl.current == (uint8_t)new_ta) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG,
+ "Keeping current TA at %u: TOA was %d\n",
+ lchan->ta_ctrl.current, toa256);
+ return;
+ }
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO,
+ "%s TA %u => %u: TOA was too %s (%d)\n",
+ (uint8_t)new_ta > lchan->ta_ctrl.current ? "Raising" : "Lowering",
+ lchan->ta_ctrl.current, (uint8_t)new_ta,
+ (uint8_t)new_ta > lchan->ta_ctrl.current ? "late" : "early",
+ toa256);
+
+ /* store the resulting new TA in the lchan */
+ lchan->ta_ctrl.current = (uint8_t)new_ta;
+}
diff --git a/src/common/tx_power.c b/src/common/tx_power.c
index e418cec5..83cdb629 100644
--- a/src/common/tx_power.c
+++ b/src/common/tx_power.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -29,6 +29,7 @@
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/tx_power.h>
+#include <osmo-bts/bts_trx.h>
static int get_pa_drive_level_mdBm(const struct power_amp *pa,
int desired_p_out_mdBm, unsigned int arfcn)
@@ -42,16 +43,16 @@ static int get_pa_drive_level_mdBm(const struct power_amp *pa,
}
/* maximum output power of the system */
-int get_p_max_out_mdBm(struct gsm_bts_trx *trx)
+int get_p_max_out_mdBm(const struct gsm_bts_trx *trx)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
/* Add user gain, internal and external PA gain to TRX output power */
return tpp->trx_p_max_out_mdBm + tpp->user_gain_mdB +
tpp->pa.nominal_gain_mdB + tpp->user_pa.nominal_gain_mdB;
}
/* nominal output power, i.e. OML-reduced maximum output power */
-int get_p_nominal_mdBm(struct gsm_bts_trx *trx)
+int get_p_nominal_mdBm(const struct gsm_bts_trx *trx)
{
/* P_max_out subtracted by OML maximum power reduction IE */
return get_p_max_out_mdBm(trx) - to_mdB(trx->max_power_red);
@@ -60,21 +61,21 @@ int get_p_nominal_mdBm(struct gsm_bts_trx *trx)
/* calculate the target total output power required, reduced by both
* OML and RSL, but ignoring the attenuation required for power ramping and
* thermal management */
-int get_p_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie)
+int get_p_target_mdBm(const struct gsm_bts_trx *trx, uint8_t bs_power_red)
{
- /* Pn subtracted by RSL BS Power IE (in 2 dB steps) */
- return get_p_nominal_mdBm(trx) - to_mdB(bs_power_ie * 2);
+ /* Pn subtracted by RSL BS Power Recudtion (in 1 dB steps) */
+ return get_p_nominal_mdBm(trx) - to_mdB(bs_power_red);
}
-int get_p_target_mdBm_lchan(struct gsm_lchan *lchan)
+int get_p_target_mdBm_lchan(const struct gsm_lchan *lchan)
{
- return get_p_target_mdBm(lchan->ts->trx, lchan->bs_power);
+ return get_p_target_mdBm(lchan->ts->trx, lchan->bs_power_ctrl.current);
}
/* calculate the actual total output power required, taking into account the
* attenuation required for power ramping but not thermal management */
-int get_p_actual_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+int get_p_actual_mdBm(const struct gsm_bts_trx *trx, int p_target_mdBm)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
/* P_target subtracted by ramp attenuation */
return p_target_mdBm - tpp->ramp.attenuation_mdB;
@@ -82,9 +83,9 @@ int get_p_actual_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
/* calculate the effective total output power required, taking into account the
* attenuation required for power ramping and thermal management */
-int get_p_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+int get_p_eff_mdBm(const struct gsm_bts_trx *trx, int p_target_mdBm)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
/* P_target subtracted by ramp attenuation */
return p_target_mdBm - tpp->ramp.attenuation_mdB - tpp->thermal_attenuation_mdB;
@@ -92,9 +93,9 @@ int get_p_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
/* calculate effect TRX output power required, taking into account the
* attenuations required for power ramping and thermal management */
-int get_p_trxout_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+int get_p_trxout_eff_mdBm(const struct gsm_bts_trx *trx, int p_target_mdBm)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
int p_actual_mdBm, user_pa_drvlvl_mdBm, pa_drvlvl_mdBm;
unsigned int arfcn = trx->arfcn;
@@ -113,14 +114,14 @@ int get_p_trxout_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
/* calculate target TRX output power required, ignoring the
* attenuations required for power ramping but not thermal management */
-int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie)
+int get_p_trxout_target_mdBm(const struct gsm_bts_trx *trx, uint8_t bs_power_red)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
int p_target_mdBm, user_pa_drvlvl_mdBm, pa_drvlvl_mdBm;
unsigned int arfcn = trx->arfcn;
/* P_target subtracted by any bulk gain added by the user */
- p_target_mdBm = get_p_target_mdBm(trx, bs_power_ie) - tpp->user_gain_mdB;
+ p_target_mdBm = get_p_target_mdBm(trx, bs_power_red) - tpp->user_gain_mdB;
/* determine input drive level required at input to user PA */
user_pa_drvlvl_mdBm = get_pa_drive_level_mdBm(&tpp->user_pa, p_target_mdBm, arfcn);
@@ -131,9 +132,9 @@ int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie)
/* internal PA input drive level is TRX output power */
return pa_drvlvl_mdBm;
}
-int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan)
+int get_p_trxout_target_mdBm_lchan(const struct gsm_lchan *lchan)
{
- return get_p_trxout_target_mdBm(lchan->ts->trx, lchan->bs_power);
+ return get_p_trxout_target_mdBm(lchan->ts->trx, lchan->bs_power_ctrl.current);
}
@@ -146,9 +147,9 @@ int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan)
* attempting to register at the same time. Rather, grow the cell slowly in
* radius than start with the full radius at once. */
-static int we_are_ramping_up(struct gsm_bts_trx *trx)
+static int we_are_ramping_up(const struct gsm_bts_trx *trx)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
if (tpp->p_total_tgt_mdBm > tpp->p_total_cur_mdBm)
return 1;
@@ -171,13 +172,13 @@ static void power_ramp_timer_cb(void *_trx)
/* compute new effective (= minus ramp and thermal attenuation) TRX output required */
p_trxout_eff_mdBm = get_p_trxout_eff_mdBm(trx, tpp->p_total_tgt_mdBm);
- LOGP(DL1C, LOGL_DEBUG, "ramp_timer_cb(cur_pout=%d, tgt_pout=%d, "
+ LOGPTRX(trx, DL1C, LOGL_DEBUG, "ramp_timer_cb(cur_pout=%d, tgt_pout=%d, "
"ramp_att=%d, therm_att=%d, user_gain=%d)\n",
tpp->p_total_cur_mdBm, tpp->p_total_tgt_mdBm,
tpp->ramp.attenuation_mdB, tpp->thermal_attenuation_mdB,
tpp->user_gain_mdB);
- LOGP(DL1C, LOGL_INFO,
+ LOGPTRX(trx, DL1C, LOGL_INFO,
"ramping TRX board output power to %d mdBm.\n", p_trxout_eff_mdBm);
/* Instruct L1 to apply new effective TRX output power required */
@@ -196,9 +197,9 @@ void power_trx_change_compl(struct gsm_bts_trx *trx, int p_trxout_cur_mdBm)
/* for now we simply write an error message, but in the future
* we might use the value (again) as part of our math? */
if (p_trxout_cur_mdBm != p_trxout_should_mdBm) {
- LOGP(DL1C, LOGL_ERROR, "bts_model notifies us of %u mdBm TRX "
- "output power. However, it should be %u mdBm!\n",
- p_trxout_cur_mdBm, p_trxout_should_mdBm);
+ LOGPTRX(trx, DL1C, LOGL_ERROR, "bts_model notifies us of %d mdBm TRX "
+ "output power. However, it should be %d mdBm!\n",
+ p_trxout_cur_mdBm, p_trxout_should_mdBm);
}
/* and do another step... */
@@ -210,8 +211,11 @@ static void power_ramp_do_step(struct gsm_bts_trx *trx, int first)
struct trx_power_params *tpp = &trx->power_params;
/* we had finished in last loop iteration */
- if (!first && tpp->ramp.attenuation_mdB == 0)
+ if (!first && tpp->ramp.attenuation_mdB == 0) {
+ if (tpp->ramp.compl_cb)
+ tpp->ramp.compl_cb(trx);
return;
+ }
if (we_are_ramping_up(trx)) {
/* ramp up power -> ramp down attenuation */
@@ -235,8 +239,7 @@ static void power_ramp_do_step(struct gsm_bts_trx *trx, int first)
osmo_timer_schedule(&tpp->ramp.step_timer, tpp->ramp.step_interval_sec, 0);
}
-
-int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass)
+int _power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass, ramp_compl_cb_t ramp_compl_cb, bool skip_ramping)
{
struct trx_power_params *tpp = &trx->power_params;
@@ -244,35 +247,43 @@ int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass)
* the maximum total system power subtracted by OML as well as RSL
* reductions */
- LOGP(DL1C, LOGL_INFO, "power_ramp_start(cur=%d, tgt=%d)\n",
- tpp->p_total_cur_mdBm, p_total_tgt_mdBm);
+ LOGPTRX(trx, DL1C, LOGL_INFO, "power_ramp_start(cur=%d, tgt=%d%s)\n",
+ tpp->p_total_cur_mdBm, p_total_tgt_mdBm, bypass ? ", bypass" : "");
if (!bypass && (p_total_tgt_mdBm > get_p_nominal_mdBm(trx))) {
- LOGP(DL1C, LOGL_ERROR, "Asked to ramp power up to "
- "%d mdBm, which exceeds P_max_out (%d)\n",
- p_total_tgt_mdBm, get_p_nominal_mdBm(trx));
+ LOGPTRX(trx, DL1C, LOGL_ERROR, "Asked to ramp power up to "
+ "%d mdBm, which exceeds P_max_out (%d)\n",
+ p_total_tgt_mdBm, get_p_nominal_mdBm(trx));
return -ERANGE;
}
/* Cancel any pending request */
- osmo_timer_del(&tpp->ramp.step_timer);
+ power_ramp_abort(trx);
/* set the new target */
tpp->p_total_tgt_mdBm = p_total_tgt_mdBm;
-
- if (we_are_ramping_up(trx)) {
+ tpp->ramp.compl_cb = ramp_compl_cb;
+
+ if (skip_ramping) {
+ /* Jump straight to the target power */
+ tpp->p_total_cur_mdBm = p_total_tgt_mdBm;
+ tpp->ramp.attenuation_mdB = 0;
+ power_ramp_timer_cb(trx);
+ } else if (we_are_ramping_up(trx)) {
if (tpp->p_total_tgt_mdBm <= tpp->ramp.max_initial_pout_mdBm) {
- LOGP(DL1C, LOGL_INFO,
- "target_power(%d) is below max.initial power\n",
- tpp->p_total_tgt_mdBm);
+ LOGPTRX(trx, DL1C, LOGL_INFO,
+ "target_power (%d mdBm) is below or equal to 'power ramp max-initial' power (%d mdBm)\n",
+ tpp->p_total_tgt_mdBm, tpp->ramp.max_initial_pout_mdBm);
/* new setting is below the maximum initial output
* power, so we can directly jump to this level */
tpp->p_total_cur_mdBm = tpp->p_total_tgt_mdBm;
tpp->ramp.attenuation_mdB = 0;
power_ramp_timer_cb(trx);
} else {
- /* We need to step it up. Start from the current value */
+ /* We need to step it up. Start from the current value, shortcutting to max-initial. */
/* Set attenuation to cause no power change right now */
+ if (tpp->p_total_cur_mdBm + (int)tpp->ramp.step_size_mdB < tpp->ramp.max_initial_pout_mdBm)
+ tpp->p_total_cur_mdBm = tpp->ramp.max_initial_pout_mdBm - tpp->ramp.step_size_mdB;
tpp->ramp.attenuation_mdB = tpp->p_total_tgt_mdBm - tpp->p_total_cur_mdBm;
/* start with the first step */
@@ -290,10 +301,16 @@ int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass)
return 0;
}
+/* Cancel any pending request */
+void power_ramp_abort(struct gsm_bts_trx *trx)
+{
+ osmo_timer_del(&trx->power_params.ramp.step_timer);
+}
+
/* determine the initial transceiver output power at start-up time */
-int power_ramp_initial_power_mdBm(struct gsm_bts_trx *trx)
+int power_ramp_initial_power_mdBm(const struct gsm_bts_trx *trx)
{
- struct trx_power_params *tpp = &trx->power_params;
+ const struct trx_power_params *tpp = &trx->power_params;
int pout_mdBm;
/* this is the maximum initial output on the antenna connector
diff --git a/src/common/vty.c b/src/common/vty.c
index 801f34c0..c0008a85 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -22,10 +22,12 @@
#include "btsconfig.h"
#include <inttypes.h>
+#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
+#include <errno.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/abis_nm.h>
@@ -36,16 +38,20 @@
#include <osmocom/vty/logging.h>
#include <osmocom/vty/misc.h>
#include <osmocom/vty/ports.h>
+#include <osmocom/vty/tdef_vty.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/sockaddr_str.h>
#include <osmocom/trau/osmo_ortp.h>
-
+#include <osmocom/core/fsm.h>
+#include <osmocom/codec/codec.h>
#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/bts_sm.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/signal.h>
@@ -54,6 +60,7 @@
#include <osmo-bts/measurement.h>
#include <osmo-bts/vty.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/osmux.h>
#define VTY_STR "Configure the VTY\n"
@@ -64,23 +71,45 @@
#define BTS_TRX_STR BTS_NR_STR TRX_NR_STR
#define BTS_TRX_TS_STR BTS_TRX_STR TS_NR_STR
#define BTS_TRX_TS_LCHAN_STR BTS_TRX_TS_STR LCHAN_NR_STR
+/* INT32_MAX, because osmo_wqueue_init takes int as an argument
+ * and INT_MAX can't be stringified as a decimal */
+#define BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX 2147483647
+
+#define X(x) (1 << x)
int g_vty_port_num = OSMO_VTY_PORT_BTS;
+static const struct value_string gsmtap_sapi_names[] = {
+ { GSMTAP_CHANNEL_BCCH, "BCCH" },
+ { GSMTAP_CHANNEL_CCCH, "CCCH" },
+ { GSMTAP_CHANNEL_RACH, "RACH" },
+ { GSMTAP_CHANNEL_AGCH, "AGCH" },
+ { GSMTAP_CHANNEL_PCH, "PCH" },
+ { GSMTAP_CHANNEL_SDCCH, "SDCCH" },
+ { GSMTAP_CHANNEL_TCH_F, "TCH/F" },
+ { GSMTAP_CHANNEL_TCH_H, "TCH/H" },
+ { GSMTAP_CHANNEL_PACCH, "PACCH" },
+ { GSMTAP_CHANNEL_PDCH, "PDTCH" },
+ { GSMTAP_CHANNEL_PTCCH, "PTCCH" },
+ { GSMTAP_CHANNEL_CBCH51,"CBCH" },
+ { GSMTAP_CHANNEL_ACCH, "SACCH" },
+ { 0, NULL }
+};
+
struct phy_instance *vty_get_phy_instance(struct vty *vty, int phy_nr, int inst_nr)
{
struct phy_link *plink = phy_link_by_num(phy_nr);
struct phy_instance *pinst;
if (!plink) {
- vty_out(vty, "Cannot find PHY link number %d%s",
+ vty_out(vty, "%% Cannot find PHY link number %d%s",
phy_nr, VTY_NEWLINE);
return NULL;
}
pinst = phy_instance_by_num(plink, inst_nr);
if (!pinst) {
- vty_out(vty, "Cannot find PHY instance number %d%s",
+ vty_out(vty, "%% Cannot find PHY instance number %d%s",
inst_nr, VTY_NEWLINE);
return NULL;
}
@@ -111,63 +140,9 @@ int bts_vty_go_parent(struct vty *vty)
return vty->node;
}
-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;
- }
-}
-
-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;
- {
- struct gsm_bts_trx *trx = vty->index;
- vty->index = trx->bts;
- }
- break;
- default:
- break;
- }
- return CMD_SUCCESS;
-}
-
-gDEFUN(ournode_end, ournode_end_cmd, "end",
- "End current mode and change to enable mode")
-{
- switch (vty->node) {
- default:
- vty_config_unlock(vty);
- vty->node = ENABLE_NODE;
- vty->index = NULL;
- vty->index_sub = NULL;
- break;
- }
- return CMD_SUCCESS;
-}
-
static const char osmobts_copyright[] =
- "Copyright (C) 2010, 2011 by Harald Welte, Andreas Eversberg and On-Waves\r\n"
+ "Copyright (C) 2010-2011 by Harald Welte, Andreas Eversberg and On-Waves\r\n"
+ "Copyright (C) 2011-2022 by sysmocom - s.f.m.c. GmbH\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
@@ -177,16 +152,18 @@ struct vty_app_info bts_vty_info = {
.version = PACKAGE_VERSION,
.copyright = osmobts_copyright,
.go_parent_cb = bts_vty_go_parent,
- .is_config_node = bts_vty_is_config_node,
+ .usr_attr_desc = {
+ [BTS_VTY_ATTR_NEW_LCHAN] = \
+ "This command applies for newly created lchans",
+ [BTS_VTY_TRX_POWERCYCLE] = \
+ "This command applies when the TRX powercycles or restarts",
+ },
+ .usr_attr_letters = {
+ [BTS_VTY_ATTR_NEW_LCHAN] = 'l',
+ [BTS_VTY_TRX_POWERCYCLE] = 'p',
+ },
};
-extern struct gsm_network bts_gsmnet;
-
-struct gsm_network *gsmnet_from_vty(struct vty *v)
-{
- return &bts_gsmnet;
-}
-
static struct cmd_node bts_node = {
BTS_NODE,
"%s(bts)# ",
@@ -199,6 +176,12 @@ static struct cmd_node trx_node = {
1,
};
+static struct cmd_node osmux_node = {
+ OSMUX_NODE,
+ "%s(osmux)# ",
+ 1,
+};
+
gDEFUN(cfg_bts_auto_band, cfg_bts_auto_band_cmd,
"auto-band",
"Automatically select band for ARFCN based on configured band\n")
@@ -219,10 +202,94 @@ gDEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd,
return CMD_SUCCESS;
}
+DEFUN_ATTR(cfg_bts_osmux, cfg_bts_osmux_cmd,
+ "osmux",
+ "Configure Osmux\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ vty->node = OSMUX_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_osmux_use, cfg_bts_osmux_use_cmd,
+ "use (off|on|only)",
+ "Configure Osmux usage\n"
+ "Never use Osmux\n"
+ "Use Osmux if requested by BSC (default)\n"
+ "Always use Osmux, reject non-Osmux BSC requests\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+ if (strcmp(argv[0], "off") == 0)
+ bts->osmux.use = OSMUX_USAGE_OFF;
+ else if (strcmp(argv[0], "on") == 0)
+ bts->osmux.use = OSMUX_USAGE_ON;
+ else if (strcmp(argv[0], "only") == 0)
+ bts->osmux.use = OSMUX_USAGE_ONLY;
+ return CMD_SUCCESS;
+}
-DEFUN(cfg_bts_trx, cfg_bts_trx_cmd,
- "trx <0-254>",
- "Select a TRX to configure\n" "TRX number\n")
+DEFUN(cfg_bts_osmux_ip,
+ cfg_bts_osmux_ip_cmd,
+ "local-ip " VTY_IPV46_CMD,
+ IP_STR
+ "IPv4 Address to bind to\n"
+ "IPv6 Address to bind to\n")
+{
+ struct gsm_bts *bts = vty->index;
+ osmo_talloc_replace_string(bts, &bts->osmux.local_addr, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_osmux_port,
+ cfg_bts_osmux_port_cmd,
+ "local-port <1-65535>",
+ "Osmux port\n" "UDP port\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->osmux.local_port = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_osmux_batch_factor,
+ cfg_bts_osmux_batch_factor_cmd,
+ "batch-factor <1-8>",
+ "Batching factor\n" "Number of messages in the batch\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->osmux.batch_factor = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_osmux_batch_size,
+ cfg_bts_osmux_batch_size_cmd,
+ "batch-size <1-65535>",
+ "Batch size\n" "Batch size in bytes\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->osmux.batch_size = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_osmux_dummy_padding,
+ cfg_bts_osmux_dummy_padding_cmd,
+ "dummy-padding (on|off)",
+ "Dummy padding\n"
+ "Enable dummy padding\n"
+ "Disable dummy padding (default)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ if (strcmp(argv[0], "on") == 0)
+ bts->osmux.dummy_padding = true;
+ else if (strcmp(argv[0], "off") == 0)
+ bts->osmux.dummy_padding = false;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_trx, cfg_bts_trx_cmd,
+ "trx <0-254>",
+ "Select a TRX to configure\n" "TRX number\n",
+ CMD_ATTR_IMMEDIATE)
{
int trx_nr = atoi(argv[0]);
struct gsm_bts *bts = vty->index;
@@ -240,7 +307,7 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd,
*/
trx = gsm_bts_trx_alloc(bts);
if (trx)
- bts_trx_init(trx);
+ bts_model_trx_init(trx);
} else
trx = gsm_bts_trx_num(bts, trx_nr);
@@ -257,11 +324,66 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd,
return CMD_SUCCESS;
}
-static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
+static void config_write_dpc_params(struct vty *vty, const char *prefix,
+ const struct gsm_power_ctrl_params *params)
{
- struct gsm_bts_trx *trx;
+ const struct gsm_power_ctrl_meas_params *mp = &params->rxlev_meas;
+
+ if (mp->lower_thresh != power_ctrl_params_def.rxlev_meas.lower_thresh ||
+ mp->upper_thresh != power_ctrl_params_def.rxlev_meas.upper_thresh) {
+ int target = (mp->lower_thresh + mp->upper_thresh) / 2;
+ int hyst = (mp->upper_thresh - mp->lower_thresh) / 2;
+
+ vty_out(vty, " %s-power-target %d", prefix, rxlev2dbm(target));
+ if (hyst > 0)
+ vty_out(vty, " hysteresis %d", hyst);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ /* MS Tx power filtering algorithm and parameters */
+ switch (mp->algo) {
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA: /* EWMA is the default */
+ if (mp->ewma.alpha != power_ctrl_params_def.rxlev_meas.ewma.alpha)
+ vty_out(vty, " %s-power-filtering algo ewma beta %u%s",
+ prefix, 100 - mp->ewma.alpha, VTY_NEWLINE);
+ break;
+ /* Other algorithm cannot be set via the VTY */
+ case BTS_PF_ALGO_NONE:
+ default:
+ vty_out(vty, " no %s-power-filtering%s", prefix, VTY_NEWLINE);
+ break;
+ }
+}
+
+static void config_write_osmux(struct vty *vty, const char *prefix, const struct gsm_bts *bts)
+{
+ vty_out(vty, "%sosmux%s", prefix, VTY_NEWLINE);
+ vty_out(vty, "%s use ", prefix);
+ switch (bts->osmux.use) {
+ case OSMUX_USAGE_ON:
+ vty_out(vty, "on%s", VTY_NEWLINE);
+ break;
+ case OSMUX_USAGE_ONLY:
+ vty_out(vty, "only%s", VTY_NEWLINE);
+ break;
+ case OSMUX_USAGE_OFF:
+ default:
+ vty_out(vty, "off%s", VTY_NEWLINE);
+ break;
+ }
+ vty_out(vty, "%s local-ip %s%s", prefix, bts->osmux.local_addr, VTY_NEWLINE);
+ vty_out(vty, "%s local-port %u%s", prefix, bts->osmux.local_port, VTY_NEWLINE);
+ vty_out(vty, "%s batch-factor %d%s", prefix, bts->osmux.batch_factor, VTY_NEWLINE);
+ vty_out(vty, "%s batch-size %u%s", prefix, bts->osmux.batch_size, VTY_NEWLINE);
+ vty_out(vty, "%s dummy-padding %s%s", prefix, bts->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
+}
+
+static void config_write_bts_single(struct vty *vty, const struct gsm_bts *bts)
+{
+ const struct gsm_bts_trx *trx;
const char *sapi_buf;
int i;
+ struct bsc_oml_host *bsc_oml_host;
vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE);
if (bts->description)
@@ -271,18 +393,32 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " auto-band%s", VTY_NEWLINE);
vty_out(vty, " ipa unit-id %u %u%s",
bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
- vty_out(vty, " oml remote-ip %s%s", bts->bsc_oml_host, VTY_NEWLINE);
+ llist_for_each_entry(bsc_oml_host, &bts->bsc_oml_hosts, list)
+ vty_out(vty, " oml remote-ip %s%s", bsc_oml_host->addr, VTY_NEWLINE);
vty_out(vty, " rtp jitter-buffer %u", bts->rtp_jitter_buf_ms);
if (bts->rtp_jitter_adaptive)
vty_out(vty, " adaptive");
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " rtp port-range %u %u%s", bts->rtp_port_range_start,
bts->rtp_port_range_end, VTY_NEWLINE);
+ if (bts->rtp_ip_dscp != -1)
+ vty_out(vty, " rtp ip-dscp %d%s", bts->rtp_ip_dscp, VTY_NEWLINE);
+ if (bts->rtp_priority != -1)
+ vty_out(vty, " rtp socket-priority %d%s", bts->rtp_priority, VTY_NEWLINE);
+ if (bts->rtp_nogaps_mode)
+ vty_out(vty, " rtp continuous-streaming%s", VTY_NEWLINE);
+ vty_out(vty, " %srtp internal-uplink-ecu%s",
+ bts->use_ul_ecu ? "" : "no ", VTY_NEWLINE);
+ vty_out(vty, " rtp hr-format %s%s",
+ bts->emit_hr_rfc5993 ? "rfc5993" : "ts101318", VTY_NEWLINE);
vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(bts->paging_state),
VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(bts->paging_state),
VTY_NEWLINE);
- vty_out(vty, " uplink-power-target %d%s", bts->ul_power_target, VTY_NEWLINE);
+
+ /* Fall-back MS Power Control parameters may be changed by the user */
+ config_write_dpc_params(vty, "uplink", &bts->ms_dpc_params);
+
if (bts->agch_queue.thresh_level != GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT
|| bts->agch_queue.low_level != GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT
|| bts->agch_queue.high_level != GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT)
@@ -290,16 +426,33 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
bts->agch_queue.thresh_level, bts->agch_queue.low_level,
bts->agch_queue.high_level, VTY_NEWLINE);
- for (i = 0; i < 32; i++) {
- if (gsmtap_sapi_mask & (1 << i)) {
- sapi_buf = osmo_str_tolower(get_value_string(gsmtap_sapi_names, i));
+ if (bts->gsmtap.remote_host != NULL)
+ vty_out(vty, " gsmtap-remote-host %s%s",
+ bts->gsmtap.remote_host,
+ VTY_NEWLINE);
+ if (bts->gsmtap.local_host != NULL)
+ vty_out(vty, " gsmtap-local-host %s%s",
+ bts->gsmtap.local_host,
+ VTY_NEWLINE);
+ for (i = 0; i < sizeof(uint32_t) * 8; i++) {
+ if (bts->gsmtap.sapi_mask & ((uint32_t) 1 << i)) {
+ sapi_buf = get_value_string_or_null(gsmtap_sapi_names, i);
+ if (sapi_buf == NULL)
+ continue;
+ sapi_buf = osmo_str_tolower(sapi_buf);
vty_out(vty, " gsmtap-sapi %s%s", sapi_buf, VTY_NEWLINE);
}
}
- if (gsmtap_sapi_acch) {
+ if (bts->gsmtap.sapi_acch) {
sapi_buf = osmo_str_tolower(get_value_string(gsmtap_sapi_names, GSMTAP_CHANNEL_ACCH));
vty_out(vty, " gsmtap-sapi %s%s", sapi_buf, VTY_NEWLINE);
}
+ if (bts->gsmtap.rlp) {
+ if (bts->gsmtap.rlp_skip_null)
+ vty_out(vty, " gsmtap-rlp skip-null%s", VTY_NEWLINE);
+ else
+ vty_out(vty, " gsmtap-rlp%s", VTY_NEWLINE);
+ }
vty_out(vty, " min-qual-rach %d%s", bts->min_qual_rach,
VTY_NEWLINE);
vty_out(vty, " min-qual-norm %d%s", bts->min_qual_norm,
@@ -308,20 +461,24 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
if (strcmp(bts->pcu.sock_path, PCU_SOCK_DEFAULT))
vty_out(vty, " pcu-socket %s%s", bts->pcu.sock_path, VTY_NEWLINE);
+ if (bts->pcu.sock_wqueue_len_max != BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX)
+ vty_out(vty, " pcu-socket-wqueue-length %u%s", bts->pcu.sock_wqueue_len_max, VTY_NEWLINE);
if (bts->supp_meas_toa256)
vty_out(vty, " supp-meas-info toa256%s", VTY_NEWLINE);
vty_out(vty, " smscb queue-max-length %d%s", bts->smscb_queue_max_len, VTY_NEWLINE);
vty_out(vty, " smscb queue-target-length %d%s", bts->smscb_queue_tgt_len, VTY_NEWLINE);
vty_out(vty, " smscb queue-hysteresis %d%s", bts->smscb_queue_hyst, VTY_NEWLINE);
+ config_write_osmux(vty, " ", bts);
+
bts_model_config_write_bts(vty, 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);
+ const struct trx_power_params *tpp = &trx->power_params;
+ const 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)
+ if (tpp->user_gain_mdB)
vty_out(vty, " user-gain %u mdB%s",
tpp->user_gain_mdB, VTY_NEWLINE);
vty_out(vty, " power-ramp max-initial %d mdBm%s",
@@ -331,8 +488,10 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " power-ramp step-interval %d%s",
tpp->ramp.step_interval_sec, VTY_NEWLINE);
vty_out(vty, " ms-power-control %s%s",
- trx->ms_power_control == 0 ? "dsp" : "osmo",
+ trx->ms_pwr_ctl_soft ? "osmo" : "dsp",
VTY_NEWLINE);
+ vty_out(vty, " ta-control interval %u%s",
+ trx->ta_ctrl_interval, VTY_NEWLINE);
vty_out(vty, " phy %u instance %u%s", pinst->phy_link->num,
pinst->num, VTY_NEWLINE);
@@ -342,16 +501,16 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
static int config_write_bts(struct vty *vty)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts;
+ const struct gsm_bts *bts;
- llist_for_each_entry(bts, &net->bts_list, list)
+ llist_for_each_entry(bts, &g_bts_sm->bts_list, list)
config_write_bts_single(vty, bts);
+ osmo_tdef_vty_groups_write(vty, "");
return CMD_SUCCESS;
}
-static void config_write_phy_single(struct vty *vty, struct phy_link *plink)
+static void config_write_phy_single(struct vty *vty, const struct phy_link *plink)
{
int i;
@@ -359,7 +518,7 @@ static void config_write_phy_single(struct vty *vty, struct phy_link *plink)
bts_model_config_write_phy(vty, plink);
for (i = 0; i < 255; i++) {
- struct phy_instance *pinst = phy_instance_by_num(plink, i);
+ const struct phy_instance *pinst = phy_instance_by_num(plink, i);
if (!pinst)
break;
vty_out(vty, " instance %u%s", pinst->num, VTY_NEWLINE);
@@ -372,7 +531,7 @@ 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);
+ const struct phy_link *plink = phy_link_by_num(i);
if (!plink)
break;
config_write_phy_single(vty, plink);
@@ -396,22 +555,22 @@ DEFUN(cfg_vty_telnet_port, cfg_vty_telnet_port_cmd,
}
/* per-BTS configuration */
-DEFUN(cfg_bts,
- cfg_bts_cmd,
- "bts BTS_NR",
- "Select a BTS to configure\n"
- "BTS Number\n")
+DEFUN_ATTR(cfg_bts,
+ cfg_bts_cmd,
+ "bts BTS_NR",
+ "Select a BTS to configure\n"
+ "BTS Number\n",
+ CMD_ATTR_IMMEDIATE)
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
int bts_nr = atoi(argv[0]);
struct gsm_bts *bts;
- if (bts_nr >= gsmnet->num_bts) {
+ if (bts_nr >= g_bts_sm->num_bts) {
vty_out(vty, "%% Unknown BTS number %u (num %u)%s",
- bts_nr, gsmnet->num_bts, VTY_NEWLINE);
+ bts_nr, g_bts_sm->num_bts, VTY_NEWLINE);
return CMD_WARNING;
} else
- bts = gsm_bts_num(gsmnet, bts_nr);
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
vty->index = bts;
vty->index_sub = &bts->description;
@@ -453,9 +612,11 @@ DEFUN(cfg_bts_band,
struct gsm_bts *bts = vty->index;
int band = gsm_band_parse(argv[0]);
+ /* This should not happen with the recent versions of libosmovty,
+ * but old versions may pass incomplete choice values like 'GSM9'. */
if (band < 0) {
- vty_out(vty, "%% BAND %d is not a valid GSM band%s",
- band, VTY_NEWLINE);
+ vty_out(vty, "%% BAND '%s' is not a valid GSM band%s",
+ argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
@@ -470,11 +631,51 @@ DEFUN(cfg_bts_oml_ip,
"OML Parameters\n" "OML IP Address\n" "OML IP Address\n")
{
struct gsm_bts *bts = vty->index;
+ struct bsc_oml_host *bsc_oml_host;
+
+ /* stop when the address is already in the list */
+ llist_for_each_entry(bsc_oml_host, &bts->bsc_oml_hosts, list) {
+ if (strcmp(argv[0], bsc_oml_host->addr) == 0) {
+ vty_out(vty, "%% duplicate BSC (A-Bis/OML) ip address configured ('%s')%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ bsc_oml_host = talloc_zero(bts, struct bsc_oml_host);
+ OSMO_ASSERT(bsc_oml_host);
+ bsc_oml_host->addr = talloc_strdup(bsc_oml_host, argv[0]);
+ OSMO_ASSERT(bsc_oml_host->addr);
+ llist_add_tail(&bsc_oml_host->list, &bts->bsc_oml_hosts);
- if (bts->bsc_oml_host)
- talloc_free(bts->bsc_oml_host);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_oml_ip,
+ cfg_bts_no_oml_ip_cmd,
+ "no oml remote-ip A.B.C.D",
+ NO_STR "OML Parameters\n" "OML IP Address\n" "OML IP Address\n")
+{
+ struct gsm_bts *bts = vty->index;
+ struct bsc_oml_host *bsc_oml_host;
+ struct bsc_oml_host *bsc_oml_host_del = NULL;
+
+ llist_for_each_entry(bsc_oml_host, &bts->bsc_oml_hosts, list) {
+ if (strcmp(argv[0], bsc_oml_host->addr) == 0)
+ bsc_oml_host_del = bsc_oml_host;
+ }
- bts->bsc_oml_host = talloc_strdup(bts, argv[0]);
+ if (bsc_oml_host_del) {
+ if (bts->abis_link_fi) {
+ osmo_fsm_inst_dispatch(bts->abis_link_fi, ABIS_LINK_EV_VTY_RM_ADDR, bsc_oml_host_del);
+ llist_del(&bsc_oml_host_del->list);
+ talloc_free(bsc_oml_host_del);
+ }
+ } else {
+ vty_out(vty, "%% no such BSC (A-Bis/OML) ip address configured ('%s')%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return CMD_SUCCESS;
}
@@ -491,10 +692,13 @@ DEFUN_DEPRECATED(cfg_bts_rtp_bind_ip,
return CMD_WARNING;
}
-DEFUN(cfg_bts_rtp_jitbuf,
- cfg_bts_rtp_jitbuf_cmd,
- "rtp jitter-buffer <0-10000> [adaptive]",
- RTP_STR "RTP jitter buffer\n" "jitter buffer in ms\n")
+DEFUN_USRATTR(cfg_bts_rtp_jitbuf,
+ cfg_bts_rtp_jitbuf_cmd,
+ X(BTS_VTY_ATTR_NEW_LCHAN),
+ "rtp jitter-buffer <0-10000> [adaptive]",
+ RTP_STR "RTP jitter buffer\n"
+ "Jitter buffer in ms\n"
+ "Enable adaptive RTP jitter buffering\n")
{
struct gsm_bts *bts = vty->index;
@@ -506,9 +710,10 @@ DEFUN(cfg_bts_rtp_jitbuf,
}
DEFUN(cfg_bts_rtp_port_range,
- cfg_bts_rtp_port_range_cmd,
- "rtp port-range <1-65534> <1-65534>",
- RTP_STR "Range of local ports to use for RTP/RTCP traffic\n")
+ cfg_bts_rtp_port_range_cmd,
+ "rtp port-range <1-65534> <1-65534>",
+ RTP_STR "Range of local ports to use for RTP/RTCP traffic\n"
+ "Port range start (inclusive)\n" "Port range end (inclusive)\n")
{
struct gsm_bts *bts = vty->index;
unsigned int start;
@@ -518,19 +723,19 @@ DEFUN(cfg_bts_rtp_port_range,
end = atoi(argv[1]);
if (end < start) {
- vty_out(vty, "range end port (%u) must be greater than the range start port (%u)!%s",
+ vty_out(vty, "%% Range end port (%u) must be greater than the range start port (%u)!%s",
end, start, VTY_NEWLINE);
return CMD_WARNING;
}
if (start & 1) {
- vty_out(vty, "range must begin at an even port number! (%u not even)%s",
+ vty_out(vty, "%% Range must begin at an even port number! (%u is odd)%s",
start, VTY_NEWLINE);
return CMD_WARNING;
}
if ((end & 1) == 0) {
- vty_out(vty, "range must end at an odd port number! (%u not odd)%s",
+ vty_out(vty, "%% Range must end at an odd port number! (%u is even)%s",
end, VTY_NEWLINE);
return CMD_WARNING;
}
@@ -542,13 +747,99 @@ DEFUN(cfg_bts_rtp_port_range,
return CMD_SUCCESS;
}
+DEFUN_USRATTR(cfg_bts_rtp_ip_dscp,
+ cfg_bts_rtp_ip_dscp_cmd,
+ X(BTS_VTY_ATTR_NEW_LCHAN),
+ "rtp ip-dscp <0-63>",
+ RTP_STR "Specify DSCP for RTP/IP packets\n" "The DSCP value (upper 6 bits of TOS)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int dscp = atoi(argv[0]);
+
+ bts->rtp_ip_dscp = dscp;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(cfg_bts_rtp_priority,
+ cfg_bts_rtp_priority_cmd,
+ X(BTS_VTY_ATTR_NEW_LCHAN),
+ "rtp socket-priority <0-255>",
+ RTP_STR "Specify socket priority for RTP/IP packets\n"
+ "The socket priority value (> 6 requires CAP_NET_ADMIN)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int prio = atoi(argv[0]);
+
+ bts->rtp_priority = prio;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_rtp_cont_stream,
+ cfg_bts_rtp_cont_stream_cmd,
+ "rtp continuous-streaming",
+ RTP_STR "Always emit an RTP packet every 20 ms\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->rtp_nogaps_mode = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_rtp_cont_stream,
+ cfg_bts_no_rtp_cont_stream_cmd,
+ "no rtp continuous-streaming",
+ NO_STR RTP_STR "Always emit an RTP packet every 20 ms\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->rtp_nogaps_mode = false;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_rtp_int_ul_ecu,
+ cfg_bts_rtp_int_ul_ecu_cmd,
+ "rtp internal-uplink-ecu",
+ RTP_STR "Apply a BTS-internal ECU to the uplink traffic frame stream\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->use_ul_ecu = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_rtp_int_ul_ecu,
+ cfg_bts_no_rtp_int_ul_ecu_cmd,
+ "no rtp internal-uplink-ecu",
+ NO_STR RTP_STR "Apply a BTS-internal ECU to the uplink traffic frame stream\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->use_ul_ecu = false;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_rtp_hr_format,
+ cfg_bts_rtp_hr_format_cmd,
+ "rtp hr-format (rfc5993|ts101318)",
+ RTP_STR "HRv1 codec output format\n" "RFC 5993\n" "TS 101 318\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->emit_hr_rfc5993 = !strcmp(argv[0], "rfc5993");
+ return CMD_SUCCESS;
+}
+
#define PAG_STR "Paging related parameters\n"
-DEFUN(cfg_bts_paging_queue_size,
- cfg_bts_paging_queue_size_cmd,
- "paging queue-size <1-1024>",
- PAG_STR "Maximum length of BTS-internal paging queue\n"
- "Maximum length of BTS-internal paging queue\n")
+DEFUN_ATTR(cfg_bts_paging_queue_size,
+ cfg_bts_paging_queue_size_cmd,
+ "paging queue-size <1-1024>",
+ PAG_STR "Maximum length of BTS-internal paging queue\n"
+ "Maximum length of BTS-internal paging queue\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -557,11 +848,12 @@ DEFUN(cfg_bts_paging_queue_size,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_paging_lifetime,
- cfg_bts_paging_lifetime_cmd,
- "paging lifetime <0-60>",
- PAG_STR "Maximum lifetime of a paging record\n"
- "Maximum lifetime of a paging record (secods)\n")
+DEFUN_ATTR(cfg_bts_paging_lifetime,
+ cfg_bts_paging_lifetime_cmd,
+ "paging lifetime <0-60>",
+ PAG_STR "Maximum lifetime of a paging record\n"
+ "Maximum lifetime of a paging record (secods)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -572,13 +864,14 @@ DEFUN(cfg_bts_paging_lifetime,
#define AGCH_QUEUE_STR "AGCH queue mgmt\n"
-DEFUN(cfg_bts_agch_queue_mgmt_params,
- cfg_bts_agch_queue_mgmt_params_cmd,
- "agch-queue-mgmt threshold <0-100> low <0-100> high <0-100000>",
- AGCH_QUEUE_STR
- "Threshold to start cleanup\nin %% of the maximum queue length\n"
- "Low water mark for cleanup\nin %% of the maximum queue length\n"
- "High water mark for cleanup\nin %% of the maximum queue length\n")
+DEFUN_ATTR(cfg_bts_agch_queue_mgmt_params,
+ cfg_bts_agch_queue_mgmt_params_cmd,
+ "agch-queue-mgmt threshold <0-100> low <0-100> high <0-100000>",
+ AGCH_QUEUE_STR
+ "Threshold to start cleanup\nin % of the maximum queue length\n"
+ "Low water mark for cleanup\nin % of the maximum queue length\n"
+ "High water mark for cleanup\nin % of the maximum queue length\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -589,11 +882,12 @@ DEFUN(cfg_bts_agch_queue_mgmt_params,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_agch_queue_mgmt_default,
- cfg_bts_agch_queue_mgmt_default_cmd,
- "agch-queue-mgmt default",
- AGCH_QUEUE_STR
- "Reset clean parameters to default values\n")
+DEFUN_ATTR(cfg_bts_agch_queue_mgmt_default,
+ cfg_bts_agch_queue_mgmt_default_cmd,
+ "agch-queue-mgmt default",
+ AGCH_QUEUE_STR
+ "Reset clean parameters to default values\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -604,22 +898,94 @@ DEFUN(cfg_bts_agch_queue_mgmt_default,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_ul_power_target, cfg_bts_ul_power_target_cmd,
- "uplink-power-target <-110-0>",
- "Set the nominal target Rx Level for uplink power control loop\n"
- "Target uplink Rx level in dBm\n")
+#define UL_POWER_TARGET_CMD \
+ "uplink-power-target <-110-0>"
+#define UL_POWER_TARGET_CMD_DESC \
+ "Set the nominal target Rx Level for uplink power control loop\n" \
+ "Target uplink Rx level in dBm\n"
+
+#define UL_POWER_DEPR_MSG(fmt, args...) \
+ vty_out(vty, "%% Command '%s' has been deprecated.%s" \
+ "%% MS/BS Power control parameters should be configured in osmo-bsc: " \
+ fmt, self->string, VTY_NEWLINE, ##args)
+
+DEFUN_ATTR(cfg_bts_ul_power_target, cfg_bts_ul_power_target_cmd,
+ UL_POWER_TARGET_CMD, UL_POWER_TARGET_CMD_DESC,
+ CMD_ATTR_DEPRECATED)
+{
+ struct gsm_power_ctrl_meas_params *mp;
+ struct gsm_bts *bts = vty->index;
+ int rxlev_dbm = atoi(argv[0]);
+ int hyst = 0;
+
+ if (argc > 1) /* optional argument */
+ hyst = atoi(argv[1]);
+
+ mp = &bts->ms_dpc_params.rxlev_meas;
+ mp->lower_thresh = dbm2rxlev(rxlev_dbm - hyst);
+ mp->upper_thresh = dbm2rxlev(rxlev_dbm + hyst);
+
+ UL_POWER_DEPR_MSG("use 'rxlev-thresh lower %u upper %u'.%s",
+ mp->lower_thresh, mp->upper_thresh,
+ VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* FIXME: libosmovty is unable to handle 'foo <-110-0> [bar <1-25>]' */
+DEFUN_CMD_ELEMENT(cfg_bts_ul_power_target,
+ cfg_bts_ul_power_target_hysteresis_cmd,
+ UL_POWER_TARGET_CMD " hysteresis <1-25>",
+ UL_POWER_TARGET_CMD_DESC
+ "Target Rx Level hysteresis\n"
+ "Tolerable deviation in dBm\n",
+ CMD_ATTR_DEPRECATED, 0);
+
+DEFUN_ATTR(cfg_no_bts_ul_power_filter,
+ cfg_bts_no_ul_power_filter_cmd,
+ "no uplink-power-filtering",
+ NO_STR "Disable filtering for uplink power control loop\n",
+ CMD_ATTR_DEPRECATED)
{
+ struct gsm_power_ctrl_meas_params *mp;
struct gsm_bts *bts = vty->index;
- bts->ul_power_target = atoi(argv[0]);
+ mp = &bts->ms_dpc_params.rxlev_meas;
+ mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE;
+
+ UL_POWER_DEPR_MSG("use 'no rxlev-avg'.%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_min_qual_rach, cfg_bts_min_qual_rach_cmd,
- "min-qual-rach <-100-100>",
- "Set the minimum link quality level of Access Bursts to be accepted\n"
- "C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)\n")
+DEFUN_ATTR(cfg_bts_ul_power_filter_ewma,
+ cfg_bts_ul_power_filter_ewma_cmd,
+ "uplink-power-filtering algo ewma beta <1-99>",
+ "Configure filtering for uplink power control loop\n"
+ "Select the filtering algorithm\n"
+ "Exponentially Weighted Moving Average (EWMA)\n"
+ "Smoothing factor (in %): beta = (100 - alpha)\n"
+ "1% - lowest smoothing, 99% - highest smoothing\n",
+ CMD_ATTR_DEPRECATED)
+{
+ struct gsm_power_ctrl_meas_params *mp;
+ struct gsm_bts *bts = vty->index;
+
+ mp = &bts->ms_dpc_params.rxlev_meas;
+ mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA;
+ mp->ewma.alpha = 100 - atoi(argv[0]);
+
+ UL_POWER_DEPR_MSG("use 'rxlev-avg algo osmo-ewma beta %s'.%s",
+ argv[0], VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_bts_min_qual_rach, cfg_bts_min_qual_rach_cmd,
+ "min-qual-rach <-100-100>",
+ "Set the minimum link quality level of Access Bursts to be accepted\n"
+ "C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -628,10 +994,11 @@ DEFUN(cfg_bts_min_qual_rach, cfg_bts_min_qual_rach_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_min_qual_norm, cfg_bts_min_qual_norm_cmd,
- "min-qual-norm <-100-100>",
- "Set the minimum link quality level of Normal Bursts to be accepted\n"
- "C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)\n")
+DEFUN_ATTR(cfg_bts_min_qual_norm, cfg_bts_min_qual_norm_cmd,
+ "min-qual-norm <-100-100>",
+ "Set the minimum link quality level of Normal Bursts to be accepted\n"
+ "C/I (Carrier-to-Interference) ratio in centiBels (10e-2 B or 10e-1 dB)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -640,10 +1007,11 @@ DEFUN(cfg_bts_min_qual_norm, cfg_bts_min_qual_norm_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_max_ber_rach, cfg_bts_max_ber_rach_cmd,
- "max-ber10k-rach <0-10000>",
- "Set the maximum BER for valid RACH requests\n"
- "BER in 1/10000 units (0=no BER; 100=1% BER)\n")
+DEFUN_ATTR(cfg_bts_max_ber_rach, cfg_bts_max_ber_rach_cmd,
+ "max-ber10k-rach <0-10000>",
+ "Set the maximum BER for valid RACH requests\n"
+ "BER in 1/10000 units (0=no BER; 100=1% BER)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -652,26 +1020,34 @@ DEFUN(cfg_bts_max_ber_rach, cfg_bts_max_ber_rach_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd,
+DEFUN(cfg_bts_pcu_sock_path, cfg_bts_pcu_sock_path_cmd,
"pcu-socket PATH",
- "Configure the PCU socket file/path name\n")
+ "Configure the PCU socket file/path name\n"
+ "UNIX socket path\n")
{
struct gsm_bts *bts = vty->index;
- if (bts->pcu.sock_path) {
- /* FIXME: close the interface? */
- talloc_free(bts->pcu.sock_path);
- }
- bts->pcu.sock_path = talloc_strdup(bts, argv[0]);
+ osmo_talloc_replace_string(bts, &bts->pcu.sock_path, argv[0]);
+
/* FIXME: re-open the interface? */
+ return CMD_SUCCESS;
+}
+DEFUN(cfg_bts_pcu_sock_ql, cfg_bts_pcu_sock_ql_cmd,
+ "pcu-socket-wqueue-length <1-" OSMO_STRINGIFY_VAL(BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX) ">",
+ "Configure the PCU socket queue length\n"
+ "Queue length\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->pcu.sock_wqueue_len_max = atoi(argv[0]);
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_supp_meas_toa256, cfg_bts_supp_meas_toa256_cmd,
- "supp-meas-info toa256",
- "Configure the RSL Supplementary Measurement Info\n"
- "Report the TOA in 1/256th symbol periods\n")
+DEFUN_ATTR(cfg_bts_supp_meas_toa256, cfg_bts_supp_meas_toa256_cmd,
+ "supp-meas-info toa256",
+ "Configure the RSL Supplementary Measurement Info\n"
+ "Report the TOA in 1/256th symbol periods\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -679,10 +1055,11 @@ DEFUN(cfg_bts_supp_meas_toa256, cfg_bts_supp_meas_toa256_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_no_supp_meas_toa256, cfg_bts_no_supp_meas_toa256_cmd,
- "no supp-meas-info toa256",
- NO_STR "Configure the RSL Supplementary Measurement Info\n"
- "Report the TOA in 1/256th symbol periods\n")
+DEFUN_ATTR(cfg_bts_no_supp_meas_toa256, cfg_bts_no_supp_meas_toa256_cmd,
+ "no supp-meas-info toa256",
+ NO_STR "Configure the RSL Supplementary Measurement Info\n"
+ "Report the TOA in 1/256th symbol periods\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
@@ -690,27 +1067,36 @@ DEFUN(cfg_bts_no_supp_meas_toa256, cfg_bts_no_supp_meas_toa256_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_smscb_max_qlen, cfg_bts_smscb_max_qlen_cmd,
- "smscb queue-max-length <1-60>",
- "Maximum queue length for SMSCB (CBCH) queue. In count of messages/pages (Default: 15)")
+#define SMSCB_STR \
+ "SMSCB (SMS Cell Broadcast) / CBCH configuration\n"
+
+DEFUN_ATTR(cfg_bts_smscb_max_qlen, cfg_bts_smscb_max_qlen_cmd,
+ "smscb queue-max-length <1-60>",
+ SMSCB_STR "Maximum length of the SMSCB (CBCH) queue\n"
+ "Length in count of messages/pages (default: 15)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
bts->smscb_queue_max_len = atoi(argv[0]);
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_smscb_tgt_qlen, cfg_bts_smscb_tgt_qlen_cmd,
- "smscb queue-target-length <1-30>",
- "Target queue length for SMSCB (CBCH) queue. In count of messages/pages (Default: 2)")
+DEFUN_ATTR(cfg_bts_smscb_tgt_qlen, cfg_bts_smscb_tgt_qlen_cmd,
+ "smscb queue-target-length <1-30>",
+ SMSCB_STR "Target length of the SMSCB (CBCH) queue\n"
+ "Length in count of messages/pages (default: 2)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
bts->smscb_queue_tgt_len = atoi(argv[0]);
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_smscb_qhyst, cfg_bts_smscb_qhyst_cmd,
- "smscb queue-hysteresis <0-30>",
- "Hysteresis for SMSCB (CBCH) queue. In count of messages/pages (Default: 2)")
+DEFUN_ATTR(cfg_bts_smscb_qhyst, cfg_bts_smscb_qhyst_cmd,
+ "smscb queue-hysteresis <0-30>",
+ SMSCB_STR "Hysteresis of the SMSCB (CBCH) queue\n"
+ "In count of messages/pages (default: 2)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts *bts = vty->index;
bts->smscb_queue_hyst = atoi(argv[0]);
@@ -718,7 +1104,7 @@ DEFUN(cfg_bts_smscb_qhyst, cfg_bts_smscb_qhyst_cmd,
}
-#define DB_DBM_STR \
+#define DB_MDB_STR \
"Unit is dB (decibels)\n" \
"Unit is mdB (milli-decibels, or rather 1/10000 bel)\n"
@@ -732,11 +1118,12 @@ static int parse_mdbm(const char *valstr, const char *unit)
return val;
}
-DEFUN(cfg_trx_user_gain,
- cfg_trx_user_gain_cmd,
- "user-gain <-100000-100000> (dB|mdB)",
- "Inform BTS about additional, user-provided gain or attenuation at TRX output\n"
- "Value of user-provided external gain(+)/attenuation(-)\n" DB_DBM_STR)
+DEFUN_ATTR(cfg_trx_user_gain,
+ cfg_trx_user_gain_cmd,
+ "user-gain <-100000-100000> (dB|mdB)",
+ "Inform BTS about additional, user-provided gain or attenuation at TRX output\n"
+ "Value of user-provided external gain(+)/attenuation(-)\n" DB_MDB_STR,
+ CMD_ATTR_IMMEDIATE)
{
struct gsm_bts_trx *trx = vty->index;
@@ -745,11 +1132,11 @@ DEFUN(cfg_trx_user_gain,
return CMD_SUCCESS;
}
-#define PR_STR "Power-Ramp settings"
+#define PR_STR "Power-Ramp settings\n"
DEFUN(cfg_trx_pr_max_initial, cfg_trx_pr_max_initial_cmd,
- "power-ramp max-initial <0-100000> (dBm|mdBm)",
+ "power-ramp max-initial <-10000-100000> (dBm|mdBm)",
PR_STR "Maximum initial power\n"
- "Value\n" DB_DBM_STR)
+ "Value\n" DB_MDB_STR)
{
struct gsm_bts_trx *trx = vty->index;
@@ -762,7 +1149,7 @@ DEFUN(cfg_trx_pr_max_initial, cfg_trx_pr_max_initial_cmd,
DEFUN(cfg_trx_pr_step_size, cfg_trx_pr_step_size_cmd,
"power-ramp step-size <1-100000> (dB|mdB)",
PR_STR "Power increase by step\n"
- "Step size\n" DB_DBM_STR)
+ "Step size\n" DB_MDB_STR)
{
struct gsm_bts_trx *trx = vty->index;
@@ -784,12 +1171,40 @@ DEFUN(cfg_trx_pr_step_interval, cfg_trx_pr_step_interval_cmd,
DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd,
"ms-power-control (dsp|osmo)",
- "Mobile Station Power Level Control (change requires restart)\n"
+ "Mobile Station Power Level Control\n"
"Handled by DSP\n" "Handled by OsmoBTS\n")
{
struct gsm_bts_trx *trx = vty->index;
+ bool soft = !strcmp(argv[0], "osmo");
+
+ if (!soft && !bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP)) {
+ /* NOTE: osmo-bts-trx used to have its own (low-level) MS Power Control loop, which
+ * has been ripped out in favour of the common implementation. Configuration files
+ * may still contain 'dsp', so let's be tolerant and override 'dsp' by 'osmo'. */
+ if (trx->bts->variant == BTS_OSMO_TRX && vty->type == VTY_FILE) {
+ vty_out(vty, "%% BTS model 'osmo-bts-trx' has no DSP/HW MS Power Control support, "
+ "consider updating your configuration file!%s", VTY_NEWLINE);
+ soft = true; /* override */
+ } else {
+ vty_out(vty, "%% This BTS model has no DSP/HW MS Power Control support%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ trx->ms_pwr_ctl_soft = soft;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ta_ctrl_interval, cfg_ta_ctrl_interval_cmd,
+ "ta-control interval <0-31>",
+ "Timing Advance Control Parameters\n"
+ "Set TA control loop interval\n"
+ "As in P_CON_INTERVAL, in units of 2 SACCH periods (0.96 seconds) (default=0, every SACCH block)\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->ta_ctrl_interval = atoi(argv[0]);
- trx->ms_power_control = argv[0][0] == 'd' ? 0 : 1;
return CMD_SUCCESS;
}
@@ -803,20 +1218,25 @@ DEFUN(cfg_trx_phy, cfg_trx_phy_cmd,
struct phy_instance *pinst;
if (!plink) {
- vty_out(vty, "phy%s does not exist%s",
+ 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",
+ 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;
+ if (pinst->trx != NULL) {
+ vty_out(vty, "%% phy%s instance %s is already bound to %s%s",
+ argv[0], argv[1], gsm_trx_name(pinst->trx), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ phy_instance_link_to_trx(pinst, trx);
return CMD_SUCCESS;
}
@@ -825,7 +1245,7 @@ DEFUN(cfg_trx_phy, cfg_trx_phy_cmd,
* SHOW
* ======================================================================*/
-static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
+static void net_dump_nmstate(struct vty *vty, const struct gsm_nm_state *nms)
{
vty_out(vty,"Oper '%s', Admin '%s', Avail '%s'%s",
abis_nm_opstate_name(nms->operational),
@@ -833,16 +1253,30 @@ static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
abis_nm_avail_name(nms->availability), VTY_NEWLINE);
}
-static void bts_dump_vty_features(struct vty *vty, struct gsm_bts *bts)
+static void bts_dump_vty_features(struct vty *vty, const struct gsm_bts *bts)
{
unsigned int i;
- bool no_features = true;
+ bool no_features;
+
vty_out(vty, " Features:%s", VTY_NEWLINE);
- for (i = 0; i < _NUM_BTS_FEAT; i++) {
- if (gsm_bts_has_feature(bts, i)) {
+ for (i = 0, no_features = true; i < _NUM_BTS_FEAT; i++) {
+ if (osmo_bts_has_feature(bts->features, i)) {
vty_out(vty, " %03u ", i);
- vty_out(vty, "%-40s%s", get_value_string(gsm_bts_features_descs, i), VTY_NEWLINE);
+ vty_out(vty, "%-40s%s", osmo_bts_features_desc(i), VTY_NEWLINE);
+ no_features = false;
+ }
+ }
+
+ if (no_features)
+ vty_out(vty, " (not available)%s", VTY_NEWLINE);
+
+ vty_out(vty, " BTS model specific (internal) flags:%s", VTY_NEWLINE);
+
+ for (i = 0, no_features = true; i < _BTS_INTERNAL_FLAG_NUM; i++) {
+ if (bts_internal_flag_get(bts, i)) {
+ vty_out(vty, " %03u ", i);
+ vty_out(vty, "%-40s%s", get_value_string(bts_impl_flag_desc, i), VTY_NEWLINE);
no_features = false;
}
}
@@ -851,13 +1285,24 @@ static void bts_dump_vty_features(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " (not available)%s", VTY_NEWLINE);
}
-static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
+static const char *stringify_radio_link_timeout(int val)
{
- struct gsm_bts_trx *trx;
+ static char buf[32];
+ if (val == -1)
+ snprintf(buf, sizeof(buf), "%s", "infinite");
+ else
+ snprintf(buf, sizeof(buf), "%d SACCH blocks", val);
+ return buf;
+}
+
+static void bts_dump_vty(struct vty *vty, const struct gsm_bts *bts)
+{
+ const struct gsm_bts_trx *trx;
- vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, "
+ vty_out(vty, "BTS %u is of type '%s', in band %s, has CI %u LAC %u, "
"BSIC %u and %u TRX%s",
- bts->nr, "FIXME", gsm_band_name(bts->band),
+ bts->nr, btsvariant2str(bts->variant),
+ gsm_band_name(bts->band),
bts->cell_identity,
bts->location_area_code, bts->bsic,
bts->num_trx, VTY_NEWLINE);
@@ -865,11 +1310,12 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
bts->description ? bts->description : "(null)", VTY_NEWLINE);
vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s",
bts->ip_access.site_id, bts->ip_access.bts_id,
- bts->oml_tei, VTY_NEWLINE);
+ bts->oml_link ? bts->oml_link->tei : 0x00,
+ VTY_NEWLINE);
vty_out(vty, " NM State: ");
net_dump_nmstate(vty, &bts->mo.nm_state);
vty_out(vty, " Site Mgr NM State: ");
- net_dump_nmstate(vty, &bts->site_mgr.mo.nm_state);
+ net_dump_nmstate(vty, &g_bts_sm->mo.nm_state);
if (strnlen(bts->pcu_version, MAX_VERSION_LENGTH))
vty_out(vty, " PCU version %s connected%s",
bts->pcu_version, VTY_NEWLINE);
@@ -897,9 +1343,19 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE);
vty_out(vty, " PH-RTS.ind FN advance average: %d, min: %d, max: %d%s",
bts_get_avg_fn_advance(bts), bts->fn_stats.min, bts->fn_stats.max, VTY_NEWLINE);
+ vty_out(vty, " Radio Link Timeout (OML): %s%s",
+ stringify_radio_link_timeout(bts->radio_link_timeout.oml), VTY_NEWLINE);
+ if (bts->radio_link_timeout.vty_override) {
+ vty_out(vty, " Radio Link Timeout (OVERRIDE): %s%s",
+ stringify_radio_link_timeout(bts->radio_link_timeout.current), VTY_NEWLINE);
+ }
+ if (bts->c0_power_red_db > 0) {
+ vty_out(vty, " BCCH carrier power reduction: %u dB%s",
+ bts->c0_power_red_db, VTY_NEWLINE);
+ }
llist_for_each_entry(trx, &bts->trx_list, list) {
- struct phy_instance *pinst = trx_phy_instance(trx);
+ const struct phy_instance *pinst = trx_phy_instance(trx);
vty_out(vty, " TRX %u%s", trx->nr, VTY_NEWLINE);
if (pinst) {
vty_out(vty, " phy %d %s", pinst->num, pinst->version);
@@ -914,32 +1370,262 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
}
-DEFUN(show_bts, show_bts_cmd, "show bts <0-255>",
- SHOW_STR "Display information about a BTS\n"
- BTS_NR_STR)
+DEFUN(show_bts, show_bts_cmd, "show bts [<0-255>]",
+ SHOW_STR "Display information about a BTS\n"
+ BTS_NR_STR)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
int bts_nr;
if (argc != 0) {
/* use the BTS number that the user has specified */
bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
+ if (bts_nr >= g_bts_sm->num_bts) {
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
VTY_NEWLINE);
return CMD_WARNING;
}
- bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
+ bts_dump_vty(vty, gsm_bts_num(g_bts_sm, bts_nr));
return CMD_SUCCESS;
}
/* print all BTS's */
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
- bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
+ for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++)
+ bts_dump_vty(vty, gsm_bts_num(g_bts_sm, bts_nr));
+
+ return CMD_SUCCESS;
+}
+
+static void gprs_dump_vty(struct vty *vty, const struct gsm_bts *bts)
+{
+ unsigned int i;
+ const struct gsm_gprs_nse *nse = &bts->site_mgr->gprs.nse;
+
+ /* GPRS parameters received from the BSC */
+ vty_out(vty, "BTS %u, RAC %u, NSEI %u, BVCI %u%s",
+ bts->nr, bts->gprs.rac,
+ nse->nsei,
+ bts->gprs.cell.bvci,
+ VTY_NEWLINE);
+
+ vty_out(vty, " Cell NM state: ");
+ net_dump_nmstate(vty, &bts->gprs.cell.mo.nm_state);
+ vty_out(vty, " NSE NM state: ");
+ net_dump_nmstate(vty, &nse->mo.nm_state);
+
+ for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
+ const struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
+
+ vty_out(vty, " NSVC%u (NSVCI %u) NM state: ", i, nsvc->nsvci);
+ net_dump_nmstate(vty, &nsvc->mo.nm_state);
+
+ if (nsvc->mo.nm_state.operational == NM_OPSTATE_ENABLED) {
+ struct osmo_sockaddr_str remote;
+ struct osmo_sockaddr_str local;
+
+ if (osmo_sockaddr_str_from_sockaddr(&remote, &nsvc->remote.u.sas) != 0)
+ remote = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
+ if (osmo_sockaddr_str_from_sockaddr(&local, &nsvc->local.u.sas) != 0)
+ local = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
+
+ /* Work around for over-defensiveness of OSMO_SOCKADDR_STR_FMT_ARGS():
+ * error: the address of ‘remote’ will always evaluate as ‘true’
+ * error: the address of ‘local’ will always evaluate as ‘true’ */
+ const struct osmo_sockaddr_str *r = &remote;
+ const struct osmo_sockaddr_str *l = &local;
+
+ /* Getting remote/local address info has never been so easy, right? */
+ vty_out(vty, " Address: r=" OSMO_SOCKADDR_STR_FMT
+ "<->l=" OSMO_SOCKADDR_STR_FMT "%s",
+ OSMO_SOCKADDR_STR_FMT_ARGS(r),
+ OSMO_SOCKADDR_STR_FMT_ARGS(l),
+ VTY_NEWLINE);
+ }
+ }
+}
+
+DEFUN(show_bts_gprs, show_bts_gprs_cmd,
+ "show bts <0-255> gprs",
+ SHOW_STR "Display information about a BTS\n"
+ BTS_NR_STR "GPRS/EGPRS configuration\n")
+{
+ const struct gsm_bts *bts;
+
+ bts = gsm_bts_num(g_bts_sm, atoi(argv[0]));
+ if (bts == NULL) {
+ vty_out(vty, "%% can't find BTS '%s'%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ /* TODO: also print info about PCUIF connection */
+ gprs_dump_vty(vty, bts);
return CMD_SUCCESS;
}
-static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
+DEFUN(test_send_failure_event_report, test_send_failure_event_report_cmd, "test send-failure-event-report <0-255>",
+ "Various testing commands\n"
+ "Send a test OML failure event report to the BSC\n" BTS_NR_STR)
+{
+ int bts_nr = atoi(argv[0]);
+ const struct gsm_bts *bts;
+
+ if (bts_nr >= g_bts_sm->num_bts) {
+ vty_out(vty, "%% can't find BTS '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MINOR, OSMO_EVT_WARN_SW_WARN, "test message sent from VTY");
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN(radio_link_timeout, radio_link_timeout_cmd, "bts <0-0> radio-link-timeout (oml|infinite|<4-64>)",
+ "BTS Specific Commands\n" BTS_NR_STR "Manually override Radio Link Timeout\n"
+ "Use value provided by BSC via A-bis OML (Connection Failure Criterion)\n"
+ "Use infinite timeout (DANGEROUS: only use during testing!)\n"
+ "Number of lost SACCH blocks\n")
+{
+ int bts_nr = atoi(argv[0]);
+ struct gsm_bts *bts = gsm_bts_num(g_bts_sm, bts_nr);
+
+ if (!bts) {
+ vty_out(vty, "%% can't find BTS '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[1], "oml")) {
+ bts->radio_link_timeout.current = bts->radio_link_timeout.oml;
+ bts->radio_link_timeout.vty_override = false;
+ } else if (!strcmp(argv[1], "infinite")) {
+ bts->radio_link_timeout.current = -1;
+ bts->radio_link_timeout.vty_override = true;
+ vty_out(vty, "%% INFINITE RADIO LINK TIMEOUT, USE ONLY FOR BTS RF TESTING%s", VTY_NEWLINE);
+ } else {
+ bts->radio_link_timeout.current = atoi(argv[1]);
+ bts->radio_link_timeout.vty_override = true;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(bts_c0_power_red,
+ bts_c0_power_red_cmd,
+ "bts <0-0> c0-power-red <0-6>",
+ "BTS Specific Commands\n" BTS_NR_STR
+ "BCCH carrier power reduction operation\n"
+ "Power reduction value (in dB, even numbers only)\n")
+{
+ const int bts_nr = atoi(argv[0]);
+ const int red = atoi(argv[1]);
+ struct gsm_bts *bts;
+
+ bts = gsm_bts_num(g_bts_sm, atoi(argv[0]));
+ if (bts == NULL) {
+ vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (red % 2 != 0) {
+ vty_out(vty, "%% Incorrect BCCH power reduction value, "
+ "an even number is expected%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bts_set_c0_pwr_red(bts, red) != 0) {
+ vty_out(vty, "%% BCCH carrier power reduction operation mode "
+ "is not supported for BTS (%d)%s", bts_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* TODO: generalize and move indention handling to libosmocore */
+#define cfg_out(vty, fmt, args...) \
+ vty_out(vty, "%*s" fmt, indent, "", ##args)
+
+static void dump_dpc_meas_params(struct vty *vty, const unsigned int indent,
+ const struct gsm_power_ctrl_meas_params *mp,
+ const char *pname, const unsigned int pn)
+{
+ cfg_out(vty, "Lower threshold (L_%s_XX_P): %u%s",
+ pname, mp->lower_thresh, VTY_NEWLINE);
+ cfg_out(vty, "Upper threshold (U_%s_XX_P): %u%s",
+ pname, mp->upper_thresh, VTY_NEWLINE);
+
+ cfg_out(vty, "Lower threshold comparators: P%u=%02u / N%u=%02u%s",
+ pn, mp->lower_cmp_p, pn, mp->lower_cmp_n, VTY_NEWLINE);
+ cfg_out(vty, "Upper threshold comparators: P%u=%02u / N%u=%02u%s",
+ pn + 1, mp->upper_cmp_p, pn + 1, mp->upper_cmp_n, VTY_NEWLINE);
+
+ cfg_out(vty, "Pre-processing algorithm: ");
+ switch (mp->algo) {
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_UNWEIGHTED:
+ vty_out(vty, "unweighted average%s", VTY_NEWLINE);
+ break;
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_WEIGHTED:
+ vty_out(vty, "weighted average%s", VTY_NEWLINE);
+ break;
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_MOD_MEDIAN:
+ vty_out(vty, "modified median%s", VTY_NEWLINE);
+ break;
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA:
+ vty_out(vty, "EWMA (alpha=%u)%s",
+ mp->ewma.alpha, VTY_NEWLINE);
+ break;
+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE:
+ vty_out(vty, "disabled (pass-through)%s", VTY_NEWLINE);
+ return;
+ default:
+ vty_out(vty, "unknown%s", VTY_NEWLINE);
+ return;
+ }
+
+ cfg_out(vty, "Pre-processing parameters: Hreqave=%u / Hreqt=%u%s",
+ mp->h_reqave, mp->h_reqt, VTY_NEWLINE);
+}
+
+static void dump_dpc_params(struct vty *vty, const unsigned int indent,
+ const struct gsm_power_ctrl_params *cp, bool uplink)
+{
+ cfg_out(vty, "Power control interval: %u ms (every %u SACCH block(s))%s",
+ cp->ctrl_interval ? cp->ctrl_interval * 2 * 480 : 480,
+ cp->ctrl_interval ? cp->ctrl_interval * 2 : 1,
+ VTY_NEWLINE);
+
+ cfg_out(vty, "Power increase step size: %u%s",
+ cp->inc_step_size_db, VTY_NEWLINE);
+ cfg_out(vty, "Power reduce step size: %u%s",
+ cp->red_step_size_db, VTY_NEWLINE);
+
+ cfg_out(vty, "RxLev measurement processing:%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->rxlev_meas, "RXLEV", 1);
+
+ cfg_out(vty, "RxQual measurement processing:%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->rxqual_meas, "RXQUAL", 3);
+
+ if (uplink) {
+ cfg_out(vty, "C/I measurement processing (FR/EFR):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_fr_meas, "CI_FR", 0);
+
+ cfg_out(vty, "C/I measurement processing (HR):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_hr_meas, "CI_HR", 0);
+
+ cfg_out(vty, "C/I measurement processing (AMR-FR):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_amr_fr_meas, "CI_AMR_FR", 0);
+
+ cfg_out(vty, "C/I measurement processing (AMR-HR):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_amr_hr_meas, "CI_AMR_HR", 0);
+
+ cfg_out(vty, "C/I measurement processing (SDCCH):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_sdcch_meas, "CI_SDCCH", 0);
+
+ cfg_out(vty, "C/I measurement processing (GPRS):%s", VTY_NEWLINE);
+ dump_dpc_meas_params(vty, indent + 2, &cp->ci_gprs_meas, "CI_GPRS", 0);
+ }
+}
+
+static void trx_dump_vty(struct vty *vty, const struct gsm_bts_trx *trx)
{
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE);
@@ -949,12 +1635,25 @@ static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
"resulting BS power: %d dBm%s",
trx->nominal_power, trx->max_power_red,
trx->nominal_power - trx->max_power_red, VTY_NEWLINE);
+
+ vty_out(vty, " BS Power control parameters (%s):%s",
+ trx->bs_dpc_params == &trx->bts->bs_dpc_params ?
+ "fall-back" : "from BSC",
+ VTY_NEWLINE);
+ dump_dpc_params(vty, 4, trx->bs_dpc_params, false);
+
+ vty_out(vty, " MS Power control parameters (%s):%s",
+ trx->ms_dpc_params == &trx->bts->ms_dpc_params ?
+ "fall-back" : "from BSC",
+ VTY_NEWLINE);
+ dump_dpc_params(vty, 4, trx->ms_dpc_params, true);
+
vty_out(vty, " NM State: ");
net_dump_nmstate(vty, &trx->mo.nm_state);
- vty_out(vty, " RSL State: %s%s", trx->rsl_link? "connected" : "disconnected", VTY_NEWLINE);
+ vty_out(vty, " RSL State: %s%s", trx->bb_transc.rsl.link ? "connected" : "disconnected", VTY_NEWLINE);
vty_out(vty, " Baseband Transceiver NM State: ");
net_dump_nmstate(vty, &trx->bb_transc.mo.nm_state);
- vty_out(vty, " IPA stream ID: 0x%02x%s", trx->rsl_tei, VTY_NEWLINE);
+ vty_out(vty, " IPA stream ID: 0x%02x%s", trx->bb_transc.rsl.tei, VTY_NEWLINE);
}
static inline void print_all_trx(struct vty *vty, const struct gsm_bts *bts)
@@ -970,19 +1669,18 @@ DEFUN(show_trx,
SHOW_STR "Display information about a TRX\n"
BTS_TRX_STR)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts = NULL;
+ const struct gsm_bts *bts = NULL;
int bts_nr, trx_nr;
if (argc >= 1) {
/* use the BTS number that the user has specified */
bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
+ if (bts_nr >= g_bts_sm->num_bts) {
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
VTY_NEWLINE);
return CMD_WARNING;
}
- bts = gsm_bts_num(net, bts_nr);
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
}
if (argc >= 2) {
trx_nr = atoi(argv[1]);
@@ -1000,18 +1698,18 @@ DEFUN(show_trx,
return CMD_SUCCESS;
}
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
- print_all_trx(vty, gsm_bts_num(net, bts_nr));
+ for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++)
+ print_all_trx(vty, gsm_bts_num(g_bts_sm, bts_nr));
return CMD_SUCCESS;
}
-static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
+static void ts_dump_vty(struct vty *vty, const struct gsm_bts_trx_ts *ts)
{
vty_out(vty, "BTS %u, TRX %u, Timeslot %u, phys cfg %s, TSC %u",
ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan), gsm_ts_tsc(ts));
+ gsm_pchan_name(ts->pchan), ts->tsc);
if (ts->pchan == GSM_PCHAN_TCH_F_PDCH)
vty_out(vty, " (%s mode)",
ts->flags & TS_F_PDCH_ACTIVE ? "PDCH" : "TCH/F");
@@ -1026,21 +1724,20 @@ DEFUN(show_ts,
SHOW_STR "Display information about a TS\n"
BTS_TRX_TS_STR)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts = NULL;
- struct gsm_bts_trx *trx = NULL;
- struct gsm_bts_trx_ts *ts = NULL;
+ const struct gsm_bts *bts = NULL;
+ const struct gsm_bts_trx *trx = NULL;
+ const struct gsm_bts_trx_ts *ts = NULL;
int bts_nr, trx_nr, ts_nr;
if (argc >= 1) {
/* use the BTS number that the user has specified */
bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
+ if (bts_nr >= g_bts_sm->num_bts) {
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
VTY_NEWLINE);
return CMD_WARNING;
}
- bts = gsm_bts_num(net, bts_nr);
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
}
if (argc >= 2) {
trx_nr = atoi(argv[1]);
@@ -1081,8 +1778,8 @@ DEFUN(show_ts,
}
} else {
/* Iterate over all BTS, TRX in each BTS, TS in each TRX */
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
+ for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++) {
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
trx = gsm_bts_trx_num(bts, trx_nr);
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
@@ -1096,25 +1793,12 @@ DEFUN(show_ts,
return CMD_SUCCESS;
}
-/* FIXME: move this to libosmogsm */
-static const struct value_string gsm48_cmode_names[] = {
- { GSM48_CMODE_SIGN, "signalling" },
- { GSM48_CMODE_SPEECH_V1, "FR or HR" },
- { GSM48_CMODE_SPEECH_EFR, "EFR" },
- { GSM48_CMODE_SPEECH_AMR, "AMR" },
- { GSM48_CMODE_DATA_14k5, "CSD(14k5)" },
- { GSM48_CMODE_DATA_12k0, "CSD(12k0)" },
- { GSM48_CMODE_DATA_6k0, "CSD(6k0)" },
- { GSM48_CMODE_DATA_3k6, "CSD(3k6)" },
- { 0, NULL }
-};
-
/* call vty_out() to print a string like " as TCH/H" for dynamic timeslots.
* Don't do anything if the ts is not dynamic. */
-static void vty_out_dyn_ts_status(struct vty *vty, struct gsm_bts_trx_ts *ts)
+static void vty_out_dyn_ts_status(struct vty *vty, const struct gsm_bts_trx_ts *ts)
{
switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
if (ts->dyn.pchan_is == ts->dyn.pchan_want)
vty_out(vty, " as %s",
gsm_pchan_name(ts->dyn.pchan_is));
@@ -1141,16 +1825,157 @@ static void vty_out_dyn_ts_status(struct vty *vty, struct gsm_bts_trx_ts *ts)
}
}
-static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
+static void lchan_bs_power_ctrl_state_dump(struct vty *vty, unsigned int indent,
+ const struct gsm_lchan *lchan)
+{
+ const struct lchan_power_ctrl_state *st = &lchan->bs_power_ctrl;
+ const struct gsm_bts_trx *trx = lchan->ts->trx;
+
+ cfg_out(vty, "BS (Downlink) Power Control (%s mode):%s",
+ st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);
+ indent += 2;
+
+ cfg_out(vty, "Channel reduction: %u dB", st->current);
+ if (st->dpc_params != NULL)
+ vty_out(vty, " (max %u dB)", st->max);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ cfg_out(vty, "TRX reduction: %u dB%s",
+ trx->max_power_red, VTY_NEWLINE);
+
+ int actual = trx->nominal_power - (trx->max_power_red + st->current);
+ cfg_out(vty, "Actual / Nominal power: %d dBm / %d dBm%s",
+ actual, trx->nominal_power, VTY_NEWLINE);
+
+ if (st->dpc_params == NULL)
+ return;
+
+ cfg_out(vty, "Power Control parameters:%s", VTY_NEWLINE);
+ dump_dpc_params(vty, indent + 2, st->dpc_params, false);
+}
+
+static void lchan_ms_power_ctrl_state_dump(struct vty *vty, unsigned int indent,
+ const struct gsm_lchan *lchan)
+{
+ const struct lchan_power_ctrl_state *st = &lchan->ms_power_ctrl;
+ const struct gsm_bts_trx *trx = lchan->ts->trx;
+
+ cfg_out(vty, "MS (Uplink) Power Control (%s):%s",
+ st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);
+ indent += 2;
+
+ int current_dbm = ms_pwr_dbm(trx->bts->band, st->current);
+ int max_dbm = ms_pwr_dbm(trx->bts->band, st->max);
+
+ cfg_out(vty, "Current power level: %u, %d dBm",
+ st->current, current_dbm);
+ if (st->dpc_params != NULL)
+ vty_out(vty, " (max %u, %d dBm)", st->max, max_dbm);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ if (st->dpc_params == NULL)
+ return;
+
+ cfg_out(vty, "Power Control parameters:%s", VTY_NEWLINE);
+ dump_dpc_params(vty, indent + 2, st->dpc_params, true);
+}
+
+static void lchan_acch_rep_state_dump(struct vty *vty, unsigned int indent,
+ const struct gsm_lchan *lchan)
+{
+ cfg_out(vty, "ACCH repetition:%s", VTY_NEWLINE);
+ indent += 2;
+ if (lchan->rep_acch_cap.rxqual)
+ cfg_out(vty, "Enable RXQUAL threshold: %u%s",
+ lchan->rep_acch_cap.rxqual, VTY_NEWLINE);
+ else
+ cfg_out(vty, "Enable RXQUAL threshold: (none, alway on)%s",
+ VTY_NEWLINE);
+
+ cfg_out(vty, "DL-FACCH:%s", VTY_NEWLINE);
+ indent += 2;
+ if (lchan->rep_acch_cap.dl_facch_all)
+ cfg_out(vty, "retramsit all LAPDM block types%s", VTY_NEWLINE);
+ else if (lchan->rep_acch_cap.dl_facch_cmd)
+ cfg_out(vty, "retramsit only LAPDM command blocks%s",
+ VTY_NEWLINE);
+ else
+ cfg_out(vty, "no retransmission (disabled)%s", VTY_NEWLINE);
+ if (lchan->rep_acch.dl_facch_active)
+ cfg_out(vty, "retransmission currently active%s", VTY_NEWLINE);
+ else
+ cfg_out(vty, "retransmission currently inactive%s",
+ VTY_NEWLINE);
+ indent -= 2;
+
+ cfg_out(vty, "DL-SACCH:%s", VTY_NEWLINE);
+ indent += 2;
+ if (lchan->rep_acch_cap.ul_sacch)
+ cfg_out(vty, "retramsit all SACCH blocks for SAPI=0%s",
+ VTY_NEWLINE);
+ else
+ cfg_out(vty, "no retransmission (disabled)%s", VTY_NEWLINE);
+ if (lchan->rep_acch.dl_sacch_active)
+ cfg_out(vty, "retransmission currently active%s", VTY_NEWLINE);
+ else
+ cfg_out(vty, "retransmission currently inactive%s",
+ VTY_NEWLINE);
+ indent -= 2;
+
+ cfg_out(vty, "UL-SACCH:%s", VTY_NEWLINE);
+ indent += 2;
+ if (lchan->rep_acch_cap.dl_sacch)
+ cfg_out(vty, "retramsit all SACCH blocks for SAPI=0%s",
+ VTY_NEWLINE);
+ else
+ cfg_out(vty, "no retransmission (disabled)%s", VTY_NEWLINE);
+ if (lchan->rep_acch.ul_sacch_active)
+ cfg_out(vty, "retransmission currently active%s", VTY_NEWLINE);
+ else
+ cfg_out(vty, "retransmission currently inactive%s",
+ VTY_NEWLINE);
+ indent -= 2;
+}
+
+static void lchan_acch_top_state_dump(struct vty *vty, unsigned int indent,
+ const struct gsm_lchan *lchan)
+{
+ if (lchan->top_acch_cap.overpower_db == 0)
+ return;
+
+ cfg_out(vty, "Temporary ACCH overpower:%s", VTY_NEWLINE);
+ indent += 2;
+
+ cfg_out(vty, "Overpower value: %u dB%s",
+ lchan->top_acch_cap.overpower_db, VTY_NEWLINE);
+
+ cfg_out(vty, "SACCH overpower: %sabled%s",
+ lchan->top_acch_cap.sacch_enable ? "en" : "dis",
+ VTY_NEWLINE);
+ cfg_out(vty, "FACCH overpower: %sabled%s",
+ lchan->top_acch_cap.facch_enable ? "en" : "dis",
+ VTY_NEWLINE);
+
+ if (lchan->top_acch_cap.rxqual == 0) {
+ cfg_out(vty, "RxQual threshold: disabled "
+ "(overpower is always on)%s", VTY_NEWLINE);
+ } else {
+ cfg_out(vty, "RxQual threshold: %u%s",
+ lchan->top_acch_cap.rxqual, VTY_NEWLINE);
+ }
+}
+
+static void lchan_dump_full_vty(struct vty *vty, const struct gsm_lchan *lchan)
{
struct in_addr ia;
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u: Type %s%s",
+ vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s), Lchan %u: Type %s%s",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
+ lchan->ts->vamos.is_shadow ? "shadow" : "primary",
lchan->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE);
/* show dyn TS details, if applicable */
switch (lchan->ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
vty_out(vty, " Osmocom Dyn TS:");
vty_out_dyn_ts_status(vty, lchan->ts);
vty_out(vty, VTY_NEWLINE);
@@ -1169,28 +1994,42 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
lchan->state == LCHAN_S_BROKEN ? " Error reason: " : "",
lchan->state == LCHAN_S_BROKEN ? lchan->broken_reason : "",
VTY_NEWLINE);
- vty_out(vty, " BS Power: %d dBm, MS Power: %u dBm%s",
- lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
- - lchan->bs_power*2,
- ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
- VTY_NEWLINE);
vty_out(vty, " Channel Mode / Codec: %s%s",
- get_value_string(gsm48_cmode_names, lchan->tch_mode),
+ gsm48_chan_mode_name(lchan->tch_mode),
VTY_NEWLINE);
+ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
+ const struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
+ const struct gsm48_multi_rate_conf *mr_conf =
+ (const struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
+ vty_out(vty, " AMR Multi-Rate Configuration: ICMI=%u, Start Mode=%u gsm48=%02x%02x%s",
+ mr_conf->icmi, mr_conf->smod, amr_mrc->gsm48_ie[0], amr_mrc->gsm48_ie[1], VTY_NEWLINE);
+ for (uint8_t i = 0; i < amr_mrc->num_modes; i++) {
+ const struct amr_mode *amode = &amr_mrc->mode[i];
+ vty_out(vty, " AMR Mode %u (%s), threshold=%u, hysteresis=%u%s",
+ amode->mode, osmo_amr_type_name(amode->mode),
+ amode->threshold, amode->hysteresis, VTY_NEWLINE);
+ }
+ }
if (lchan->abis_ip.bound_ip) {
ia.s_addr = htonl(lchan->abis_ip.bound_ip);
- vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
+ vty_out(vty, " Bound IP: %s Port %u CONN_ID=%u",
inet_ntoa(ia), lchan->abis_ip.bound_port,
- lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
- VTY_NEWLINE);
+ lchan->abis_ip.conn_id);
+ if (lchan->abis_ip.osmux.use)
+ vty_out(vty, " Osmux_CID=%u%s", lchan->abis_ip.osmux.local_cid, VTY_NEWLINE);
+ else
+ vty_out(vty, " RTP_TYPE2=%u%s", lchan->abis_ip.rtp_payload2, VTY_NEWLINE);
}
if (lchan->abis_ip.connect_ip) {
ia.s_addr = htonl(lchan->abis_ip.connect_ip);
- vty_out(vty, " Conn. IP: %s Port %u RTP_TYPE=%u SPEECH_MODE=0x%02u%s",
+ vty_out(vty, " Conn. IP: %s Port %u SPEECH_MODE=0x%02x",
inet_ntoa(ia), lchan->abis_ip.connect_port,
- lchan->abis_ip.rtp_payload, lchan->abis_ip.speech_mode,
- VTY_NEWLINE);
+ lchan->abis_ip.speech_mode);
+ if (lchan->abis_ip.osmux.use)
+ vty_out(vty, " Osmux_CID=%u%s", lchan->abis_ip.osmux.remote_cid, VTY_NEWLINE);
+ else
+ vty_out(vty, " RTP_TYPE=%u%s", lchan->abis_ip.rtp_payload, VTY_NEWLINE);
}
#define LAPDM_ESTABLISHED(link, sapi_idx) \
(link).datalink[sapi_idx].dl.state == LAPD_STATE_MF_EST
@@ -1215,15 +2054,31 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
if (lchan->loopback)
vty_out(vty, " RTP/PDCH Loopback Enabled%s", VTY_NEWLINE);
vty_out(vty, " Radio Link Failure Counter 'S': %d%s", lchan->s, VTY_NEWLINE);
- /* TODO: MS Power Control */
+
+ /* Interference levels */
+ if (lchan->meas.interf_meas_avg_dbm != 0) {
+ vty_out(vty, " Interference: %d dBm (band %d)%s",
+ lchan->meas.interf_meas_avg_dbm,
+ lchan->meas.interf_band,
+ VTY_NEWLINE);
+ }
+
+ /* BS/MS Power Control state and parameters */
+ lchan_bs_power_ctrl_state_dump(vty, 2, lchan);
+ lchan_ms_power_ctrl_state_dump(vty, 2, lchan);
+
+ /* ACCH repetition / overpower state */
+ lchan_acch_rep_state_dump(vty, 2, lchan);
+ lchan_acch_top_state_dump(vty, 2, lchan);
}
-static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
+static void lchan_dump_short_vty(struct vty *vty, const struct gsm_lchan *lchan)
{
const struct gsm_meas_rep_unidir *mru = &lchan->meas.ul_res;
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u %s",
+ vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s) %s",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
+ lchan->ts->vamos.is_shadow ? "shadow" : "primary",
gsm_pchan_name(lchan->ts->pchan));
vty_out_dyn_ts_status(vty, lchan->ts);
vty_out(vty, ", Lchan %u, Type %s, State %s - "
@@ -1234,40 +2089,50 @@ static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
VTY_NEWLINE);
}
-static int dump_lchan_trx_ts(struct gsm_bts_trx_ts *ts, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
+static int dump_lchan_trx_ts(const struct gsm_bts_trx_ts *ts, struct vty *vty,
+ void (*dump_cb)(struct vty *, const struct gsm_lchan *))
{
int lchan_nr;
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; lchan_nr++) {
- struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
+ const struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
if (lchan->state == LCHAN_S_NONE)
continue;
- dump_cb(vty, lchan);
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ case GSM_LCHAN_TCH_F:
+ case GSM_LCHAN_TCH_H:
+ dump_cb(vty, lchan);
+ break;
+ default:
+ continue;
+ }
}
return CMD_SUCCESS;
}
-static int dump_lchan_trx(struct gsm_bts_trx *trx, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
+static int dump_lchan_trx(const struct gsm_bts_trx *trx, struct vty *vty,
+ void (*dump_cb)(struct vty *, const struct gsm_lchan *))
{
int ts_nr;
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
+ const struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
dump_lchan_trx_ts(ts, vty, dump_cb);
+ if (ts->vamos.peer != NULL) /* VAMOS: shadow timeslot */
+ dump_lchan_trx_ts(ts->vamos.peer, vty, dump_cb);
}
return CMD_SUCCESS;
}
-static int dump_lchan_bts(struct gsm_bts *bts, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
+static int dump_lchan_bts(const struct gsm_bts *bts, struct vty *vty,
+ void (*dump_cb)(struct vty *, const struct gsm_lchan *))
{
int trx_nr;
for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_nr);
+ const struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_nr);
dump_lchan_trx(trx, vty, dump_cb);
}
@@ -1275,24 +2140,23 @@ static int dump_lchan_bts(struct gsm_bts *bts, struct vty *vty,
}
static int lchan_summary(struct vty *vty, int argc, const char **argv,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
+ void (*dump_cb)(struct vty *, const struct gsm_lchan *))
{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- struct gsm_lchan *lchan;
+ const struct gsm_bts *bts = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
+ const struct gsm_bts_trx *trx = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
+ const struct gsm_bts_trx_ts *ts = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
+ const struct gsm_lchan *lchan;
int bts_nr, trx_nr, ts_nr, lchan_nr;
if (argc >= 1) {
/* use the BTS number that the user has specified */
bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
+ if (bts_nr >= g_bts_sm->num_bts) {
vty_out(vty, "%% can't find BTS %s%s", argv[0],
VTY_NEWLINE);
return CMD_WARNING;
}
- bts = gsm_bts_num(net, bts_nr);
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
if (argc == 1)
return dump_lchan_bts(bts, vty, dump_cb);
@@ -1333,8 +2197,8 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
return CMD_SUCCESS;
}
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
+ for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++) {
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
dump_lchan_bts(bts, vty, dump_cb);
}
@@ -1360,18 +2224,18 @@ DEFUN(show_lchan_summary,
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
-static struct gsm_lchan *resolve_lchan(struct gsm_network *net,
- const char **argv, int idx)
+static struct gsm_lchan *resolve_lchan(const char **argv, int idx)
{
int bts_nr = atoi(argv[idx+0]);
int trx_nr = atoi(argv[idx+1]);
int ts_nr = atoi(argv[idx+2]);
- int lchan_nr = atoi(argv[idx+3]);
+ bool shadow = argv[idx+3][0] == 's';
+ int lchan_nr = atoi(argv[idx+4]);
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
- bts = gsm_bts_num(net, bts_nr);
+ bts = gsm_bts_num(g_bts_sm, bts_nr);
if (!bts)
return NULL;
@@ -1382,6 +2246,11 @@ static struct gsm_lchan *resolve_lchan(struct gsm_network *net,
if (ts_nr >= ARRAY_SIZE(trx->ts))
return NULL;
ts = &trx->ts[ts_nr];
+ if (shadow) { /* VAMOS shadow */
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ }
if (lchan_nr >= ARRAY_SIZE(ts->lchan))
return NULL;
@@ -1389,6 +2258,8 @@ static struct gsm_lchan *resolve_lchan(struct gsm_network *net,
return &ts->lchan[lchan_nr];
}
+#define BTS_T_T_L_CMD \
+ "bts <0-0> trx <0-255> ts <0-7> (lchan|shadow-lchan) <0-7>"
#define BTS_T_T_L_STR \
"BTS related commands\n" \
"BTS number\n" \
@@ -1396,38 +2267,151 @@ static struct gsm_lchan *resolve_lchan(struct gsm_network *net,
"TRX number\n" \
"timeslot related commands\n" \
"timeslot number\n" \
- "logical channel commands\n" \
+ "Primary logical channel commands\n" \
+ "Shadow logical channel commands\n" \
"logical channel number\n"
-DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd,
+DEFUN(cfg_bts_gsmtap_remote_host,
+ cfg_bts_gsmtap_remote_host_cmd,
+ "gsmtap-remote-host [HOSTNAME]",
+ "Enable GSMTAP Um logging (see also 'gsmtap-sapi')\n"
+ "Remote IP address or hostname ('localhost' if omitted)\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ osmo_talloc_replace_string(bts, &bts->gsmtap.remote_host,
+ argc > 0 ? argv[0] : "localhost");
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gsmtap_local_host,
+ cfg_bts_gsmtap_local_host_cmd,
+ "gsmtap-local-host HOSTNAME",
+ "Enable local bind for GSMTAP Um logging (see also 'gsmtap-sapi')\n"
+ "Local IP address or hostname\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ osmo_talloc_replace_string(bts, &bts->gsmtap.local_host, argv[0]);
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_gsmtap_remote_host,
+ cfg_bts_no_gsmtap_remote_host_cmd,
+ "no gsmtap-remote-host",
+ NO_STR "Disable GSMTAP Um logging\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (bts->gsmtap.remote_host != NULL)
+ talloc_free(bts->gsmtap.remote_host);
+ bts->gsmtap.remote_host = NULL;
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_gsmtap_local_host,
+ cfg_bts_no_gsmtap_local_host_cmd,
+ "no gsmtap-local-host",
+ NO_STR "Disable local bind for GSMTAP Um logging\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (bts->gsmtap.local_host != NULL)
+ talloc_free(bts->gsmtap.local_host);
+
+ bts->gsmtap.local_host = NULL;
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gsmtap_sapi_all, cfg_bts_gsmtap_sapi_all_cmd,
+ "gsmtap-sapi (enable-all|disable-all)",
+ "Enable/disable sending of UL/DL messages over GSMTAP\n"
+ "Enable all kinds of messages (all SAPI)\n"
+ "Disable all kinds of messages (all SAPI)\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (argv[0][0] == 'e') {
+ bts->gsmtap.sapi_mask = UINT32_MAX;
+ bts->gsmtap.sapi_acch = 1;
+ } else {
+ bts->gsmtap.sapi_mask = 0x00;
+ bts->gsmtap.sapi_acch = 0;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gsmtap_sapi, cfg_bts_gsmtap_sapi_cmd,
"HIDDEN", "HIDDEN")
{
+ struct gsm_bts *bts = vty->index;
int sapi;
sapi = get_string_value(gsmtap_sapi_names, argv[0]);
OSMO_ASSERT(sapi >= 0);
if (sapi == GSMTAP_CHANNEL_ACCH)
- gsmtap_sapi_acch = 1;
+ bts->gsmtap.sapi_acch = 1;
else
- gsmtap_sapi_mask |= (1 << sapi);
+ bts->gsmtap.sapi_mask |= (1 << sapi);
return CMD_SUCCESS;
}
-DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd,
+DEFUN(cfg_bts_no_gsmtap_sapi, cfg_bts_no_gsmtap_sapi_cmd,
"HIDDEN", "HIDDEN")
{
+ struct gsm_bts *bts = vty->index;
int sapi;
sapi = get_string_value(gsmtap_sapi_names, argv[0]);
OSMO_ASSERT(sapi >= 0);
if (sapi == GSMTAP_CHANNEL_ACCH)
- gsmtap_sapi_acch = 0;
+ bts->gsmtap.sapi_acch = 0;
+ else
+ bts->gsmtap.sapi_mask &= ~(1 << sapi);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gsmtap_rlp, cfg_bts_gsmtap_rlp_cmd,
+ "gsmtap-rlp [skip-null]",
+ "Enable generation of GSMTAP frames for RLP (non-transparent CSD)\n"
+ "Skip the generation of GSMTAP for RLP NULL frames\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->gsmtap.rlp = true;
+ if (argc >= 1 && !strcmp(argv[0], "skip-null"))
+ bts->gsmtap.rlp_skip_null = true;
else
- gsmtap_sapi_mask &= ~(1 << sapi);
+ bts->gsmtap.rlp_skip_null = false;
+ return CMD_SUCCESS;
+}
+DEFUN(cfg_bts_no_gsmtap_rlp, cfg_bts_no_gsmtap_rlp_cmd,
+ "no gsmtap-rlp",
+ NO_STR "Disable generation of GSMTAP frames for RLP (non-transparent CSD)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->gsmtap.rlp = false;
return CMD_SUCCESS;
}
@@ -1443,9 +2427,10 @@ static struct cmd_node phy_inst_node = {
1,
};
-DEFUN(cfg_phy, cfg_phy_cmd,
- "phy <0-255>",
- "Select a PHY to configure\n" "PHY number\n")
+DEFUN_ATTR(cfg_phy, cfg_phy_cmd,
+ "phy <0-255>",
+ "Select a PHY to configure\n" "PHY number\n",
+ CMD_ATTR_IMMEDIATE)
{
int phy_nr = atoi(argv[0]);
struct phy_link *plink;
@@ -1463,9 +2448,10 @@ DEFUN(cfg_phy, cfg_phy_cmd,
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")
+DEFUN_ATTR(cfg_phy_inst, cfg_phy_inst_cmd,
+ "instance <0-255>",
+ "Select a PHY instance to configure\n" "PHY Instance number\n",
+ CMD_ATTR_IMMEDIATE)
{
int inst_nr = atoi(argv[0]);
struct phy_link *plink = vty->index;
@@ -1475,7 +2461,7 @@ DEFUN(cfg_phy_inst, cfg_phy_inst_cmd,
if (!pinst) {
pinst = phy_instance_create(plink, inst_nr);
if (!pinst) {
- vty_out(vty, "Unable to create phy%u instance %u%s",
+ vty_out(vty, "%% Unable to create phy%u instance %u%s",
plink->num, inst_nr, VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1498,7 +2484,7 @@ DEFUN(cfg_phy_no_inst, cfg_phy_no_inst_cmd,
pinst = phy_instance_by_num(plink, inst_nr);
if (!pinst) {
- vty_out(vty, "No such instance %u%s", inst_nr, VTY_NEWLINE);
+ vty_out(vty, "%% No such instance %u%s", inst_nr, VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1518,7 +2504,7 @@ DEFUN(cfg_phy_type, cfg_phy_type_cmd,
struct phy_link *plink = vty->index;
if (plink->state != PHY_LINK_SHUTDOWN) {
- vty_out(vty, "Cannot change type of active PHY%s", VTY_NEWLINE);
+ vty_out(vty, "%% Cannot change type of active PHY%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1533,17 +2519,16 @@ DEFUN(cfg_phy_type, cfg_phy_type_cmd,
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>",
+ BTS_T_T_L_CMD " rtp jitter-buffer <0-10000>",
BTS_T_T_L_STR "RTP settings\n"
"Jitter buffer\n" "Size of jitter buffer in (ms)\n")
{
- struct gsm_network *net = gsmnet_from_vty(vty);
struct gsm_lchan *lchan;
int jitbuf_ms = atoi(argv[4]), rc;
- lchan = resolve_lchan(net, argv, 0);
+ lchan = resolve_lchan(argv, 0);
if (!lchan) {
- vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE);
+ vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (!lchan->abis_ip.rtp_socket) {
@@ -1564,17 +2549,17 @@ DEFUN(bts_t_t_l_jitter_buf,
return CMD_SUCCESS;
}
-DEFUN(bts_t_t_l_loopback,
- bts_t_t_l_loopback_cmd,
- "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback",
- BTS_T_T_L_STR "Set loopback\n")
+DEFUN_ATTR(bts_t_t_l_loopback,
+ bts_t_t_l_loopback_cmd,
+ BTS_T_T_L_CMD " loopback",
+ BTS_T_T_L_STR "Set loopback\n",
+ CMD_ATTR_HIDDEN)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
struct gsm_lchan *lchan;
- lchan = resolve_lchan(net, argv, 0);
+ lchan = resolve_lchan(argv, 0);
if (!lchan) {
- vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE);
+ vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
return CMD_WARNING;
}
lchan->loopback = 1;
@@ -1582,17 +2567,17 @@ DEFUN(bts_t_t_l_loopback,
return CMD_SUCCESS;
}
-DEFUN(no_bts_t_t_l_loopback,
- no_bts_t_t_l_loopback_cmd,
- "no bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback",
- NO_STR BTS_T_T_L_STR "Set loopback\n")
+DEFUN_ATTR(no_bts_t_t_l_loopback,
+ no_bts_t_t_l_loopback_cmd,
+ "no " BTS_T_T_L_CMD " loopback",
+ NO_STR BTS_T_T_L_STR "Set loopback\n",
+ CMD_ATTR_HIDDEN)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
struct gsm_lchan *lchan;
- lchan = resolve_lchan(net, argv, 0);
+ lchan = resolve_lchan(argv, 0);
if (!lchan) {
- vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE);
+ vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
return CMD_WARNING;
}
lchan->loopback = 0;
@@ -1600,20 +2585,147 @@ DEFUN(no_bts_t_t_l_loopback,
return CMD_SUCCESS;
}
-int bts_vty_init(struct gsm_bts *bts)
+#define LCHAN_PWR_CTRL_CMD \
+ BTS_T_T_L_CMD " (bs-power-ctrl|ms-power-ctrl)"
+#define LCHAN_PWR_CTRL_STR \
+ BTS_T_T_L_STR "BS power control\n" "MS power control\n"
+
+DEFUN_ATTR(bts_t_t_l_power_ctrl_mode,
+ bts_t_t_l_power_ctrl_mode_cmd,
+ LCHAN_PWR_CTRL_CMD " mode (static|dynamic)",
+ LCHAN_PWR_CTRL_STR "Change power control mode\n"
+ "Disable the power control loop\n"
+ "Enable the power control loop\n",
+ CMD_ATTR_HIDDEN)
+{
+ const struct gsm_power_ctrl_params *params;
+ struct lchan_power_ctrl_state *state;
+ const char **args = argv + 4;
+ struct gsm_lchan *lchan;
+
+ lchan = resolve_lchan(argv, 0);
+ if (!lchan) {
+ vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (strcmp(args[0], "bs-power-ctrl") == 0) {
+ params = &lchan->bs_dpc_params;
+ state = &lchan->bs_power_ctrl;
+ } else { /* ms-power-ctrl */
+ params = &lchan->ms_dpc_params;
+ state = &lchan->ms_power_ctrl;
+ }
+
+ if (strcmp(args[1], "dynamic") == 0)
+ state->dpc_params = params;
+ else
+ state->dpc_params = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(bts_t_t_l_power_ctrl_current_max,
+ bts_t_t_l_power_ctrl_current_max_cmd,
+ LCHAN_PWR_CTRL_CMD " value (current|max) <0-255>",
+ LCHAN_PWR_CTRL_STR "Change current power value\n"
+ "Current value (for both dynamic and static modes)\n"
+ "Maximum value (for dynamic mode only)\n"
+ "BS power reduction (in dB) or MS power level\n",
+ CMD_ATTR_HIDDEN)
{
- cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names,
+ struct lchan_power_ctrl_state *state;
+ const char **args = argv + 4;
+ struct gsm_lchan *lchan;
+
+ lchan = resolve_lchan(argv, 0);
+ if (!lchan) {
+ vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (strcmp(args[0], "bs-power-ctrl") == 0)
+ state = &lchan->bs_power_ctrl;
+ else /* ms-power-ctrl */
+ state = &lchan->ms_power_ctrl;
+
+ if (strcmp(args[1], "current") == 0)
+ state->current = atoi(args[2]);
+ else
+ state->max = atoi(args[2]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_fltr_l1_sapi, logging_fltr_l1_sapi_cmd, "HIDDEN", "HIDDEN")
+{
+ int sapi = get_string_value(l1sap_common_sapi_names, argv[0]);
+ struct log_target *tgt = osmo_log_vty2tgt(vty);
+ uint16_t **sapi_mask;
+
+ OSMO_ASSERT(sapi >= 0);
+ if (!tgt)
+ return CMD_WARNING;
+
+ sapi_mask = (uint16_t **)&tgt->filter_data[LOG_FLT_L1_SAPI];
+
+ if (!*sapi_mask)
+ *sapi_mask = talloc(tgt, uint16_t);
+
+ OSMO_ASSERT(sapi <= 31);
+ **sapi_mask |= (1 << sapi);
+ tgt->filter_map |= (1 << LOG_FLT_L1_SAPI);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_logging_fltr_l1_sapi, no_logging_fltr_l1_sapi_cmd, "HIDDEN", "HIDDEN")
+{
+ int sapi = get_string_value(l1sap_common_sapi_names, argv[0]);
+ struct log_target *tgt = osmo_log_vty2tgt(vty);
+ uint16_t *sapi_mask;
+
+ OSMO_ASSERT(sapi >= 0);
+ if (!tgt)
+ return CMD_WARNING;
+ if (!tgt->filter_data[LOG_FLT_L1_SAPI])
+ return CMD_SUCCESS;
+
+ OSMO_ASSERT(sapi <= 31);
+ sapi_mask = (uint16_t *)tgt->filter_data[LOG_FLT_L1_SAPI];
+ *sapi_mask &= ~(1 << sapi);
+
+ return CMD_SUCCESS;
+}
+
+int bts_vty_init(void *ctx)
+{
+ cfg_bts_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(ctx, gsmtap_sapi_names,
"gsmtap-sapi (",
"|",")", VTY_DO_LOWER);
- cfg_trx_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names,
- "GSMTAP SAPI\n",
+ cfg_bts_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(ctx, gsmtap_sapi_names,
+ "Enable sending of UL/DL messages over GSMTAP\n",
"\n", "", 0);
- cfg_trx_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names,
+ cfg_bts_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(ctx, gsmtap_sapi_names,
"no gsmtap-sapi (",
"|",")", VTY_DO_LOWER);
- cfg_trx_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names,
- NO_STR "GSMTAP SAPI\n",
+ cfg_bts_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(ctx, gsmtap_sapi_names,
+ NO_STR "Disable sending of UL/DL messages over GSMTAP\n",
+ "\n", "", 0);
+
+ logging_fltr_l1_sapi_cmd.string = vty_cmd_string_from_valstr(ctx, l1sap_common_sapi_names,
+ "logging filter l1-sapi (",
+ "|", ")", VTY_DO_LOWER);
+ logging_fltr_l1_sapi_cmd.doc = vty_cmd_string_from_valstr(ctx, l1sap_common_sapi_names,
+ LOGGING_STR FILTER_STR "L1 SAPI\n",
+ "\n", "", 0);
+
+ no_logging_fltr_l1_sapi_cmd.string = vty_cmd_string_from_valstr(ctx, l1sap_common_sapi_names,
+ "no logging filter l1-sapi (",
+ "|", ")", VTY_DO_LOWER);
+ no_logging_fltr_l1_sapi_cmd.doc = vty_cmd_string_from_valstr(ctx, l1sap_common_sapi_names,
+ NO_STR LOGGING_STR FILTER_STR "L1 SAPI\n",
"\n", "", 0);
install_element_ve(&show_bts_cmd);
@@ -1621,19 +2733,30 @@ int bts_vty_init(struct gsm_bts *bts)
install_element_ve(&show_ts_cmd);
install_element_ve(&show_lchan_cmd);
install_element_ve(&show_lchan_summary_cmd);
+ install_element_ve(&show_bts_gprs_cmd);
- logging_vty_add_cmds();
- osmo_talloc_vty_add_cmds();
- osmo_stats_vty_add_cmds();
+ install_element_ve(&logging_fltr_l1_sapi_cmd);
+ install_element_ve(&no_logging_fltr_l1_sapi_cmd);
install_node(&bts_node, config_write_bts);
install_element(CONFIG_NODE, &cfg_bts_cmd);
install_element(CONFIG_NODE, &cfg_vty_telnet_port_cmd);
+
+ osmo_tdef_vty_groups_init(CONFIG_NODE, bts_tdef_groups);
+
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
install_element(BTS_NODE, &cfg_bts_oml_ip_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_oml_ip_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_bind_ip_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_jitbuf_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_port_range_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_ip_dscp_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_priority_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_cont_stream_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_rtp_cont_stream_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_int_ul_ecu_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_rtp_int_ul_ecu_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_hr_format_cmd);
install_element(BTS_NODE, &cfg_bts_band_cmd);
install_element(BTS_NODE, &cfg_description_cmd);
install_element(BTS_NODE, &cfg_no_description_cmd);
@@ -1642,18 +2765,40 @@ int bts_vty_init(struct gsm_bts *bts)
install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_default_cmd);
install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_params_cmd);
install_element(BTS_NODE, &cfg_bts_ul_power_target_cmd);
+ install_element(BTS_NODE, &cfg_bts_ul_power_target_hysteresis_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_ul_power_filter_cmd);
+ install_element(BTS_NODE, &cfg_bts_ul_power_filter_ewma_cmd);
install_element(BTS_NODE, &cfg_bts_min_qual_rach_cmd);
install_element(BTS_NODE, &cfg_bts_min_qual_norm_cmd);
install_element(BTS_NODE, &cfg_bts_max_ber_rach_cmd);
- install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd);
+ install_element(BTS_NODE, &cfg_bts_pcu_sock_path_cmd);
+ install_element(BTS_NODE, &cfg_bts_pcu_sock_ql_cmd);
install_element(BTS_NODE, &cfg_bts_supp_meas_toa256_cmd);
install_element(BTS_NODE, &cfg_bts_no_supp_meas_toa256_cmd);
install_element(BTS_NODE, &cfg_bts_smscb_max_qlen_cmd);
install_element(BTS_NODE, &cfg_bts_smscb_tgt_qlen_cmd);
install_element(BTS_NODE, &cfg_bts_smscb_qhyst_cmd);
- install_element(BTS_NODE, &cfg_trx_gsmtap_sapi_cmd);
- install_element(BTS_NODE, &cfg_trx_no_gsmtap_sapi_cmd);
+ install_element(BTS_NODE, &cfg_bts_gsmtap_remote_host_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_gsmtap_remote_host_cmd);
+ install_element(BTS_NODE, &cfg_bts_gsmtap_local_host_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_gsmtap_local_host_cmd);
+ install_element(BTS_NODE, &cfg_bts_gsmtap_sapi_all_cmd);
+ install_element(BTS_NODE, &cfg_bts_gsmtap_sapi_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_gsmtap_sapi_cmd);
+ install_element(BTS_NODE, &cfg_bts_gsmtap_rlp_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_gsmtap_rlp_cmd);
+
+ /* Osmux Node */
+ install_element(BTS_NODE, &cfg_bts_osmux_cmd);
+ install_node(&osmux_node, config_write_dummy);
+
+ install_element(OSMUX_NODE, &cfg_bts_osmux_use_cmd);
+ install_element(OSMUX_NODE, &cfg_bts_osmux_ip_cmd);
+ install_element(OSMUX_NODE, &cfg_bts_osmux_port_cmd);
+ install_element(OSMUX_NODE, &cfg_bts_osmux_batch_factor_cmd);
+ install_element(OSMUX_NODE, &cfg_bts_osmux_batch_size_cmd);
+ install_element(OSMUX_NODE, &cfg_bts_osmux_dummy_padding_cmd);
/* add and link to TRX config node */
install_element(BTS_NODE, &cfg_bts_trx_cmd);
@@ -1664,11 +2809,17 @@ int bts_vty_init(struct gsm_bts *bts)
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_ta_ctrl_interval_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(ENABLE_NODE, &bts_t_t_l_power_ctrl_mode_cmd);
+ install_element(ENABLE_NODE, &bts_t_t_l_power_ctrl_current_max_cmd);
+ install_element(ENABLE_NODE, &test_send_failure_event_report_cmd);
+ install_element(ENABLE_NODE, &radio_link_timeout_cmd);
+ install_element(ENABLE_NODE, &bts_c0_power_red_cmd);
install_element(CONFIG_NODE, &cfg_phy_cmd);
install_node(&phy_node, config_write_phy);
@@ -1677,5 +2828,6 @@ int bts_vty_init(struct gsm_bts *bts)
install_node(&phy_inst_node, config_write_dummy);
- return 0;
+ /* Install variant-specific VTY options */
+ return bts_model_vty_init(ctx);
}
diff --git a/src/osmo-bts-lc15/Makefile.am b/src/osmo-bts-lc15/Makefile.am
new file mode 100644
index 00000000..58284e95
--- /dev/null
+++ b/src/osmo-bts-lc15/Makefile.am
@@ -0,0 +1,102 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(LITECELL15_INCDIR)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(LIBGPS_CFLAGS) \
+ $(LIBSYSTEMD_CFLAGS) \
+ $(NULL)
+
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+AM_CFLAGS += -DENABLE_LC15BTS
+
+EXTRA_DIST = \
+ misc/lc15bts_mgr.h \
+ misc/lc15bts_misc.h \
+ misc/lc15bts_par.h \
+ misc/lc15bts_led.h \
+ misc/lc15bts_temp.h \
+ misc/lc15bts_power.h \
+ misc/lc15bts_clock.h \
+ misc/lc15bts_bid.h \
+ misc/lc15bts_nl.h \
+ misc/lc15bts_bts.h \
+ misc/lc15bts_swd.h \
+ hw_misc.h \
+ l1_if.h \
+ l1_transp.h \
+ lc15bts.h \
+ utils.h \
+ $(NULL)
+
+bin_PROGRAMS = osmo-bts-lc15 lc15bts-mgr lc15bts-util
+
+COMMON_SOURCES = \
+ main.c \
+ lc15bts.c \
+ l1_if.c \
+ oml.c \
+ lc15bts_vty.c \
+ tch.c \
+ hw_misc.c \
+ calib_file.c \
+ utils.c \
+ misc/lc15bts_par.c \
+ misc/lc15bts_bid.c \
+ $(NULL)
+
+osmo_bts_lc15_SOURCES = $(COMMON_SOURCES) l1_transp_hw.c
+osmo_bts_lc15_LDADD = \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(NULL)
+
+lc15bts_mgr_SOURCES = \
+ misc/lc15bts_mgr.c \
+ misc/lc15bts_misc.c \
+ misc/lc15bts_par.c \
+ misc/lc15bts_nl.c \
+ misc/lc15bts_temp.c \
+ misc/lc15bts_power.c \
+ misc/lc15bts_clock.c \
+ misc/lc15bts_bid.c \
+ misc/lc15bts_mgr_vty.c \
+ misc/lc15bts_mgr_nl.c \
+ misc/lc15bts_mgr_temp.c \
+ misc/lc15bts_mgr_calib.c \
+ misc/lc15bts_led.c \
+ misc/lc15bts_bts.c \
+ misc/lc15bts_swd.c \
+ $(NULL)
+
+lc15bts_mgr_LDADD = \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(LIBGPS_LIBS) \
+ $(LIBSYSTEMD_LIBS) \
+ $(NULL)
+
+lc15bts_util_SOURCES = \
+ misc/lc15bts_util.c \
+ misc/lc15bts_par.c \
+ $(NULL)
+lc15bts_util_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/src/osmo-bts-litecell15/calib_file.c b/src/osmo-bts-lc15/calib_file.c
index b7049df1..543be90f 100644
--- a/src/osmo-bts-litecell15/calib_file.c
+++ b/src/osmo-bts-lc15/calib_file.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -317,7 +317,7 @@ static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *d
fseek(st->fp, 0L, SEEK_END);
sz = ftell(st->fp);
- /* rewind read poiner */
+ /* rewind read pointer */
fseek(st->fp, 0L, SEEK_SET);
/* read file */
diff --git a/src/osmo-bts-litecell15/hw_misc.c b/src/osmo-bts-lc15/hw_misc.c
index 9f070bba..97ed3b75 100644
--- a/src/osmo-bts-litecell15/hw_misc.c
+++ b/src/osmo-bts-lc15/hw_misc.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/hw_misc.h b/src/osmo-bts-lc15/hw_misc.h
index 59ed04b7..59ed04b7 100644
--- a/src/osmo-bts-litecell15/hw_misc.h
+++ b/src/osmo-bts-lc15/hw_misc.h
diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-lc15/l1_if.c
index 2ac0b7ab..4ef90949 100644
--- a/src/osmo-bts-litecell15/l1_if.c
+++ b/src/osmo-bts-lc15/l1_if.c
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -54,6 +54,7 @@
#include <osmo-bts/l1sap.h>
#include <osmo-bts/msg_utils.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
+#include <osmo-bts/nm_common_fsm.h>
#include <nrw/litecell15/litecell15.h>
#include <nrw/litecell15/gsml1prim.h>
@@ -346,7 +347,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -394,9 +395,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
sapi = GsmL1_Sapi_Agch;
} else {
- LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
- "chan_nr %d link_id %d\n", l1sap->oph.primitive,
- l1sap->oph.operation, chan_nr, link_id);
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d chan_nr %d link_id %d\n",
+ l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
msgb_free(l1msg);
return -EINVAL;
}
@@ -457,9 +457,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
msgb_l2len(msg));
}
- LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -469,7 +468,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(l1msg);
} else
dtx_int_signal(lchan);
@@ -507,7 +506,6 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* create new message and fill data */
if (msg) {
- msgb_pull(msg, sizeof(*l1sap));
/* create new message */
nmsg = l1p_msgb_alloc();
if (!nmsg)
@@ -516,7 +514,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
rc = l1if_tch_encode(lchan,
l1p->u.phDataReq.msgUnitParam.u8Buffer,
&l1p->u.phDataReq.msgUnitParam.u8Size,
- msg->data, msg->len, u32Fn, use_cache,
+ msgb_l2(msg), msgb_l2len(msg), u32Fn, use_cache,
l1sap->u.tch.marker);
if (rc < 0) {
/* no data encoded for L1: smth will be generated below */
@@ -552,7 +550,12 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr);
}
/* send message to DSP's queue */
- osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg);
+ if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) < 0) {
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ msgb_free(nmsg);
+ return -ENOBUFS;
+ }
+
if (dtx_is_first_p1(lchan))
dtx_dispatch(lchan, E_FIRST);
else
@@ -681,7 +684,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
if (ts->flags & TS_F_PDCH_ACTIVE)
return GSM_PCHAN_PDCH;
return GSM_PCHAN_TCH_F;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return ts->dyn.pchan_is;
default:
return ts->pchan;
@@ -695,7 +698,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
uint8_t cbits = 0;
enum gsm_phys_chan_config pchan = pick_pchan(ts);
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
switch (sapi) {
case GsmL1_Sapi_Bcch:
@@ -795,6 +798,45 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
return (cbits << 3) | u8Tn;
}
+static const enum l1sap_common_sapi common_sapi_by_sapi_t[] = {
+ [GsmL1_Sapi_Idle] = L1SAP_COMMON_SAPI_IDLE,
+ [GsmL1_Sapi_Fcch] = L1SAP_COMMON_SAPI_FCCH,
+ [GsmL1_Sapi_Sch] = L1SAP_COMMON_SAPI_SCH,
+ [GsmL1_Sapi_Sacch] = L1SAP_COMMON_SAPI_SACCH,
+ [GsmL1_Sapi_Sdcch] = L1SAP_COMMON_SAPI_SDCCH,
+ [GsmL1_Sapi_Bcch] = L1SAP_COMMON_SAPI_BCCH,
+ [GsmL1_Sapi_Pch] = L1SAP_COMMON_SAPI_PCH,
+ [GsmL1_Sapi_Agch] = L1SAP_COMMON_SAPI_AGCH,
+ [GsmL1_Sapi_Cbch] = L1SAP_COMMON_SAPI_CBCH,
+ [GsmL1_Sapi_Rach] = L1SAP_COMMON_SAPI_RACH,
+ [GsmL1_Sapi_TchF] = L1SAP_COMMON_SAPI_TCH_F,
+ [GsmL1_Sapi_FacchF] = L1SAP_COMMON_SAPI_FACCH_F,
+ [GsmL1_Sapi_TchH] = L1SAP_COMMON_SAPI_TCH_H,
+ [GsmL1_Sapi_FacchH] = L1SAP_COMMON_SAPI_FACCH_H,
+ [GsmL1_Sapi_Nch] = L1SAP_COMMON_SAPI_NCH,
+ [GsmL1_Sapi_Pdtch] = L1SAP_COMMON_SAPI_PDTCH,
+ [GsmL1_Sapi_Pacch] = L1SAP_COMMON_SAPI_PACCH,
+ [GsmL1_Sapi_Pbcch] = L1SAP_COMMON_SAPI_PBCCH,
+ [GsmL1_Sapi_Pagch] = L1SAP_COMMON_SAPI_PAGCH,
+ [GsmL1_Sapi_Ppch] = L1SAP_COMMON_SAPI_PPCH,
+ [GsmL1_Sapi_Pnch] = L1SAP_COMMON_SAPI_PNCH,
+ [GsmL1_Sapi_Ptcch] = L1SAP_COMMON_SAPI_PTCCH,
+ [GsmL1_Sapi_Prach] = L1SAP_COMMON_SAPI_PRACH,
+};
+
+static enum l1sap_common_sapi get_common_sapi(GsmL1_Sapi_t sapi)
+{
+ if (sapi >= GsmL1_Sapi_NUM)
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ return common_sapi_by_sapi_t[sapi];
+}
+
+static void set_log_ctx_sapi(GsmL1_Sapi_t sapi)
+{
+ l1sap_log_ctx_sapi = get_common_sapi(sapi);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+}
+
static int handle_ph_readytosend_ind(struct lc15l1_hdl *fl1,
GsmL1_PhReadyToSendInd_t *rts_ind,
struct msgb *l1p_msg)
@@ -811,6 +853,8 @@ static int handle_ph_readytosend_ind(struct lc15l1_hdl *fl1,
uint8_t chan_nr, link_id;
uint32_t fn;
+ set_log_ctx_sapi(rts_ind->sapi);
+
/* check if primitive should be handled by common part */
chan_nr = chan_nr_by_sapi(&trx->ts[rts_ind->u8Tn], rts_ind->sapi,
rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
@@ -895,12 +939,8 @@ empty_frame:
goto tx;
}
-static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
-{
- LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, "
- "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality,
- m->fBer, m->i16BurstTiming);
-}
+#define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d"
+#define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming
static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
GsmL1_MeasParam_t *m, uint32_t fn)
@@ -933,6 +973,8 @@ static int handle_ph_data_ind(struct lc15l1_hdl *fl1, GsmL1_PhDataInd_t *data_in
int rc = 0;
int8_t rssi;
+ set_log_ctx_sapi(data_ind->sapi);
+
chan_nr = chan_nr_by_sapi(&trx->ts[data_ind->u8Tn], data_ind->sapi,
data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn);
fn = data_ind->u32Fn;
@@ -949,10 +991,10 @@ static int handle_ph_data_ind(struct lc15l1_hdl *fl1, GsmL1_PhDataInd_t *data_in
process_meas_res(trx, chan_nr, &data_ind->measParam, fn);
- DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
+ DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
get_value_string(lc15bts_l1sapi_names, data_ind->sapi), (uint32_t)data_ind->hLayer2,
- osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size));
- dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
+ osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
+ LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -985,11 +1027,10 @@ static int handle_ph_data_ind(struct lc15l1_hdl *fl1, GsmL1_PhDataInd_t *data_in
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.fn = fn;
l1sap->u.data.rssi = rssi;
- if (!pcu_direct) {
- l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
- l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
- l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
- }
+ l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
+ l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
+ l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
+
return l1sap_up(trx, l1sap);
}
@@ -1002,7 +1043,9 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
int rc;
struct ph_rach_ind_param rach_ind_param;
- dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
+ set_log_ctx_sapi(ra_ind->sapi);
+ LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
+ LOG_PARAM_MEAS(&ra_ind->measParam));
if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) {
@@ -1204,7 +1247,6 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
Litecell15_Prim_t *sysp = msgb_sysprim(resp);
GsmL1_Status_t status;
int on = 0;
- unsigned int i;
if (sysp->id == Litecell15_PrimId_ActivateRfCnf)
on = 1;
@@ -1217,27 +1259,26 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_INFO, "Rx RF-%sACT.conf (status=%s)\n", on ? "" : "DE",
get_value_string(lc15bts_l1status_names, status));
+ struct bts_lc15_priv *bts_lc15 = trx->bts->model_priv;
if (on) {
if (status != GsmL1_Status_Success) {
LOGP(DL1C, LOGL_FATAL, "RF-ACT.conf with status %s\n",
get_value_string(lc15bts_l1status_names, status));
bts_shutdown(trx->bts, "RF-ACT failure");
- } else
- bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
+ } else {
+ if (bts_lc15->led_ctrl_mode == LC15_LED_CONTROL_BTS)
+ bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
+ }
/* signal availability */
- 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 (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
} else {
- bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
- oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
+ if (bts_lc15->led_ctrl_mode == LC15_LED_CONTROL_BTS)
+ bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
msgb_free(resp);
@@ -1250,17 +1291,28 @@ int l1if_activate_rf(struct lc15l1_hdl *hdl, int on)
{
struct msgb *msg = sysp_msgb_alloc();
Litecell15_Prim_t *sysp = msgb_sysprim(msg);
+ struct phy_instance *pinst = hdl->phy_inst;
if (on) {
sysp->id = Litecell15_PrimId_ActivateRfReq;
sysp->u.activateRfReq.msgq.u8UseTchMsgq = 0;
sysp->u.activateRfReq.msgq.u8UsePdtchMsgq = pcu_direct;
- sysp->u.activateRfReq.u8UnusedTsMode = 0;
+ sysp->u.activateRfReq.u8UnusedTsMode = pinst->u.lc15.pedestal_mode;
+
sysp->u.activateRfReq.u8McCorrMode = 0;
+ /* diversity mode: 0: SISO-A, 1: SISO-B, 2: MRC */
+ sysp->u.activateRfReq.u8DiversityMode = pinst->u.lc15.diversity_mode;
+
/* maximum cell size in quarter-bits, 90 == 12.456 km */
- sysp->u.activateRfReq.u8MaxCellSize = 90;
+ sysp->u.activateRfReq.u8MaxCellSize = pinst->u.lc15.max_cell_size;
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ /* auto tx power adjustment mode 0:none, 1: automatic*/
+ sysp->u.activateRfReq.u8EnAutoPowerAdjust = pinst->u.lc15.tx_pwr_adj_mode;
+#endif
+
} else {
sysp->id = Litecell15_PrimId_DeactivateRfReq;
}
@@ -1374,6 +1426,30 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_FATAL, "BTS band %s not supported by hw\n",
gsm_band_name(trx->bts->band));
+ /* Frequency bands indicated to the BSC */
+ switch (fl1h->hw_info.band_support) {
+ case GSM_BAND_450:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_450;
+ break;
+ case GSM_BAND_480:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_480;
+ break;
+ case GSM_BAND_850:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
+ break;
+ case GSM_BAND_900:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
+ break;
+ case GSM_BAND_1800:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
+ break;
+ case GSM_BAND_1900:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
+ break;
+ }
+
/* Request the activation */
l1if_activate_rf(fl1h, 1);
@@ -1549,6 +1625,57 @@ int l1if_close(struct lc15l1_hdl *fl1h)
return 0;
}
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+static int dsp_alive_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
+{
+ Litecell15_Prim_t *sysp = msgb_sysprim(resp);
+ Litecell15_IsAliveCnf_t *sac = &sysp->u.isAliveCnf;
+ struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx);
+
+ fl1h->hw_alive.dsp_alive_cnt++;
+ LOGP(DL1C, LOGL_DEBUG, "Rx SYS prim %s, status=%d (%d)\n",
+ get_value_string(lc15bts_sysprim_names, sysp->id), sac->status, trx->nr);
+
+ msgb_free(resp);
+ return 0;
+}
+
+static void dsp_alive_timer_cb(void *data)
+{
+ struct lc15l1_hdl *fl1h = data;
+ struct gsm_bts_trx *trx = fl1h->phy_inst->trx;
+ struct msgb *msg = sysp_msgb_alloc();
+ int rc;
+
+ Litecell15_Prim_t *sys_prim = msgb_sysprim(msg);
+ sys_prim->id = Litecell15_PrimId_IsAliveReq;
+
+ if (fl1h->hw_alive.dsp_alive_cnt == 0) {
+ LOGP(DL1C, LOGL_ERROR, "Timeout waiting for SYS prim %s primitive (%d)\n",
+ get_value_string(lc15bts_sysprim_names, sys_prim->id + 1), trx->nr);
+
+ if( fl1h->phy_inst->trx ){
+ fl1h->phy_inst->trx->mo.obj_inst.trx_nr = fl1h->phy_inst->trx->nr;
+ }
+ }
+
+ LOGP(DL1C, LOGL_DEBUG, "Tx SYS prim %s (%d)\n",
+ get_value_string(lc15bts_sysprim_names, sys_prim->id), trx->nr);
+
+ rc = l1if_req_compl(fl1h, msg, dsp_alive_compl_cb, NULL);
+ if (rc < 0) {
+ LOGP(DL1C, LOGL_FATAL, "Failed to send %s primitive\n", get_value_string(lc15bts_sysprim_names, sys_prim->id));
+ return;
+ }
+
+ /* restart timer */
+ fl1h->hw_alive.dsp_alive_cnt = 0;
+ osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0);
+
+ return;
+}
+#endif
+
int bts_model_phy_link_open(struct phy_link *plink)
{
struct phy_instance *pinst = phy_instance_by_num(plink, 0);
@@ -1568,6 +1695,29 @@ int bts_model_phy_link_open(struct phy_link *plink)
return -EIO;
}
+ /* Set default PHY parameters */
+ if (!pinst->u.lc15.max_cell_size)
+ pinst->u.lc15.max_cell_size = LC15_BTS_MAX_CELL_SIZE_DEFAULT;
+
+ if (!pinst->u.lc15.diversity_mode)
+ pinst->u.lc15.diversity_mode = LC15_BTS_DIVERSITY_MODE_DEFAULT;
+
+ if (!pinst->u.lc15.pedestal_mode)
+ pinst->u.lc15.pedestal_mode = LC15_BTS_PEDESTAL_MODE_DEFAULT;
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ if (!pinst->u.lc15.dsp_alive_period)
+ pinst->u.lc15.dsp_alive_period = LC15_BTS_DSP_ALIVE_TMR_DEFAULT;
+
+ if (!pinst->u.lc15.tx_pwr_adj_mode)
+ pinst->u.lc15.tx_pwr_adj_mode = LC15_BTS_TX_PWR_ADJ_DEFAULT;
+
+ if (!pinst->u.lc15.tx_pwr_red_8psk)
+ pinst->u.lc15.tx_pwr_red_8psk = LC15_BTS_TX_RED_PWR_8PSK_DEFAULT;
+
+ if (!pinst->u.lc15.tx_c0_idle_pwr_red)
+ pinst->u.lc15.tx_c0_idle_pwr_red = LC15_BTS_TX_C0_IDLE_RED_PWR_DEFAULT;
+#endif
struct lc15l1_hdl *fl1h = pinst->u.lc15.hdl;
fl1h->dsp_trace_f = dsp_trace;
@@ -1576,5 +1726,26 @@ int bts_model_phy_link_open(struct phy_link *plink)
phy_link_state_set(plink, PHY_LINK_CONNECTED);
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ /* Send first IS_ALIVE primitive */
+ struct msgb *msg = sysp_msgb_alloc();
+ int rc;
+
+ Litecell15_Prim_t *sys_prim = msgb_sysprim(msg);
+ sys_prim->id = Litecell15_PrimId_IsAliveReq;
+
+ rc = l1if_req_compl(fl1h, msg, dsp_alive_compl_cb, NULL);
+ if (rc < 0) {
+ LOGP(DL1C, LOGL_FATAL, "Failed to send %s primitive\n", get_value_string(lc15bts_sysprim_names, sys_prim->id));
+ return -EIO;
+ }
+
+ /* initialize DSP heart beat alive timer */
+ osmo_timer_setup(&fl1h->hw_alive.dsp_alive_timer, dsp_alive_timer_cb, fl1h);
+ fl1h->hw_alive.dsp_alive_cnt = 0;
+ fl1h->hw_alive.dsp_alive_period = pinst->u.lc15.dsp_alive_period;
+ osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0);
+#endif
+
return 0;
}
diff --git a/src/osmo-bts-litecell15/l1_if.h b/src/osmo-bts-lc15/l1_if.h
index aac26075..655e63fb 100644
--- a/src/osmo-bts-litecell15/l1_if.h
+++ b/src/osmo-bts-lc15/l1_if.h
@@ -30,6 +30,12 @@ enum {
_NUM_MQ_WRITE
};
+/* gsm_bts->model_priv, specific to Litecell 1.5 BTS */
+struct bts_lc15_priv {
+ uint8_t led_ctrl_mode; /* 0: control by BTS, 1: not control by BTS */
+ unsigned int rtp_drift_thres_ms; /* RTP timestamp drift detection threshold */
+};
+
struct calib_send_state {
FILE *fp;
const char *path;
@@ -62,6 +68,15 @@ struct lc15l1_hdl {
struct calib_send_state st;
uint8_t last_rf_mute[8];
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ struct {
+ struct osmo_timer_list dsp_alive_timer;
+ unsigned int dsp_alive_cnt;
+ uint8_t dsp_alive_period;
+ } hw_alive;
+#endif
+
};
#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h)
@@ -118,14 +133,14 @@ int bts_check_for_ciph_cmd(struct lc15l1_hdl *fl1h,
int l1if_ms_pwr_ctrl(struct gsm_lchan *lchan, const int uplink_target,
const uint8_t ms_power, const float rxLevel);
-static inline struct lc15l1_hdl *trx_lc15l1_hdl(struct gsm_bts_trx *trx)
+static inline struct lc15l1_hdl *trx_lc15l1_hdl(const struct gsm_bts_trx *trx)
{
- struct phy_instance *pinst = trx_phy_instance(trx);
+ const struct phy_instance *pinst = trx_phy_instance(trx);
OSMO_ASSERT(pinst);
return pinst->u.lc15.hdl;
}
-static inline struct gsm_bts_trx *lc15l1_hdl_trx(struct lc15l1_hdl *fl1h)
+static inline struct gsm_bts_trx *lc15l1_hdl_trx(const struct lc15l1_hdl *fl1h)
{
OSMO_ASSERT(fl1h->phy_inst);
return fl1h->phy_inst->trx;
diff --git a/src/osmo-bts-litecell15/l1_transp.h b/src/osmo-bts-lc15/l1_transp.h
index 7d6772e8..7d6772e8 100644
--- a/src/osmo-bts-litecell15/l1_transp.h
+++ b/src/osmo-bts-lc15/l1_transp.h
diff --git a/src/osmo-bts-litecell15/l1_transp_hw.c b/src/osmo-bts-lc15/l1_transp_hw.c
index c8972be5..63b596b2 100644
--- a/src/osmo-bts-litecell15/l1_transp_hw.c
+++ b/src/osmo-bts-lc15/l1_transp_hw.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -88,18 +88,18 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
queue = container_of(fd, struct osmo_wqueue, bfd);
- if (what & BSC_FD_READ)
+ if (what & OSMO_FD_READ)
queue->read_cb(fd);
- if (what & BSC_FD_EXCEPT)
+ if (what & OSMO_FD_EXCEPT)
queue->except_cb(fd);
- if (what & BSC_FD_WRITE) {
+ if (what & OSMO_FD_WRITE) {
struct iovec iov[5];
struct msgb *msg, *tmp;
int written, count = 0;
- fd->when &= ~BSC_FD_WRITE;
+ osmo_fd_write_disable(fd);
llist_for_each_entry(msg, &queue->msg_queue, list) {
/* more writes than we have */
@@ -117,7 +117,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
/* Nothing scheduled? This should not happen. */
if (count == 0) {
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -125,7 +125,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
if (written < 0) {
/* nothing written?! */
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -144,7 +144,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
}
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
}
return 0;
@@ -265,11 +265,7 @@ int l1if_transport_open(int q, struct lc15l1_hdl *hdl)
buf, 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;
+ osmo_fd_setup(read_ofd, rc, OSMO_FD_READ, l1if_fd_cb, hdl, q);
rc = osmo_fd_register(read_ofd);
if (rc < 0) {
close(read_ofd->fd);
@@ -288,11 +284,7 @@ int l1if_transport_open(int q, struct lc15l1_hdl *hdl)
}
osmo_wqueue_init(wq, 10);
wq->write_cb = l1fd_write_cb;
- write_ofd->cb = wqueue_vector_cb;
- write_ofd->fd = rc;
- write_ofd->priv_nr = q;
- write_ofd->data = hdl;
- write_ofd->when = BSC_FD_WRITE;
+ osmo_fd_setup(write_ofd, rc, OSMO_FD_WRITE, wqueue_vector_cb, hdl, q);
rc = osmo_fd_register(write_ofd);
if (rc < 0) {
close(write_ofd->fd);
diff --git a/src/osmo-bts-litecell15/lc15bts.c b/src/osmo-bts-lc15/lc15bts.c
index 172a7e45..40077902 100644
--- a/src/osmo-bts-litecell15/lc15bts.c
+++ b/src/osmo-bts-lc15/lc15bts.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -121,6 +121,14 @@ enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id)
case Litecell15_PrimId_MuteRfCnf: return L1P_T_CONF;
case Litecell15_PrimId_SetRxAttenReq: return L1P_T_REQ;
case Litecell15_PrimId_SetRxAttenCnf: return L1P_T_CONF;
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ case Litecell15_PrimId_IsAliveReq: return L1P_T_REQ;
+ case Litecell15_PrimId_IsAliveCnf: return L1P_T_CONF;
+ case Litecell15_PrimId_SetMaxCellSizeReq: return L1P_T_REQ;
+ case Litecell15_PrimId_SetMaxCellSizeCnf: return L1P_T_CONF;
+ case Litecell15_PrimId_SetC0IdleSlotPowerReductionReq: return L1P_T_REQ;
+ case Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf: return L1P_T_CONF;
+#endif
default: return L1P_T_INVALID;
}
}
@@ -142,6 +150,14 @@ const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1] = {
{ Litecell15_PrimId_MuteRfCnf, "MUTE-RF.cnf" },
{ Litecell15_PrimId_SetRxAttenReq, "SET-RX-ATTEN.req" },
{ Litecell15_PrimId_SetRxAttenCnf, "SET-RX-ATTEN-CNF.cnf" },
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ { Litecell15_PrimId_IsAliveReq, "IS-ALIVE.req" },
+ { Litecell15_PrimId_IsAliveCnf, "IS-ALIVE-CNF.cnf" },
+ { Litecell15_PrimId_SetMaxCellSizeReq, "SET-MAX-CELL-SIZE.req" },
+ { Litecell15_PrimId_SetMaxCellSizeCnf, "SET-MAX-CELL-SIZE.cnf" },
+ { Litecell15_PrimId_SetC0IdleSlotPowerReductionReq, "SET-C0-IDLE-PWR-RED.req" },
+ { Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf, "SET-C0-IDLE-PWR-RED.cnf" },
+#endif
{ 0, NULL }
};
@@ -155,6 +171,11 @@ Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id)
case Litecell15_PrimId_SetCalibTblReq: return Litecell15_PrimId_SetCalibTblCnf;
case Litecell15_PrimId_MuteRfReq: return Litecell15_PrimId_MuteRfCnf;
case Litecell15_PrimId_SetRxAttenReq: return Litecell15_PrimId_SetRxAttenCnf;
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ case Litecell15_PrimId_IsAliveReq: return Litecell15_PrimId_IsAliveCnf;
+ case Litecell15_PrimId_SetMaxCellSizeReq: return Litecell15_PrimId_SetMaxCellSizeCnf;
+ case Litecell15_PrimId_SetC0IdleSlotPowerReductionReq: return Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf;
+#endif
default: return -1; // Weak
}
}
diff --git a/src/osmo-bts-lc15/lc15bts.h b/src/osmo-bts-lc15/lc15bts.h
new file mode 100644
index 00000000..ecfeb3da
--- /dev/null
+++ b/src/osmo-bts-lc15/lc15bts.h
@@ -0,0 +1,101 @@
+#ifndef LC15BTS_H
+#define LC15BTS_H
+
+#include <stdlib.h>
+#include <osmocom/core/utils.h>
+
+#include <nrw/litecell15/litecell15.h>
+#include <nrw/litecell15/gsml1const.h>
+
+/*
+ * Depending on the firmware version either GsmL1_Prim_t or Litecell15_Prim_t
+ * is the bigger struct. For earlier firmware versions the GsmL1_Prim_t was the
+ * bigger struct.
+ */
+#define LC15BTS_PRIM_SIZE \
+ (OSMO_MAX(sizeof(Litecell15_Prim_t), sizeof(GsmL1_Prim_t)) + 128)
+
+enum l1prim_type {
+ L1P_T_INVALID, /* this must be 0 to detect uninitialized elements */
+ L1P_T_REQ,
+ L1P_T_CONF,
+ L1P_T_IND,
+};
+
+
+enum lc15_diversity_mode{
+ LC15_DIVERSITY_SISO_A = 0,
+ LC15_DIVERSITY_SISO_B,
+ LC15_DIVERSITY_MRC,
+};
+
+enum lc15_pedestal_mode{
+ LC15_PEDESTAL_OFF = 0,
+ LC15_PEDESTAL_ON,
+};
+
+enum lc15_led_control_mode{
+ LC15_LED_CONTROL_BTS = 0,
+ LC15_LED_CONTROL_EXT,
+};
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+enum lc15_auto_pwr_adjust_mode{
+ LC15_TX_PWR_ADJ_NONE = 0,
+ LC15_TX_PWR_ADJ_AUTO,
+};
+#endif
+
+enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id);
+extern const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1];
+GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id);
+
+enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id);
+extern const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1];
+Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id);
+
+extern const struct value_string lc15bts_l1sapi_names[GsmL1_Sapi_NUM+1];
+extern const struct value_string lc15bts_l1status_names[GSML1_STATUS_NUM+1];
+
+extern const struct value_string lc15bts_tracef_names[29];
+extern const struct value_string lc15bts_tracef_docs[29];
+
+extern const struct value_string lc15bts_tch_pl_names[15];
+
+extern const struct value_string lc15bts_clksrc_names[10];
+
+extern const struct value_string lc15bts_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
+};
+
+extern const uint8_t pdch_msu_size[_NUM_PDCH_CS];
+
+/* LC15 default parameters */
+#define LC15_BTS_MAX_CELL_SIZE_DEFAULT 166 /* 166 qbits is default value */
+#define LC15_BTS_DIVERSITY_MODE_DEFAULT 0 /* SISO-A is default mode */
+#define LC15_BTS_PEDESTAL_MODE_DEFAULT 0 /* Unused TS is off by default */
+#define LC15_BTS_LED_CTRL_MODE_DEFAULT 0 /* LED is controlled by BTS by default */
+#define LC15_BTS_RTP_DRIFT_THRES_DEFAULT 0 /* Default RTP drift threshold is 0 ms (disabled) */
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+#define LC15_BTS_DSP_ALIVE_TMR_DEFAULT 5 /* Default DSP alive timer is 5 seconds */
+#define LC15_BTS_TX_PWR_ADJ_DEFAULT 0 /* Default Tx power auto adjustment is none */
+#define LC15_BTS_TX_RED_PWR_8PSK_DEFAULT 0 /* Default 8-PSK maximum power level is 0 dB */
+#define LC15_BTS_TX_C0_IDLE_RED_PWR_DEFAULT 0 /* Default C0 idle slot reduction power level is 0 dB */
+#endif
+
+#endif /* LC15BTS_H */
diff --git a/src/osmo-bts-litecell15/lc15bts_vty.c b/src/osmo-bts-lc15/lc15bts_vty.c
index d27ec281..5efbfcc5 100644
--- a/src/osmo-bts-litecell15/lc15bts_vty.c
+++ b/src/osmo-bts-lc15/lc15bts_vty.c
@@ -2,7 +2,7 @@
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
* Copyright (C) 2016 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* Based on sysmoBTS:
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2012,2013 by Holger Hans Peter Freyther
@@ -43,6 +43,11 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/misc.h>
+#include <osmocom/ctrl/control_cmd.h>
+#include <osmo-bts/signal.h>
+#include <osmo-bts/oml.h>
+#include <osmo-bts/bts.h>
+
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
@@ -55,6 +60,7 @@
#include "utils.h"
extern int lchan_activate(struct gsm_lchan *lchan);
+extern int rsl_tx_preproc_meas_res(struct gsm_lchan *lchan);
#define TRX_STR "Transceiver related commands\n" "TRX number\n"
@@ -63,7 +69,32 @@ extern int lchan_activate(struct gsm_lchan *lchan);
TRX_STR
#define DSP_TRACE_F_STR "DSP Trace Flag\n"
-static struct gsm_bts *vty_bts;
+static const struct value_string lc15_diversity_mode_strs[] = {
+ { LC15_DIVERSITY_SISO_A, "siso-a" },
+ { LC15_DIVERSITY_SISO_B, "siso-b" },
+ { LC15_DIVERSITY_MRC, "mrc" },
+ { 0, NULL }
+};
+
+static const struct value_string lc15_pedestal_mode_strs[] = {
+ { LC15_PEDESTAL_OFF, "off" },
+ { LC15_PEDESTAL_ON, "on" },
+ { 0, NULL }
+};
+
+static const struct value_string lc15_led_mode_strs[] = {
+ { LC15_LED_CONTROL_BTS, "bts" },
+ { LC15_LED_CONTROL_EXT, "external" },
+ { 0, NULL }
+};
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+static const struct value_string lc15_auto_adj_pwr_strs[] = {
+ { LC15_TX_PWR_ADJ_NONE, "none" },
+ { LC15_TX_PWR_ADJ_AUTO, "auto" },
+ { 0, NULL }
+};
+#endif
/* configuration */
@@ -87,7 +118,7 @@ DEFUN(cfg_phy_dsp_trace_f, cfg_phy_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(lc15bts_tracef_names, argv[1]);
+ flag = get_string_value(lc15bts_tracef_names, argv[0]);
pinst->u.lc15.dsp_trace_f |= flag;
return CMD_SUCCESS;
@@ -99,7 +130,7 @@ DEFUN(cfg_phy_no_dsp_trace_f, cfg_phy_no_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(lc15bts_tracef_names, argv[1]);
+ flag = get_string_value(lc15bts_tracef_names, argv[0]);
pinst->u.lc15.dsp_trace_f &= ~flag;
return CMD_SUCCESS;
@@ -109,11 +140,11 @@ DEFUN(cfg_phy_no_dsp_trace_f, cfg_phy_no_dsp_trace_f_cmd,
/* runtime */
DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd,
- "show trx <0-0> dsp-trace-flags",
+ "show dsp-trace-flags trx <0-0>",
SHOW_TRX_STR "Display the current setting of the DSP trace flags")
{
int trx_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct lc15l1_hdl *fl1h;
int i;
@@ -235,7 +266,7 @@ DEFUN(activate_lchan, activate_lchan_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[3]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -256,9 +287,9 @@ DEFUN(set_tx_power, set_tx_power_cmd,
{
int trx_nr = atoi(argv[0]);
int power = atoi(argv[1]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
- power_ramp_start(trx, to_mdB(power), 1);
+ power_ramp_start(trx, to_mdB(power), 1, NULL);
return CMD_SUCCESS;
}
@@ -273,7 +304,7 @@ DEFUN(loopback, loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -292,7 +323,7 @@ DEFUN(no_loopback, no_loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -302,39 +333,155 @@ DEFUN(no_loopback, no_loopback_cmd,
}
DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
- "nominal-tx-power <0-40>",
- "Set the nominal transmit output power in dBm\n"
- "Nominal transmit output power level in dBm\n")
+ "nominal-tx-power <0-40>",
+ "Set the nominal transmit output power in dBm\n"
+ "Nominal transmit output power level in dBm\n")
{
int nominal_power = atoi(argv[0]);
struct gsm_bts_trx *trx = vty->index;
- if (( nominal_power > 40 ) || ( nominal_power < 0 )) {
- vty_out(vty, "Nominal Tx power level must be between 0 and 40 dBm (%d) %s",
- nominal_power, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
trx->nominal_power = nominal_power;
trx->power_params.trx_p_max_out_mdBm = to_mdB(nominal_power);
return CMD_SUCCESS;
}
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+DEFUN(cfg_phy_max_cell_size, cfg_phy_max_cell_size_cmd,
+ "max-cell-size <0-166>",
+ "Set the maximum cell size in qbits\n")
+{
+ struct phy_instance *pinst = vty->index;
+ int cell_size = (uint8_t)atoi(argv[0]);
+
+ pinst->u.lc15.max_cell_size = (uint8_t)cell_size;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_phy_diversity_mode, cfg_phy_diversity_mode_cmd,
+ "diversity-mode (siso-a|siso-b|mrc)",
+ "Set reception diversity mode \n"
+ "Reception diversity mode can be (siso-a, siso-b, mrc)\n")
+{
+ struct phy_instance *pinst = vty->index;
+ int val = get_string_value(lc15_diversity_mode_strs, argv[0]);
+
+ OSMO_ASSERT(val != -EINVAL);
+
+ pinst->u.lc15.diversity_mode = (uint8_t)val;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_phy_pedestal_mode, cfg_phy_pedestal_mode_cmd,
+ "pedestal-mode (on|off)",
+ "Set unused time-slot transmission in pedestal mode\n"
+ "Transmission pedestal mode can be (off, on)\n")
+{
+ struct phy_instance *pinst = vty->index;
+ int val = get_string_value(lc15_pedestal_mode_strs, argv[0]);
+
+ OSMO_ASSERT(val != -EINVAL);
+
+ pinst->u.lc15.pedestal_mode = (uint8_t)val;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_led_mode, cfg_bts_led_mode_cmd,
+ "led-control-mode (bts|external)",
+ "Set LED controlled by BTS or external software\n"
+ "LED can be controlled by (bts, external)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int val = get_string_value(lc15_led_mode_strs, argv[0]);
+
+ OSMO_ASSERT(val != -EINVAL);
+
+ struct bts_lc15_priv *bts_lc15 = bts->model_priv;
+ bts_lc15->led_ctrl_mode = (uint8_t)val;
+ return CMD_SUCCESS;
+}
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+DEFUN(cfg_phy_dsp_alive_timer, cfg_phy_dsp_alive_timer_cmd,
+ "dsp-alive-period <0-60>",
+ "Set DSP alive timer period in second\n")
+{
+ struct phy_instance *pinst = vty->index;
+ uint8_t period = (uint8_t)atoi(argv[0]);
+
+ pinst->u.lc15.dsp_alive_period = period;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_phy_auto_tx_pwr_adj, cfg_phy_auto_tx_pwr_adj_cmd,
+ "pwr-adj-mode (none|auto)",
+ "Set output power adjustment mode\n")
{
+ struct phy_instance *pinst = vty->index;
+ int val = get_string_value(lc15_auto_adj_pwr_strs, argv[0]);
+
+ OSMO_ASSERT(val != -EINVAL);
+
+ pinst->u.lc15.tx_pwr_adj_mode = (uint8_t)val;
+ return CMD_SUCCESS;
}
-void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
+DEFUN(cfg_phy_tx_red_pwr_8psk, cfg_phy_tx_red_pwr_8psk_cmd,
+ "tx-red-pwr-8psk <0-40>",
+ "Set reduction output power for 8-PSK scheme in dB unit\n")
+{
+ struct phy_instance *pinst = vty->index;
+ int val = atoi(argv[0]);
+
+ pinst->u.lc15.tx_pwr_red_8psk = (uint8_t)val;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_phy_c0_idle_red_pwr, cfg_phy_c0_idle_red_pwr_cmd,
+ "c0-idle-red-pwr <0-40>",
+ "Set reduction output power for C0 idle slot in dB unit\n")
+{
+ struct phy_instance *pinst = vty->index;
+ int val = atoi(argv[0]);
+
+ pinst->u.lc15.tx_c0_idle_pwr_red = (uint8_t)val;
+ return CMD_SUCCESS;
+}
+#endif
+
+DEFUN(cfg_bts_rtp_drift_threshold, cfg_bts_rtp_drift_threshold_cmd,
+ "rtp-drift-threshold <0-10000>",
+ "RTP parameters\n"
+ "RTP timestamp drift threshold in ms\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ struct bts_lc15_priv *bts_lc15 = bts->model_priv;
+ bts_lc15->rtp_drift_thres_ms = (unsigned int) atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
+{
+ const struct bts_lc15_priv *bts_lc15 = bts->model_priv;
+ vty_out(vty, " led-control-mode %s%s",
+ get_value_string(lc15_led_mode_strs, bts_lc15->led_ctrl_mode), VTY_NEWLINE);
+
+ vty_out(vty, " rtp-drift-threshold %d%s",
+ bts_lc15->rtp_drift_thres_ms, VTY_NEWLINE);
+
+}
+
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,VTY_NEWLINE);
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
int i;
@@ -349,41 +496,62 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst
if (pinst->u.lc15.calib_path)
vty_out(vty, " trx-calibration-path %s%s",
pinst->u.lc15.calib_path, VTY_NEWLINE);
+
+ vty_out(vty, " max-cell-size %d%s",
+ pinst->u.lc15.max_cell_size, VTY_NEWLINE);
+
+ vty_out(vty, " diversity-mode %s%s",
+ get_value_string(lc15_diversity_mode_strs, pinst->u.lc15.diversity_mode), VTY_NEWLINE);
+
+ vty_out(vty, " pedestal-mode %s%s",
+ get_value_string(lc15_pedestal_mode_strs, pinst->u.lc15.pedestal_mode) , VTY_NEWLINE);
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ vty_out(vty, " dsp-alive-period %d%s",
+ pinst->u.lc15.dsp_alive_period, VTY_NEWLINE);
+
+ vty_out(vty, " pwr-adj-mode %s%s",
+ get_value_string(lc15_auto_adj_pwr_strs, pinst->u.lc15.tx_pwr_adj_mode), VTY_NEWLINE);
+
+ vty_out(vty, " tx-red-pwr-8psk %d%s",
+ pinst->u.lc15.tx_pwr_red_8psk, VTY_NEWLINE);
+
+ vty_out(vty, " c0-idle-red-pwr %d%s",
+ pinst->u.lc15.tx_c0_idle_pwr_red, VTY_NEWLINE);
+#endif
}
-int bts_model_vty_init(struct gsm_bts *bts)
+int bts_model_vty_init(void *ctx)
{
- vty_bts = bts;
-
/* runtime-patch the command strings with debug levels */
- dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, lc15bts_tracef_names,
+ dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, lc15bts_tracef_names,
"phy <0-0> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, lc15bts_tracef_docs,
+ dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, lc15bts_tracef_docs,
TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
- no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, lc15bts_tracef_names,
+ no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, lc15bts_tracef_names,
"no phy <0-0> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, lc15bts_tracef_docs,
+ no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, lc15bts_tracef_docs,
NO_STR TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
- cfg_phy_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts,
+ cfg_phy_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx,
lc15bts_tracef_names,
"dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- cfg_phy_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts,
+ cfg_phy_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx,
lc15bts_tracef_docs,
DSP_TRACE_F_STR,
"\n", "", 0);
- cfg_phy_no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts,
+ cfg_phy_no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx,
lc15bts_tracef_names,
"no dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- cfg_phy_no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts,
+ cfg_phy_no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx,
lc15bts_tracef_docs,
NO_STR DSP_TRACE_F_STR,
"\n", "", 0);
@@ -401,6 +569,8 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(BTS_NODE, &cfg_bts_auto_band_cmd);
install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd);
+ install_element(BTS_NODE, &cfg_bts_led_mode_cmd);
+ install_element(BTS_NODE, &cfg_bts_rtp_drift_threshold_cmd);
install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
@@ -408,6 +578,15 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(PHY_INST_NODE, &cfg_phy_no_dsp_trace_f_cmd);
install_element(PHY_INST_NODE, &cfg_phy_cal_path_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_diversity_mode_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_pedestal_mode_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_max_cell_size_cmd);
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ install_element(PHY_INST_NODE, &cfg_phy_dsp_alive_timer_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_auto_tx_pwr_adj_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_tx_red_pwr_8psk_cmd);
+ install_element(PHY_INST_NODE, &cfg_phy_c0_idle_red_pwr_cmd);
+#endif
return 0;
}
diff --git a/src/osmo-bts-litecell15/main.c b/src/osmo-bts-lc15/main.c
index c47d76d0..23601299 100644
--- a/src/osmo-bts-litecell15/main.c
+++ b/src/osmo-bts-lc15/main.c
@@ -2,7 +2,7 @@
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
* Copyright (C) 2016 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* Based on sysmoBTS:
* (C) 2011-2013 by Harald Welte <laforge@gnumonks.org>
*
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -76,50 +76,69 @@ static int write_status_file(char *status_file, char *status_str)
#include "utils.h"
#include "l1_if.h"
#include "hw_misc.h"
-#include "oml_router.h"
#include "misc/lc15bts_bid.h"
unsigned int dsp_trace = 0x00000000;
int bts_model_init(struct gsm_bts *bts)
{
- struct gsm_bts_trx *trx;
struct stat st;
- static struct osmo_fd accept_fd, read_fd;
- int rc;
+ struct bts_lc15_priv *bts_lc15 = talloc(bts, struct bts_lc15_priv);
+
+ bts->model_priv = bts_lc15;
bts->variant = BTS_OSMO_LITECELL15;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
+ | NM_IPAC_MASK_GPRS_CODING_MCS;
- rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd);
- if (rc < 0) {
- fprintf(stderr, "Error creating the OML router: %s rc=%d\n",
- OML_ROUTER_PATH, rc);
- exit(1);
- }
+ /* specific default values for LC15 platform */
+ bts_lc15->led_ctrl_mode = LC15_BTS_LED_CTRL_MODE_DEFAULT;
+ /* RTP drift threshold default */
+ bts_lc15->rtp_drift_thres_ms = LC15_BTS_RTP_DRIFT_THRES_DEFAULT;
if (stat(LC15BTS_RF_LOCK_PATH, &st) == 0) {
LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n");
exit(23);
}
- gsm_bts_set_feature(bts, BTS_FEAT_GPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_EGPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
- gsm_bts_set_feature(bts, BTS_FEAT_AGCH_PCH_PROP);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_EFR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
-
- bts_model_vty_init(bts);
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_AGCH_PCH_PROP);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_EFR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
+
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP);
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER);
+
+ /* The default HR codec output format in the absence of saved
+ * vty config needs to match what was implemented previously,
+ * for the sake of existing deployments, i.e., to avoid
+ * a surprise functional change upon software update. */
+ bts->emit_hr_rfc5993 = false;
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = 0x00; /* updated in info_compl_cb() */
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH;
+
trx->nominal_power = 40;
trx->power_params.trx_p_max_out_mdBm = to_mdB(trx->bts->c0->nominal_power);
return 0;
@@ -159,9 +178,11 @@ void bts_update_status(enum bts_global_status which, int on)
void bts_model_print_help()
{
- printf( " -w --hw-version Print the targeted HW Version\n"
- " -M --pcu-direct Force PCU to access message queue for PDCH dchannel directly\n"
- " -p --dsp-trace Set DSP trace flags\n"
+ printf( "\nModel specific options:\n"
+ " -w --hw-version Print the targeted HW Version\n"
+ " -M --pcu-direct Force PCU to access message queue for "
+ "PDCH dchannel directly\n"
+ " -p --dsp-trace Set DSP trace flags\n"
);
}
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_bid.c b/src/osmo-bts-lc15/misc/lc15bts_bid.c
index 9284b62e..9267e06f 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_bid.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_bid.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_bid.h b/src/osmo-bts-lc15/misc/lc15bts_bid.h
index a71fdd7e..a71fdd7e 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_bid.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_bid.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_bts.c b/src/osmo-bts-lc15/misc/lc15bts_bts.c
index 0343e930..560320a0 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_bts.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_bts.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_bts.h b/src/osmo-bts-lc15/misc/lc15bts_bts.h
index 3918b870..3918b870 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_bts.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_bts.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_clock.c b/src/osmo-bts-lc15/misc/lc15bts_clock.c
index 71701496..23f8f021 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_clock.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_clock.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_clock.h b/src/osmo-bts-lc15/misc/lc15bts_clock.h
index d9673598..d9673598 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_clock.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_clock.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_led.c b/src/osmo-bts-lc15/misc/lc15bts_led.c
index a93d3fb0..88b12207 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_led.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_led.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_led.h b/src/osmo-bts-lc15/misc/lc15bts_led.h
index b6d9d28b..b6d9d28b 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_led.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_led.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c b/src/osmo-bts-lc15/misc/lc15bts_mgr.c
index ccacc1e5..fb4f5c40 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr.c
@@ -1,7 +1,7 @@
/* Main program for NuRAN Wireless Litecell 1.5 BTS management daemon */
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
- *
+ *
* Based on sysmoBTS:
* sysmobts_mgr.c
* (C) 2012 by Harald Welte <laforge@gnumonks.org>
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -220,11 +220,11 @@ static int parse_options(int argc, char **argv)
return 0;
}
-static void signal_handler(int signal)
+static void signal_handler(int signum)
{
- fprintf(stderr, "signal %u received\n", signal);
+ fprintf(stderr, "signal %u received\n", signum);
- switch (signal) {
+ switch (signum) {
case SIGINT:
case SIGTERM:
lc15bts_check_temp(no_rom_write);
@@ -234,6 +234,16 @@ static void signal_handler(int signal)
exit(0);
break;
case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report and
+ * then run default SIGABRT handler, who will generate coredump
+ * and abort the process. abort() should do this for us after we
+ * return, but program wouldn't exit if an external SIGABRT is
+ * received.
+ */
+ talloc_report_full(tall_mgr_ctx, stderr);
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ break;
case SIGUSR1:
case SIGUSR2:
talloc_report_full(tall_mgr_ctx, stderr);
@@ -248,31 +258,31 @@ static struct log_info_cat mgr_log_info_cat[] = {
.name = "DTEMP",
.description = "Temperature monitoring",
.color = "\033[1;35m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFW] = {
.name = "DFW",
.description = "Firmware management",
.color = "\033[1;36m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFIND] = {
.name = "DFIND",
.description = "ipaccess-find handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DCALIB] = {
.name = "DCALIB",
.description = "Calibration handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DSWD] = {
.name = "DSWD",
.description = "Software Watchdog",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
};
@@ -293,6 +303,7 @@ int main(int argc, char **argv)
osmo_init_ignore_signals();
signal(SIGINT, &signal_handler);
signal(SIGTERM, &signal_handler);
+ signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
@@ -308,7 +319,7 @@ int main(int argc, char **argv)
exit(1);
}
- rc = telnet_init(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
+ rc = telnet_init_default(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
if (rc < 0) {
fprintf(stderr, "Error initializing telnet\n");
exit(1);
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr.h b/src/osmo-bts-lc15/misc/lc15bts_mgr.h
index 4bfbdbc9..4bfbdbc9 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c b/src/osmo-bts-lc15/misc/lc15bts_mgr_calib.c
index badb5455..f25955f8 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_calib.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr_calib.c
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_nl.c b/src/osmo-bts-lc15/misc/lc15bts_mgr_nl.c
index 3a617dd7..b34becf1 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_nl.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr_nl.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c b/src/osmo-bts-lc15/misc/lc15bts_mgr_temp.c
index 9665e1db..abffce3b 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_temp.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr_temp.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr_vty.c b/src/osmo-bts-lc15/misc/lc15bts_mgr_vty.c
index 80751fb0..65c1fe72 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_mgr_vty.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_mgr_vty.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -89,39 +89,10 @@ static int go_to_parent(struct vty *vty)
return vty->node;
}
-static int is_config_node(struct vty *vty, int node)
-{
- switch (node) {
- case MGR_NODE:
- case ACT_NORM_NODE:
- case ACT_WARN_NODE:
- case ACT_CRIT_NODE:
- case LIMIT_SUPPLY_TEMP_NODE:
- case LIMIT_SOC_NODE:
- case LIMIT_FPGA_NODE:
- case LIMIT_RMSDET_NODE:
- case LIMIT_OCXO_NODE:
- case LIMIT_TX0_TEMP_NODE:
- case LIMIT_TX1_TEMP_NODE:
- case LIMIT_PA0_TEMP_NODE:
- case LIMIT_PA1_TEMP_NODE:
- case LIMIT_SUPPLY_VOLT_NODE:
- case LIMIT_TX0_VSWR_NODE:
- case LIMIT_TX1_VSWR_NODE:
- case LIMIT_SUPPLY_PWR_NODE:
- case LIMIT_PA0_PWR_NODE:
- case LIMIT_PA1_PWR_NODE:
- return 1;
- default:
- return 0;
- }
-}
-
static struct vty_app_info vty_info = {
.name = "lc15bts-mgr",
.version = PACKAGE_VERSION,
.go_parent_cb = go_to_parent,
- .is_config_node = is_config_node,
.copyright = copyright,
};
@@ -584,39 +555,39 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
lc15bts_mgr_sensor_get_state(s_mgr->state.state), VTY_NEWLINE);
vty_out(vty, "Current Temperatures%s", VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_SUPPLY, &temp);
- vty_out(vty, " Main Supply : %4.2f Celcius%s",
+ vty_out(vty, " Main Supply : %4.2f Celsius%s",
temp/ 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_SOC, &temp);
- vty_out(vty, " SoC : %4.2f Celcius%s",
+ vty_out(vty, " SoC : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_FPGA, &temp);
- vty_out(vty, " FPGA : %4.2f Celcius%s",
+ vty_out(vty, " FPGA : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_RMSDET, &temp);
- vty_out(vty, " RMSDet : %4.2f Celcius%s",
+ vty_out(vty, " RMSDet : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_OCXO, &temp);
- vty_out(vty, " OCXO : %4.2f Celcius%s",
+ vty_out(vty, " OCXO : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_TX0, &temp);
- vty_out(vty, " TX 0 : %4.2f Celcius%s",
+ vty_out(vty, " TX 0 : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_TX1, &temp);
- vty_out(vty, " TX 1 : %4.2f Celcius%s",
+ vty_out(vty, " TX 1 : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_PA0, &temp);
- vty_out(vty, " Power Amp #0: %4.2f Celcius%s",
+ vty_out(vty, " Power Amp #0: %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
lc15bts_temp_get(LC15BTS_TEMP_PA1, &temp);
- vty_out(vty, " Power Amp #1: %4.2f Celcius%s",
+ vty_out(vty, " Power Amp #1: %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_misc.c b/src/osmo-bts-lc15/misc/lc15bts_misc.c
index 2cedc5d8..bd801099 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_misc.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_misc.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -363,7 +363,7 @@ int lc15bts_firmware_reload(enum lc15bts_firmware_type type)
case LC15BTS_FW_DSP1:
fd = open(fw_sysfs[type], O_WRONLY);
if (fd < 0) {
- LOGP(DFW, LOGL_ERROR, "unable ot open firmware device %s: %s\n",
+ LOGP(DFW, LOGL_ERROR, "unable to open firmware device %s: %s\n",
fw_sysfs[type], strerror(errno));
close(fd);
return fd;
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_misc.h b/src/osmo-bts-lc15/misc/lc15bts_misc.h
index 79e9e686..79e9e686 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_misc.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_misc.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_nl.c b/src/osmo-bts-lc15/misc/lc15bts_nl.c
index 39f64aae..d1d1bd13 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_nl.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_nl.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_nl.h b/src/osmo-bts-lc15/misc/lc15bts_nl.h
index 340cf117..b5a15403 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_nl.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_nl.h
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_par.c b/src/osmo-bts-lc15/misc/lc15bts_par.c
index af9d030f..e93c45b6 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_par.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_par.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_par.h b/src/osmo-bts-lc15/misc/lc15bts_par.h
index 74295653..74295653 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_par.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_par.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_power.c b/src/osmo-bts-lc15/misc/lc15bts_power.c
index 1a37d8e6..c28232b7 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_power.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_power.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_power.h b/src/osmo-bts-lc15/misc/lc15bts_power.h
index b48cfdcd..b48cfdcd 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_power.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_power.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_swd.c b/src/osmo-bts-lc15/misc/lc15bts_swd.c
index 59c7b616..f0af6bca 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_swd.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_swd.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -161,7 +161,7 @@ int lc15bts_swd_init(struct lc15bts_mgr_instance *mgr, int swd_num_events)
the value must be in the range of [0,'swd_num_events'[ (see lc15bts_swd_init).
For example, if 'swd_num_events' was 64, 'swd_event' events are numbered 0 to 63.
WARNING: if this function can be used from multiple threads at the same time,
- it must be protected with a kind of mutex to avoid loosing event notification.
+ it must be protected with a kind of mutex to avoid losing event notification.
*/
int lc15bts_swd_event(struct lc15bts_mgr_instance *mgr, enum mgr_swd_events swd_event)
{
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_swd.h b/src/osmo-bts-lc15/misc/lc15bts_swd.h
index b78a2c2a..b78a2c2a 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_swd.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_swd.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_temp.c b/src/osmo-bts-lc15/misc/lc15bts_temp.c
index 45602dcc..f69b9bb7 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_temp.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_temp.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_temp.h b/src/osmo-bts-lc15/misc/lc15bts_temp.h
index 35d81f1b..35d81f1b 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_temp.h
+++ b/src/osmo-bts-lc15/misc/lc15bts_temp.h
diff --git a/src/osmo-bts-litecell15/misc/lc15bts_util.c b/src/osmo-bts-lc15/misc/lc15bts_util.c
index 430ce0f7..a5ab6027 100644
--- a/src/osmo-bts-litecell15/misc/lc15bts_util.c
+++ b/src/osmo-bts-lc15/misc/lc15bts_util.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-lc15/oml.c
index f084f1bf..6f312e80 100644
--- a/src/osmo-bts-litecell15/oml.c
+++ b/src/osmo-bts-lc15/oml.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -26,6 +26,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
#include <nrw/litecell15/gsml1prim.h>
#include <nrw/litecell15/gsml1const.h>
@@ -42,11 +43,14 @@
#include <osmo-bts/phy_link.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
#include "l1_if.h"
#include "lc15bts.h"
#include "utils.h"
+static void dump_lch_par(int logl, GsmL1_LogChParam_t *lch_par, GsmL1_Sapi_t sapi);
+
static int mph_info_chan_confirm(struct gsm_lchan *lchan,
enum osmo_mph_info_type type, uint8_t cause)
{
@@ -91,7 +95,7 @@ static const enum GsmL1_LogChComb_t pchan_to_logChComb[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII,
[GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0,
/*
- * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be
+ * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_OSMO_DYN should not be
* part of this, only "real" pchan values will be looked up here.
* See the callers of ts_connect_as().
*/
@@ -268,36 +272,48 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);
GsmL1_Status_t status = prim_status(l1p);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);
if (status != GsmL1_Status_Success) {
LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",
get_value_string(lc15bts_l1prim_names, l1p->id),
get_value_string(lc15bts_l1status_names, status));
msgb_free(l1_msg);
- return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ case NM_OC_CHANNEL:
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ default:
+ OSMO_ASSERT(0);
+ }
}
msgb_free(l1_msg);
-
- /* Set to Operational State: Enabled */
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
-
- /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
- if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&
- mo->obj_inst.ts_nr == 0) {
- struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
- DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
- mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
- LCHAN_REL_ACT_OML;
- lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
- if (cbch) {
- cbch->rel_act_kind = LCHAN_REL_ACT_OML;
- lchan_activate(cbch);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ case NM_OC_CHANNEL:
+ /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
+ if (mo->obj_inst.trx_nr == 0 &&
+ mo->obj_inst.ts_nr == 0) {
+ struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
+ DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
+ mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
+ LCHAN_REL_ACT_OML;
+ lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
+ if (cbch) {
+ cbch->rel_act_kind = LCHAN_REL_ACT_OML;
+ lchan_activate(cbch);
+ }
}
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi,
+ NM_EV_OPSTART_ACK, NULL);
+ default:
+ OSMO_ASSERT(0);
}
-
- /* Send OPSTART ack */
- return oml_mo_opstart_ack(mo);
}
static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
@@ -355,7 +371,7 @@ static int trx_init_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
trx_rf_lock(trx, 1, trx_mute_on_init_cb);
/* Begin to ramp up the power */
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
return opstart_compl(&trx->mo, l1_msg);
}
@@ -384,14 +400,24 @@ static int trx_init(struct gsm_bts_trx *trx)
struct msgb *msg;
GsmL1_MphInitReq_t *mi_req;
GsmL1_DeviceParam_t *dev_par;
- int lc15_band;
+ int rc, lc15_band;
if (!gsm_abis_mo_check_attr(&trx->mo, trx_rqd_attr,
ARRAY_SIZE(trx_rqd_attr))) {
/* HACK: spec says we need to decline, but openbsc
* doesn't deal with this very well */
- return oml_mo_opstart_ack(&trx->mo);
- //return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ // (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ }
+
+ /* Update TRX band */
+ rc = gsm_arfcn2band_rc(trx->arfcn, &trx->bts->band);
+ if (rc) {
+ /* FIXME: abort initialization? */
+ LOGP(DL1C, LOGL_ERROR, "Could not pick GSM band "
+ "for ARFCN %u\n", trx->arfcn);
+ trx->bts->band = 0x00;
}
lc15_band = lc15bts_select_lc15_band(trx, trx->arfcn);
@@ -408,9 +434,16 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->freqBand = lc15_band;
dev_par->u16Arfcn = trx->arfcn;
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
- dev_par->u8NbTsc = trx->bts->bsic & 7;
- dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
- ? 0.0 : trx->bts->ul_power_target;
+ dev_par->u8NbTsc = BTS_TSC(trx->bts);
+
+ if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+ /* Target is in the middle between lower and upper RxLev thresholds */
+ int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+ int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+ dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+ } else {
+ dev_par->fRxPowerLevel = 0.0;
+ }
dev_par->fTxPowerLevel = 0.0;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (Band %d, ARFCN %u, TSC %u, RxPower % 2f dBm, "
@@ -421,9 +454,9 @@ static int trx_init(struct gsm_bts_trx *trx)
return l1if_gsm_req_compl(fl1h, msg, trx_init_compl_cb, NULL);
}
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
- struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx);
+ const struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx);
return fl1h->hLayer1;
}
@@ -432,20 +465,24 @@ static int trx_close_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
void *data)
{
msgb_free(l1_msg);
+ bts_model_trx_close_cb(trx, 0);
return 0;
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx);
struct msgb *msg;
+ int rc;
msg = l1p_msgb_alloc();
prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphCloseReq, fl1h,
l1p_handle_for_trx(trx));
LOGP(DL1C, LOGL_NOTICE, "Close TRX %u\n", trx->nr);
- return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ rc = l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ if (rc < 0)
+ bts_model_trx_close_cb(trx, rc);
}
static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb)
@@ -490,7 +527,7 @@ static int ts_connect_as(struct gsm_bts_trx_ts *ts,
GsmL1_MphConnectReq_t *cr;
if (pchan == GSM_PCHAN_TCH_F_PDCH
- || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ || pchan == GSM_PCHAN_OSMO_DYN) {
LOGP(DL1C, LOGL_ERROR,
"%s Requested TS connect as %s,"
" expected a specific pchan instead\n",
@@ -510,7 +547,7 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts)
{
enum gsm_phys_chan_config pchan = ts->pchan;
switch (pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
/* First connect as NONE, until first RSL CHAN ACT. */
pchan = GSM_PCHAN_NONE;
@@ -534,8 +571,7 @@ GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan)
case GSM_LCHAN_TCH_H:
return GsmL1_Sapi_TchH;
default:
- LOGP(DL1C, LOGL_NOTICE, "%s cannot determine L1 SAPI\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "cannot determine L1 SAPI\n");
break;
}
return GsmL1_Sapi_Idle;
@@ -545,7 +581,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
{
enum gsm_phys_chan_config pchan = lchan->ts->pchan;
- if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH)
+ if (pchan == GSM_PCHAN_OSMO_DYN)
pchan = lchan->ts->dyn.pchan_want;
switch (pchan) {
@@ -564,7 +600,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
case GSM_PCHAN_PDCH:
case GSM_PCHAN_UNKNOWN:
default:
- /* case GSM_PCHAN_TCH_F_TCH_H_PDCH: is caught above */
+ /* case GSM_PCHAN_OSMO_DYN: is caught above */
return GsmL1_SubCh_NA;
}
@@ -627,10 +663,6 @@ static const struct sapi_dir pdtch_sapis[] = {
#endif
};
-static const struct sapi_dir ho_sapis[] = {
- { GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink },
-};
-
struct lchan_sapis {
const struct sapi_dir *sapis;
unsigned int num_sapis;
@@ -663,11 +695,6 @@ static const struct lchan_sapis sapis_for_lchan[_GSM_LCHAN_MAX] = {
},
};
-static const struct lchan_sapis sapis_for_ho = {
- .sapis = ho_sapis,
- .num_sapis = ARRAY_SIZE(ho_sapis),
-};
-
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
@@ -755,12 +782,8 @@ static void sapi_queue_dispatch(struct gsm_lchan *lchan, int status)
talloc_free(cmd);
if (end || llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_DEBUG,
- "%s End of SAPI cmd queue encountered.%s\n",
- gsm_lchan_name(lchan),
- llist_empty(&lchan->sapi_cmds)
- ? " Queue is now empty."
- : " More pending.");
+ LOGPLCHAN(lchan, DL1C, LOGL_DEBUG, "End of SAPI cmd queue encountered.%s\n",
+ llist_empty(&lchan->sapi_cmds) ? " Queue is now empty." : " More pending.");
return;
}
@@ -800,9 +823,8 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_l1sapi_names, ic->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.conf (%s ",
+ get_value_string(lc15bts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(lc15bts_dir_names, ic->dir));
@@ -823,19 +845,15 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
lchan->sapis_ul[ic->sapi] = status;
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_ACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -909,15 +927,14 @@ static void set_payload_format(GsmL1_LogChParam_t *lch_par)
lch_par->tch.tchPlFmt = GsmL1_TchPlFmt_Rtp;
}
-static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
+static int lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
{
struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
struct gsm48_multi_rate_conf *mr_conf =
(struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
int j;
- LOGP(DL1C, LOGL_INFO, "%s: %s tch_mode=0x%02x\n",
- gsm_lchan_name(lchan), __FUNCTION__, lchan->tch_mode);
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s tch_mode=0x%02x\n", __func__, lchan->tch_mode);
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
@@ -945,7 +962,9 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_SPEECH_AMR:
lch_par->tch.tchPlType = GsmL1_TchPlType_Amr;
set_payload_format(lch_par);
- lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd; /* FIXME? */
+ /* At call set-up, after every successful handover and after a channel mode modify, the
+ * default phase (odd) shall be used in downlink direction. */
+ lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd;
lch_par->tch.amrInitCodecMode = amr_get_initial_mode(lchan);
/* initialize to clean state */
@@ -994,10 +1013,13 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
- LOGP(DL1C, LOGL_ERROR, "%s: CSD not supported!\n",
- gsm_lchan_name(lchan));
- break;
+ default:
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Channel mode %s is not supported!\n",
+ gsm48_chan_mode_name(lchan->tch_mode));
+ return -ENOTSUP;
}
+
+ return 0;
}
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
@@ -1006,6 +1028,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
struct msgb *msg = l1p_msgb_alloc();
int sapi = cmd->sapi;
int dir = cmd->dir;
+ int rc;
GsmL1_MphActivateReq_t *act_req;
GsmL1_LogChParam_t *lch_par;
@@ -1028,7 +1051,10 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
case GsmL1_Sapi_TchH:
case GsmL1_Sapi_TchF:
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/*
* Be sure that every packet is received, even if it
* fails. In this case the length might be lower or 0.
@@ -1061,9 +1087,9 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.req (hL2=0x%08x, %s ",
- gsm_lchan_name(lchan), (uint32_t)act_req->hLayer2,
- get_value_string(lc15bts_l1sapi_names, act_req->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.req (hL2=0x%08x, %s ",
+ (uint32_t)act_req->hLayer2, get_value_string(lc15bts_l1sapi_names, act_req->sapi));
+ dump_lch_par(LOGL_INFO, lch_par, act_req->sapi);
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(lc15bts_dir_names, act_req->dir));
@@ -1087,9 +1113,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status)
/* FIXME: Error handling */
if (status != GsmL1_Status_Success) {
- LOGP(DL1C, LOGL_ERROR,
- "%s act failed mark broken due status: %d\n",
- gsm_lchan_name(lchan), status);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "act failed mark broken due status: %d\n", status);
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_PROCESSOR_OVERLOAD);
@@ -1136,14 +1160,12 @@ int lchan_activate(struct gsm_lchan *lchan)
lchan_set_state(lchan, LCHAN_S_ACT_REQ);
if (!llist_empty(&lchan->sapi_cmds))
- LOGP(DL1C, LOGL_ERROR,
- "%s Trying to activate lchan, but commands in queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate lchan, but commands in queue\n");
- /* override the regular SAPIs if this is the first hand-over
- * related activation of the LCHAN */
- if (lchan->ho.active == HANDOVER_ENABLED)
- s4l = &sapis_for_ho;
+ /* For handover, always start the main channel immediately. lchan->want_dl_sacch_active indicates whether dl
+ * SACCH should be activated. Also, for HO, start the RACH SAPI. */
+ if (lchan->ho.active == HANDOVER_ENABLED || rsl_chan_rt_is_asci(lchan->rsl_chan_rt))
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
for (i = 0; i < s4l->num_sapis; i++) {
int sapi = s4l->sapis[i].sapi;
@@ -1156,12 +1178,14 @@ int lchan_activate(struct gsm_lchan *lchan)
fl1h->alive_prim_cnt = 0;
osmo_timer_schedule(&fl1h->alive_timer, 5, 0);
}
- enqueue_sapi_act_cmd(lchan, sapi, dir);
- }
-#warning "FIXME: Should this be in sapi_activate_cb?"
- lchan_init_lapdm(lchan);
+ /* For handover, possibly postpone activating the dl SACCH until the HO RACH is received. */
+ if (sapi == GsmL1_Sapi_Sacch && dir == GsmL1_Dir_TxDownlink
+ && !lchan->want_dl_sacch_active)
+ continue;
+ enqueue_sapi_act_cmd(lchan, sapi, dir);
+ }
return 0;
}
@@ -1170,6 +1194,9 @@ const struct value_string lc15bts_l1cfgt_names[] = {
{ GsmL1_ConfigParamId_SetTxPowerLevel, "Set Tx power level" },
{ GsmL1_ConfigParamId_SetLogChParams, "Set logical channel params" },
{ GsmL1_ConfigParamId_SetCipheringParams,"Configure ciphering params" },
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ { GsmL1_ConfigParamId_Set8pskPowerReduction, "Set 8PSK Tx power reduction" },
+#endif
{ 0, NULL }
};
@@ -1227,6 +1254,58 @@ static int chmod_txpower_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
return 0;
}
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+static int chmod_txpower_backoff_8psk_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
+ void *data)
+{
+ GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);
+ GsmL1_MphConfigCnf_t *cc = &l1p->u.mphConfigCnf;
+
+ LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ",
+ gsm_trx_name(trx),
+ get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId));
+
+ LOGPC(DL1C, LOGL_INFO, "Backoff %u dB\n",
+ cc->cfgParams.set8pskPowerReduction.u8PowerReduction);
+
+ msgb_free(l1_msg);
+
+ return 0;
+}
+
+static int chmod_max_cell_size_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
+ void *data)
+{
+ Litecell15_Prim_t *sysp = msgb_sysprim(resp);
+ Litecell15_SetMaxCellSizeCnf_t *sac = &sysp->u.setMaxCellSizeCnf;
+
+ LOGP(DL1C, LOGL_INFO, "%s Rx SYS prim %s -> %s\n",
+ gsm_trx_name(trx),
+ get_value_string(lc15bts_sysprim_names, sysp->id),
+ get_value_string(lc15bts_l1status_names, sac->status));
+
+ msgb_free(resp);
+
+ return 0;
+}
+
+static int chmod_c0_idle_pwr_red_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
+ void *data)
+{
+ Litecell15_Prim_t *sysp = msgb_sysprim(resp);
+ Litecell15_SetC0IdleSlotPowerReductionCnf_t *sac = &sysp->u.setC0IdleSlotPowerReductionCnf;
+
+ LOGP(DL1C, LOGL_INFO, "%s Rx SYS prim %s -> %s\n",
+ gsm_trx_name(trx),
+ get_value_string(lc15bts_sysprim_names, sysp->id),
+ get_value_string(lc15bts_l1status_names, sac->status));
+
+ msgb_free(resp);
+
+ return 0;
+}
+#endif
+
static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
void *data)
{
@@ -1242,9 +1321,8 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.conf (%s) ",
+ get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId));
switch (cc->cfgParamId) {
case GsmL1_ConfigParamId_SetLogChParams:
@@ -1276,9 +1354,7 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
break;
}
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got ciphering conf with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got ciphering conf with empty queue\n");
goto err;
}
@@ -1303,6 +1379,7 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
struct msgb *msg = l1p_msgb_alloc();
GsmL1_MphConfigReq_t *conf_req;
GsmL1_LogChParam_t *lch_par;
+ int rc;
/* channel mode, encryption and/or multirate have changed */
@@ -1317,7 +1394,10 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
conf_req->hLayer3 = (HANDLE)l1if_lchan_to_hLayer(lchan);
lch_par = &conf_req->cfgParams.setLogChParams.logChParams;
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/* Update the MS Power Level */
if (cmd->sapi == GsmL1_Sapi_Sacch && trx_ms_pwr_ctrl_is_osmo(trx))
@@ -1325,10 +1405,8 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
/* FIXME: update encryption */
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.req (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_l1sapi_names,
- conf_req->cfgParams.setLogChParams.sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.req (%s) ",
+ get_value_string(lc15bts_l1sapi_names, conf_req->cfgParams.setLogChParams.sapi));
LOGPC(DL1C, LOGL_INFO, "cfgParams Tn=%u, subCh=%u, dir=0x%x ",
conf_req->cfgParams.setLogChParams.u8Tn,
conf_req->cfgParams.setLogChParams.subCh,
@@ -1368,6 +1446,49 @@ int l1if_set_txpower(struct lc15l1_hdl *fl1h, float tx_power)
return l1if_gsm_req_compl(fl1h, msg, chmod_txpower_compl_cb, NULL);
}
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+int l1if_set_txpower_backoff_8psk(struct lc15l1_hdl *fl1h, uint8_t backoff)
+{
+ struct msgb *msg = l1p_msgb_alloc();
+ GsmL1_MphConfigReq_t *conf_req;
+
+ conf_req = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConfigReq, fl1h, 0);
+ conf_req->cfgParamId = GsmL1_ConfigParamId_Set8pskPowerReduction;
+ conf_req->cfgParams.set8pskPowerReduction.u8PowerReduction = backoff;
+
+ return l1if_gsm_req_compl(fl1h, msg, chmod_txpower_backoff_8psk_compl_cb, NULL);
+}
+
+int l1if_set_max_cell_size(struct lc15l1_hdl *fl1h, uint8_t cell_size)
+{
+ struct msgb *msg = sysp_msgb_alloc();
+ Litecell15_Prim_t *sys_prim = msgb_sysprim(msg);
+ sys_prim->id = Litecell15_PrimId_SetMaxCellSizeReq;
+ sys_prim->u.setMaxCellSizeReq.u8MaxCellSize = cell_size;
+
+ LOGP(DL1C, LOGL_INFO, "%s Set max cell size = %d qbits\n",
+ gsm_trx_name(fl1h->phy_inst->trx),
+ cell_size);
+
+ return l1if_req_compl(fl1h, msg, chmod_max_cell_size_compl_cb, NULL);
+
+}
+
+int l1if_set_txpower_c0_idle_pwr_red(struct lc15l1_hdl *fl1h, uint8_t red)
+{
+ struct msgb *msg = sysp_msgb_alloc();
+ Litecell15_Prim_t *sys_prim = msgb_sysprim(msg);
+ sys_prim->id = Litecell15_PrimId_SetC0IdleSlotPowerReductionReq;
+ sys_prim->u.setC0IdleSlotPowerReductionReq.u8PowerReduction = red;
+
+ LOGP(DL1C, LOGL_INFO, "%s Set C0 idle slot power reduction = %d dB\n",
+ gsm_trx_name(fl1h->phy_inst->trx),
+ red);
+
+ return l1if_req_compl(fl1h, msg, chmod_c0_idle_pwr_red_compl_cb, NULL);
+}
+#endif
+
const enum GsmL1_CipherId_t rsl2l1_ciph[] = {
[0] = GsmL1_CipherId_A50,
[1] = GsmL1_CipherId_A50,
@@ -1395,11 +1516,9 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c
return -EINVAL;
cfgr->cfgParams.setCipheringParams.cipherId = rsl2l1_ciph[lchan->encr.alg_id];
- LOGP(DL1C, LOGL_NOTICE, "%s SET_CIPHERING (ALG=%u %s)\n",
- gsm_lchan_name(lchan),
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "SET_CIPHERING (ALG=%u %s)\n",
cfgr->cfgParams.setCipheringParams.cipherId,
- get_value_string(lc15bts_dir_names,
- cfgr->cfgParams.setCipheringParams.dir));
+ get_value_string(lc15bts_dir_names, cfgr->cfgParams.setCipheringParams.dir));
memcpy(cfgr->cfgParams.setCipheringParams.u8Kc,
lchan->encr.key, lchan->encr.key_len);
@@ -1477,9 +1596,8 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_l1sapi_names, ic->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.conf (%s ",
+ get_value_string(lc15bts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(lc15bts_dir_names, ic->dir));
@@ -1501,19 +1619,15 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got de-activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got de-activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_DEACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -1538,9 +1652,8 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd
deact_req->sapi = cmd->sapi;
deact_req->hLayer3 = (HANDLE)l1if_lchan_to_hLayer(lchan);
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.req (%s ",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_l1sapi_names, deact_req->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.req (%s ",
+ get_value_string(lc15bts_l1sapi_names, deact_req->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(lc15bts_dir_names, deact_req->dir));
@@ -1552,8 +1665,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status)
{
/* FIXME: Error handling. There is no NACK... */
if (status != GsmL1_Status_Success && lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s is now broken. Stopping the release.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "is now broken. Stopping the release.\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
@@ -1610,17 +1722,9 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir)
return enqueue_sapi_deact_cmd(lchan, sapi, dir);
}
-static int release_sapis_for_ho(struct gsm_lchan *lchan)
+static int release_sapi_ul_rach(struct gsm_lchan *lchan)
{
- int res = 0;
- int i;
-
- const struct lchan_sapis *s4l = &sapis_for_ho;
-
- for (i = s4l->num_sapis-1; i >= 0; i--)
- res |= check_sapi_release(lchan,
- s4l->sapis[i].sapi, s4l->sapis[i].dir);
- return res;
+ return check_sapi_release(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
}
static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
@@ -1642,12 +1746,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
}
/* always attempt to disable the RACH burst */
- res |= release_sapis_for_ho(lchan);
+ res |= release_sapi_ul_rach(lchan);
/* nothing was queued */
if (res == 0) {
- LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "all SAPIs already released?\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
}
@@ -1694,67 +1797,87 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
void *obj)
{
/* FIXME: more checks if the attributes are valid */
-
- switch (msg_type) {
- case NM_MT_SET_CHAN_ATTR:
- /* our L1 only supports one global TSC for all channels
- * one one TRX, so we need to make sure not to activate
- * channels with a different TSC!! */
- if (TLVP_PRES_LEN(new_attr, NM_ATT_TSC, 1) &&
- *TLVP_VAL(new_attr, NM_ATT_TSC) != (bts->bsic & 7)) {
- LOGP(DOML, LOGL_ERROR, "Channel TSC %u != BSIC-TSC %u\n",
- *TLVP_VAL(new_attr, NM_ATT_TSC), bts->bsic & 7);
- return -NM_NACK_PARAM_RANGE;
- }
- break;
- }
return 0;
}
/* callback from OML */
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
-{
- if (kind == NM_OC_RADIO_CARRIER) {
- struct gsm_bts_trx *trx = obj;
- struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx);
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
+{
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx;
+ struct lc15l1_hdl *fl1h;
+
+ switch (foh->msg_type) {
+ case NM_MT_SET_RADIO_ATTR:
+ trx = obj;
+ fl1h = trx_lc15l1_hdl(trx);
+
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ {
+ /* convert max TA to max cell size in qbits */
+ uint8_t cell_size = bts->max_ta << 2;
+ /* We do not need to check for L1 handle
+ * because the max cell size parameter can receive before MphInit */
+ if (fl1h->phy_inst->u.lc15.max_cell_size != cell_size) {
+ /* instruct L1 to apply max cell size */
+ l1if_set_max_cell_size(fl1h, cell_size);
+ /* update current max cell size */
+ fl1h->phy_inst->u.lc15.max_cell_size = cell_size;
+ }
+ }
+#endif
/* Did we go through MphInit yet? If yes fire and forget */
- if (fl1h->hLayer1)
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ if (fl1h->hLayer1) {
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
+#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
+ if (fl1h->phy_inst->u.lc15.tx_pwr_red_8psk != trx->max_power_backoff_8psk) {
+ /* update current Tx power backoff for 8-PSK */
+ fl1h->phy_inst->u.lc15.tx_pwr_red_8psk = trx->max_power_backoff_8psk;
+ /* instruct L1 to apply Tx power backoff for 8 PSK */
+ l1if_set_txpower_backoff_8psk(fl1h, fl1h->phy_inst->u.lc15.tx_pwr_red_8psk);
+ }
+
+ if (fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red != trx->c0_idle_power_red) {
+ /* update current C0 idle slot Tx power reduction */
+ fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red = trx->c0_idle_power_red;
+ /* instruct L1 to apply C0 idle slot power reduction */
+ l1if_set_txpower_c0_idle_pwr_red(fl1h, fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red);
+ }
+#endif
+ }
+ break;
}
- /* FIXME: we actaully need to send a ACK or NACK for the OML message */
- return oml_fom_ack_nack(msg, 0);
+ return 0;
}
/* callback from OML */
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj)
{
+ struct gsm_bts_bb_trx *bb_transc;
+ struct gsm_bts_trx *trx;
+ struct gsm_bts_trx_ts *ts;
int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- rc = trx_init(obj);
- break;
- case NM_OC_CHANNEL:
- rc = ts_opstart(obj);
- break;
- case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
+ case NM_OC_BTS:
case NM_OC_BASEB_TRANSC:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, -1);
- rc = oml_mo_opstart_ack(mo);
- if (mo->obj_class == NM_OC_BTS) {
- oml_mo_state_chg(&bts->mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nse.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.cell.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK);
- }
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ trx = (struct gsm_bts_trx *) obj;
+ rc = trx_init(trx);
+ break;
+ case NM_OC_CHANNEL:
+ ts = (struct gsm_bts_trx_ts*) obj;
+ rc = ts_opstart(ts);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -1825,24 +1948,17 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
*/
int l1if_rsl_chan_mod(struct gsm_lchan *lchan)
{
- const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
- unsigned int i;
-
if (lchan->ho.active == HANDOVER_NONE)
return -1;
- LOGP(DHO, LOGL_ERROR, "%s modifying channel for handover\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DHO, LOGL_ERROR, "modifying channel for handover\n");
/* Give up listening to RACH bursts */
- release_sapis_for_ho(lchan);
+ release_sapi_ul_rach(lchan);
- /* Activate the normal SAPIs */
- for (i = 0; i < s4l->num_sapis; i++) {
- int sapi = s4l->sapis[i].sapi;
- int dir = s4l->sapis[i].dir;
- enqueue_sapi_act_cmd(lchan, sapi, dir);
- }
+ /* All the normal SAPIs have already been activated, only DL SACCH may still be missing. */
+ if (lchan->want_dl_sacch_active)
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Sacch, GsmL1_Dir_TxDownlink);
return 0;
}
@@ -1851,8 +1967,7 @@ int l1if_rsl_chan_rel(struct gsm_lchan *lchan)
{
/* A duplicate RF Release Request, ignore it */
if (lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s already in release request state.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "already in release request state.\n");
return 0;
}
@@ -1888,11 +2003,12 @@ static int ts_disconnect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- LOGP(DL1C, LOGL_DEBUG, "%s Rx mphDisconnectCnf\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "Rx mphDisconnectCnf\n");
cb_ts_disconnected(ts);
+ msgb_free(l1_msg);
+
return 0;
}
@@ -1902,7 +2018,7 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(ts->trx);
GsmL1_MphDisconnectReq_t *cr;
- DEBUGP(DRSL, "%s TS disconnect\n", gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "TS disconnect\n");
cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphDisconnectReq, fl1h,
l1p_handle_for_ts(ts));
cr->u8Tn = ts->nr;
@@ -1918,8 +2034,7 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- DEBUGP(DL1C, "%s %s Rx mphConnectCnf flags=%s%s%s\n",
- gsm_lchan_name(ts->lchan),
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "%s Rx mphConnectCnf flags=%s%s%s\n",
gsm_pchan_name(ts->pchan),
ts->flags & TS_F_PDCH_ACTIVE ? "ACTIVE " : "",
ts->flags & TS_F_PDCH_ACT_PENDING ? "ACT_PENDING " : "",
@@ -1927,6 +2042,8 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
cb_ts_connected(ts, 0);
+ msgb_free(l1_msg);
+
return 0;
}
diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-lc15/tch.c
index 5eae7538..afd5b53f 100644
--- a/src/osmo-bts-litecell15/tch.c
+++ b/src/osmo-bts-lc15/tch.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -68,7 +68,7 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
cur = msgb_put(msg, GSM_FR_BYTES);
memcpy(cur, l1_payload, GSM_FR_BYTES);
- lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan);
+ lchan_set_marker(osmo_fr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -101,12 +101,8 @@ static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload,
/* new L1 can deliver bits like we need them */
cur = msgb_put(msg, GSM_EFR_BYTES);
memcpy(cur, l1_payload, GSM_EFR_BYTES);
- enum osmo_amr_type ft;
- enum osmo_amr_quality bfi;
- uint8_t cmr;
- int8_t sti, cmi;
- osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti);
- lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan);
+
+ lchan_set_marker(osmo_efr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -259,7 +255,10 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Efr;
rc = rtppayload_to_l1_efr(l1_payload, rtp_pl,
rtp_pl_len);
- /* FIXME: detect and save EFR SID */
+ if (rc && lchan->ts->trx->bts->dtxd)
+ is_sid = osmo_efr_check_sid(rtp_pl, rtp_pl_len);
+ if (is_sid)
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
break;
case GSM48_CMODE_SPEECH_AMR:
if (use_cache) {
@@ -360,7 +359,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
- uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
+ uint8_t *payload, payload_type, payload_len;
struct msgb *rmsg = NULL;
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
@@ -368,12 +367,12 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
return -EAGAIN;
if (data_ind->msgUnitParam.u8Size < 1) {
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx Payload size 0\n", chan_nr);
/* Push empty payload to upper layers */
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
}
payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -399,6 +398,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (lchan->type != GSM_LCHAN_TCH_H &&
lchan->type != GSM_LCHAN_TCH_F)
goto err_payload_match;
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received ONSET from L1 " "(%d bytes)\n",
+ payload_len);
/* according to 3GPP TS 26.093 ONSET frames precede the first
speech frame of a speech burst - set the marker for next RTP
frame */
@@ -407,33 +408,32 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
case GsmL1_TchPlType_Amr_SidFirstP1:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P1 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstP2:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P2 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidUpdateInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_UPDATE_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
default:
- LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "%s Rx Payload Type %s is unsupported\n",
- gsm_lchan_name(lchan),
- get_value_string(lc15bts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_NOTICE, "%s Rx Payload Type %s is unsupported\n",
+ gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
break;
}
@@ -449,27 +449,21 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
rmsg = l1_to_rtppayload_efr(payload, payload_len, lchan);
break;
case GsmL1_TchPlType_Amr:
- rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
- break;
case GsmL1_TchPlType_Amr_SidFirstP1:
- memcpy(sid_first, payload, payload_len);
- int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
- if (len < 0)
- return 0;
- rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
+ rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
break;
}
if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
return 0;
err_payload_match:
- LOGPFN(DL1P, LOGL_ERROR, data_ind->u32Fn, "%s Rx Payload Type %s incompatible with lchan\n",
- gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_ERROR, "%s Rx Payload Type %s incompatible with lchan\n",
+ gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
return -EINVAL;
}
diff --git a/src/osmo-bts-litecell15/utils.c b/src/osmo-bts-lc15/utils.c
index 8d980ba8..b1906d12 100644
--- a/src/osmo-bts-litecell15/utils.c
+++ b/src/osmo-bts-lc15/utils.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-litecell15/utils.h b/src/osmo-bts-lc15/utils.h
index a2a22348..a2a22348 100644
--- a/src/osmo-bts-litecell15/utils.h
+++ b/src/osmo-bts-lc15/utils.h
diff --git a/src/osmo-bts-litecell15/Makefile.am b/src/osmo-bts-litecell15/Makefile.am
deleted file mode 100644
index 0cc124ab..00000000
--- a/src/osmo-bts-litecell15/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-AUTOMAKE_OPTIONS = subdir-objects
-
-AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(LITECELL15_INCDIR)
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS) $(LIBSYSTEMD_CFLAGS)
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS)
-
-AM_CFLAGS += -DENABLE_LC15BTS
-
-EXTRA_DIST = misc/lc15bts_mgr.h misc/lc15bts_misc.h misc/lc15bts_par.h misc/lc15bts_led.h \
- misc/lc15bts_temp.h misc/lc15bts_power.h misc/lc15bts_clock.h \
- misc/lc15bts_bid.h misc/lc15bts_nl.h misc/lc15bts_bts.h misc/lc15bts_swd.h \
- hw_misc.h l1_if.h l1_transp.h lc15bts.h oml_router.h utils.h
-
-bin_PROGRAMS = osmo-bts-lc15 lc15bts-mgr lc15bts-util
-
-COMMON_SOURCES = main.c lc15bts.c l1_if.c oml.c lc15bts_vty.c tch.c hw_misc.c calib_file.c \
- utils.c misc/lc15bts_par.c misc/lc15bts_bid.c oml_router.c
-
-osmo_bts_lc15_SOURCES = $(COMMON_SOURCES) l1_transp_hw.c
-osmo_bts_lc15_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
-
-lc15bts_mgr_SOURCES = \
- misc/lc15bts_mgr.c misc/lc15bts_misc.c \
- misc/lc15bts_par.c misc/lc15bts_nl.c \
- misc/lc15bts_temp.c misc/lc15bts_power.c \
- misc/lc15bts_clock.c misc/lc15bts_bid.c \
- misc/lc15bts_mgr_vty.c \
- misc/lc15bts_mgr_nl.c \
- misc/lc15bts_mgr_temp.c \
- misc/lc15bts_mgr_calib.c \
- misc/lc15bts_led.c \
- misc/lc15bts_bts.c \
- misc/lc15bts_swd.c
-
-lc15bts_mgr_LDADD = $(top_builddir)/src/common/libbts.a $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBSYSTEMD_LIBS) $(COMMON_LDADD)
-
-lc15bts_util_SOURCES = misc/lc15bts_util.c misc/lc15bts_par.c
-lc15bts_util_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/src/osmo-bts-litecell15/lc15bts.h b/src/osmo-bts-litecell15/lc15bts.h
deleted file mode 100644
index 4c40db0f..00000000
--- a/src/osmo-bts-litecell15/lc15bts.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef LC15BTS_H
-#define LC15BTS_H
-
-#include <stdlib.h>
-#include <osmocom/core/utils.h>
-
-#include <nrw/litecell15/litecell15.h>
-#include <nrw/litecell15/gsml1const.h>
-
-/*
- * Depending on the firmware version either GsmL1_Prim_t or Litecell15_Prim_t
- * is the bigger struct. For earlier firmware versions the GsmL1_Prim_t was the
- * bigger struct.
- */
-#define LC15BTS_PRIM_SIZE \
- (OSMO_MAX(sizeof(Litecell15_Prim_t), sizeof(GsmL1_Prim_t)) + 128)
-
-enum l1prim_type {
- L1P_T_INVALID, /* this must be 0 to detect uninitialized elements */
- L1P_T_REQ,
- L1P_T_CONF,
- L1P_T_IND,
-};
-
-enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id);
-const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1];
-GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id);
-
-enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id);
-const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1];
-Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id);
-
-const struct value_string lc15bts_l1sapi_names[GsmL1_Sapi_NUM+1];
-const struct value_string lc15bts_l1status_names[GSML1_STATUS_NUM+1];
-
-const struct value_string lc15bts_tracef_names[29];
-const struct value_string lc15bts_tracef_docs[29];
-
-const struct value_string lc15bts_tch_pl_names[15];
-
-const struct value_string lc15bts_clksrc_names[10];
-
-const struct value_string lc15bts_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 /* LC15BTS_H */
diff --git a/src/osmo-bts-litecell15/oml_router.c b/src/osmo-bts-litecell15/oml_router.c
deleted file mode 100644
index 198d5e30..00000000
--- a/src/osmo-bts-litecell15/oml_router.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Beginnings of an OML router */
-
-/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
- *
- * Based on sysmoBTS:
- * (C) 2014 by sysmocom s.f.m.c. GmbH
- *
- * 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 "oml_router.h"
-
-#include <osmo-bts/bts.h>
-#include <osmo-bts/logging.h>
-#include <osmo-bts/oml.h>
-#include <osmo-bts/msg_utils.h>
-
-#include <osmocom/core/socket.h>
-#include <osmocom/core/select.h>
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-static int oml_router_read_cb(struct osmo_fd *fd, unsigned int what)
-{
- struct msgb *msg;
- int rc;
-
- msg = oml_msgb_alloc();
- if (!msg) {
- LOGP(DL1C, LOGL_ERROR, "Failed to allocate oml msgb.\n");
- return -1;
- }
-
- rc = recv(fd->fd, msg->tail, msg->data_len, 0);
- if (rc <= 0) {
- close(fd->fd);
- osmo_fd_unregister(fd);
- fd->fd = -1;
- goto err;
- }
-
- msg->l1h = msgb_put(msg, rc);
- rc = msg_verify_ipa_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid IPA message rc(%d)\n", rc);
- goto err;
- }
-
- rc = msg_verify_oml_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid OML message rc(%d)\n", rc);
- goto err;
- }
-
- /* todo dispatch message */
-
-err:
- msgb_free(msg);
- return -1;
-}
-
-static int oml_router_accept_cb(struct osmo_fd *accept_fd, unsigned int what)
-{
- int fd;
- struct osmo_fd *read_fd = (struct osmo_fd *) accept_fd->data;
-
- /* Accept only one connection at a time. De-register it */
- if (read_fd->fd > -1) {
- LOGP(DL1C, LOGL_NOTICE,
- "New OML router connection. Closing old one.\n");
- close(read_fd->fd);
- osmo_fd_unregister(read_fd);
- read_fd->fd = -1;
- }
-
- fd = accept(accept_fd->fd, NULL, NULL);
- if (fd < 0) {
- LOGP(DL1C, LOGL_ERROR, "Failed to accept. errno: %s.\n",
- strerror(errno));
- return -1;
- }
-
- read_fd->fd = fd;
- if (osmo_fd_register(read_fd) != 0) {
- LOGP(DL1C, LOGL_ERROR, "Registering the read fd failed.\n");
- close(fd);
- read_fd->fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-int oml_router_init(struct gsm_bts *bts, const char *path,
- struct osmo_fd *accept_fd, struct osmo_fd *read_fd)
-{
- int rc;
-
- memset(accept_fd, 0, sizeof(*accept_fd));
- memset(read_fd, 0, sizeof(*read_fd));
-
- accept_fd->cb = oml_router_accept_cb;
- accept_fd->data = read_fd;
-
- read_fd->cb = oml_router_read_cb;
- read_fd->data = bts;
- read_fd->when = BSC_FD_READ;
- read_fd->fd = -1;
-
- rc = osmo_sock_unix_init_ofd(accept_fd, SOCK_SEQPACKET, 0,
- path,
- OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK);
- return rc;
-}
diff --git a/src/osmo-bts-litecell15/oml_router.h b/src/osmo-bts-litecell15/oml_router.h
deleted file mode 100644
index 8c08baaa..00000000
--- a/src/osmo-bts-litecell15/oml_router.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-struct gsm_bts;
-struct osmo_fd;
-
-/**
- * The default path lc15bts will listen for incoming
- * registrations for OML routing and sending.
- */
-#define OML_ROUTER_PATH "/var/run/lc15bts_oml_router"
-
-
-int oml_router_init(struct gsm_bts *bts, const char *path, struct osmo_fd *accept, struct osmo_fd *read);
diff --git a/src/osmo-bts-oc2g/Makefile.am b/src/osmo-bts-oc2g/Makefile.am
index 54a8afab..29374efd 100644
--- a/src/osmo-bts-oc2g/Makefile.am
+++ b/src/osmo-bts-oc2g/Makefile.am
@@ -1,38 +1,104 @@
-AUTOMAKE_OPTIONS = subdir-objects
+AUTOMAKE_OPTIONS = subdir-objects
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(OC2G_INCDIR)
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS) $(ORTP_CFLAGS) $(LIBSYSTEMD_CFLAGS)
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(LIBGPS_CFLAGS) \
+ $(LIBSYSTEMD_CFLAGS) \
+ $(ORTP_CFLAGS) \
+ $(NULL)
+
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(ORTP_LIBS) \
+ $(NULL)
AM_CFLAGS += -DENABLE_OC2GBTS
-EXTRA_DIST = misc/oc2gbts_mgr.h misc/oc2gbts_misc.h misc/oc2gbts_par.h misc/oc2gbts_led.h \
- misc/oc2gbts_temp.h misc/oc2gbts_power.h misc/oc2gbts_clock.h \
- misc/oc2gbts_bid.h misc/oc2gbts_bts.h misc/oc2gbts_nl.h misc/oc2gbts_swd.h \
- hw_misc.h l1_if.h l1_transp.h oc2gbts.h oml_router.h utils.h
+EXTRA_DIST = \
+ misc/oc2gbts_mgr.h \
+ misc/oc2gbts_misc.h \
+ misc/oc2gbts_par.h \
+ misc/oc2gbts_led.h \
+ misc/oc2gbts_temp.h \
+ misc/oc2gbts_power.h \
+ misc/oc2gbts_clock.h \
+ misc/oc2gbts_bid.h \
+ misc/oc2gbts_bts.h \
+ misc/oc2gbts_nl.h \
+ misc/oc2gbts_swd.h \
+ hw_misc.h \
+ l1_if.h \
+ l1_transp.h \
+ oc2gbts.h \
+ utils.h \
+ $(NULL)
bin_PROGRAMS = osmo-bts-oc2g oc2gbts-mgr oc2gbts-util
-COMMON_SOURCES = main.c oc2gbts.c l1_if.c oml.c oc2gbts_vty.c tch.c hw_misc.c calib_file.c \
- utils.c misc/oc2gbts_par.c misc/oc2gbts_bid.c oml_router.c
+COMMON_SOURCES = \
+ main.c \
+ oc2gbts.c \
+ l1_if.c \
+ oml.c \
+ oc2gbts_vty.c \
+ tch.c \
+ hw_misc.c \
+ calib_file.c \
+ utils.c \
+ misc/oc2gbts_par.c \
+ misc/oc2gbts_bid.c \
+ $(NULL)
osmo_bts_oc2g_SOURCES = $(COMMON_SOURCES) l1_transp_hw.c
-osmo_bts_oc2g_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
+osmo_bts_oc2g_LDADD = \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(NULL)
oc2gbts_mgr_SOURCES = \
- misc/oc2gbts_mgr.c misc/oc2gbts_misc.c \
- misc/oc2gbts_par.c misc/oc2gbts_nl.c \
- misc/oc2gbts_temp.c misc/oc2gbts_power.c \
- misc/oc2gbts_clock.c misc/oc2gbts_bid.c \
+ misc/oc2gbts_mgr.c \
+ misc/oc2gbts_misc.c \
+ misc/oc2gbts_par.c \
+ misc/oc2gbts_nl.c \
+ misc/oc2gbts_temp.c \
+ misc/oc2gbts_power.c \
+ misc/oc2gbts_clock.c \
+ misc/oc2gbts_bid.c \
misc/oc2gbts_mgr_vty.c \
misc/oc2gbts_mgr_nl.c \
misc/oc2gbts_mgr_temp.c \
misc/oc2gbts_mgr_calib.c \
misc/oc2gbts_led.c \
misc/oc2gbts_bts.c \
- misc/oc2gbts_swd.c
+ misc/oc2gbts_swd.c \
+ $(NULL)
-oc2gbts_mgr_LDADD = $(top_builddir)/src/common/libbts.a $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBSYSTEMD_LIBS) $(COMMON_LDADD)
+oc2gbts_mgr_LDADD = \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(LIBGPS_LIBS) \
+ $(LIBSYSTEMD_LIBS) \
+ $(NULL)
-oc2gbts_util_SOURCES = misc/oc2gbts_util.c misc/oc2gbts_par.c
+oc2gbts_util_SOURCES = \
+ misc/oc2gbts_util.c \
+ misc/oc2gbts_par.c \
+ $(NULL)
oc2gbts_util_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/src/osmo-bts-oc2g/calib_file.c b/src/osmo-bts-oc2g/calib_file.c
index 6d2d5610..df15ee99 100644
--- a/src/osmo-bts-oc2g/calib_file.c
+++ b/src/osmo-bts-oc2g/calib_file.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -307,7 +307,7 @@ static int calib_verify(struct oc2gl1_hdl *fl1h, const struct calib_file_desc *d
fseek(st->fp, 0L, SEEK_END);
sz = ftell(st->fp);
- /* rewind read poiner */
+ /* rewind read pointer */
fseek(st->fp, 0L, SEEK_SET);
/* read file */
diff --git a/src/osmo-bts-oc2g/hw_misc.c b/src/osmo-bts-oc2g/hw_misc.c
index 31daf078..d886effd 100644
--- a/src/osmo-bts-oc2g/hw_misc.c
+++ b/src/osmo-bts-oc2g/hw_misc.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/l1_if.c b/src/osmo-bts-oc2g/l1_if.c
index d987bb52..d43f31b7 100644
--- a/src/osmo-bts-oc2g/l1_if.c
+++ b/src/osmo-bts-oc2g/l1_if.c
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -37,6 +37,7 @@
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/write_queue.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/lapdm.h>
@@ -55,6 +56,7 @@
#include <osmo-bts/msg_utils.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <osmo-bts/cbch.h>
+#include <osmo-bts/nm_common_fsm.h>
#include <nrw/oc2g/oc2g.h>
#include <nrw/oc2g/gsml1prim.h>
@@ -390,7 +392,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -438,9 +440,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
sapi = GsmL1_Sapi_Agch;
} else {
- LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
- "chan_nr %d link_id %d\n", l1sap->oph.primitive,
- l1sap->oph.operation, chan_nr, link_id);
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n",
+ l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
msgb_free(l1msg);
return -EINVAL;
}
@@ -501,9 +502,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
msgb_l2len(msg));
}
- LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN)
@@ -521,7 +521,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(l1msg);
} else
dtx_int_signal(lchan);
@@ -559,7 +559,6 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* create new message and fill data */
if (msg) {
- msgb_pull(msg, sizeof(*l1sap));
/* create new message */
nmsg = l1p_msgb_alloc();
if (!nmsg)
@@ -568,7 +567,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
rc = l1if_tch_encode(lchan,
l1p->u.phDataReq.msgUnitParam.u8Buffer,
&l1p->u.phDataReq.msgUnitParam.u8Size,
- msg->data, msg->len, u32Fn, use_cache,
+ msgb_l2(msg), msgb_l2len(msg), u32Fn, use_cache,
l1sap->u.tch.marker);
if (rc < 0) {
/* no data encoded for L1: smth will be generated below */
@@ -604,7 +603,11 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr);
}
/* send message to DSP's queue */
- osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg);
+ if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) < 0) {
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ msgb_free(nmsg);
+ return -ENOBUFS;
+ }
if (dtx_is_first_p1(lchan))
dtx_dispatch(lchan, E_FIRST);
else
@@ -733,7 +736,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
if (ts->flags & TS_F_PDCH_ACTIVE)
return GSM_PCHAN_PDCH;
return GSM_PCHAN_TCH_F;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return ts->dyn.pchan_is;
default:
return ts->pchan;
@@ -747,7 +750,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
uint8_t cbits = 0;
enum gsm_phys_chan_config pchan = pick_pchan(ts);
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
switch (sapi) {
case GsmL1_Sapi_Bcch:
@@ -847,6 +850,45 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
return (cbits << 3) | u8Tn;
}
+static const enum l1sap_common_sapi common_sapi_by_sapi_t[] = {
+ [GsmL1_Sapi_Idle] = L1SAP_COMMON_SAPI_IDLE,
+ [GsmL1_Sapi_Fcch] = L1SAP_COMMON_SAPI_FCCH,
+ [GsmL1_Sapi_Sch] = L1SAP_COMMON_SAPI_SCH,
+ [GsmL1_Sapi_Sacch] = L1SAP_COMMON_SAPI_SACCH,
+ [GsmL1_Sapi_Sdcch] = L1SAP_COMMON_SAPI_SDCCH,
+ [GsmL1_Sapi_Bcch] = L1SAP_COMMON_SAPI_BCCH,
+ [GsmL1_Sapi_Pch] = L1SAP_COMMON_SAPI_PCH,
+ [GsmL1_Sapi_Agch] = L1SAP_COMMON_SAPI_AGCH,
+ [GsmL1_Sapi_Cbch] = L1SAP_COMMON_SAPI_CBCH,
+ [GsmL1_Sapi_Rach] = L1SAP_COMMON_SAPI_RACH,
+ [GsmL1_Sapi_TchF] = L1SAP_COMMON_SAPI_TCH_F,
+ [GsmL1_Sapi_FacchF] = L1SAP_COMMON_SAPI_FACCH_F,
+ [GsmL1_Sapi_TchH] = L1SAP_COMMON_SAPI_TCH_H,
+ [GsmL1_Sapi_FacchH] = L1SAP_COMMON_SAPI_FACCH_H,
+ [GsmL1_Sapi_Nch] = L1SAP_COMMON_SAPI_NCH,
+ [GsmL1_Sapi_Pdtch] = L1SAP_COMMON_SAPI_PDTCH,
+ [GsmL1_Sapi_Pacch] = L1SAP_COMMON_SAPI_PACCH,
+ [GsmL1_Sapi_Pbcch] = L1SAP_COMMON_SAPI_PBCCH,
+ [GsmL1_Sapi_Pagch] = L1SAP_COMMON_SAPI_PAGCH,
+ [GsmL1_Sapi_Ppch] = L1SAP_COMMON_SAPI_PPCH,
+ [GsmL1_Sapi_Pnch] = L1SAP_COMMON_SAPI_PNCH,
+ [GsmL1_Sapi_Ptcch] = L1SAP_COMMON_SAPI_PTCCH,
+ [GsmL1_Sapi_Prach] = L1SAP_COMMON_SAPI_PRACH,
+};
+
+static enum l1sap_common_sapi get_common_sapi(GsmL1_Sapi_t sapi)
+{
+ if (sapi >= GsmL1_Sapi_NUM)
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ return common_sapi_by_sapi_t[sapi];
+}
+
+static void set_log_ctx_sapi(GsmL1_Sapi_t sapi)
+{
+ l1sap_log_ctx_sapi = get_common_sapi(sapi);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+}
+
static int handle_ph_readytosend_ind(struct oc2gl1_hdl *fl1,
GsmL1_PhReadyToSendInd_t *rts_ind,
struct msgb *l1p_msg)
@@ -863,6 +905,8 @@ static int handle_ph_readytosend_ind(struct oc2gl1_hdl *fl1,
uint8_t chan_nr, link_id;
uint32_t fn;
+ set_log_ctx_sapi(rts_ind->sapi);
+
/* check if primitive should be handled by common part */
chan_nr = chan_nr_by_sapi(&trx->ts[rts_ind->u8Tn], rts_ind->sapi,
rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
@@ -951,12 +995,9 @@ empty_frame:
goto tx;
}
-static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
-{
- LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, "
- "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality,
- m->fBer, m->i16BurstTiming);
-}
+
+#define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d"
+#define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming
static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
GsmL1_MeasParam_t *m, uint32_t fn)
@@ -989,6 +1030,8 @@ static int handle_ph_data_ind(struct oc2gl1_hdl *fl1, GsmL1_PhDataInd_t *data_in
int rc = 0;
int8_t rssi;
+ set_log_ctx_sapi(data_ind->sapi);
+
chan_nr = chan_nr_by_sapi(&trx->ts[data_ind->u8Tn], data_ind->sapi,
data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn);
fn = data_ind->u32Fn;
@@ -1005,10 +1048,10 @@ static int handle_ph_data_ind(struct oc2gl1_hdl *fl1, GsmL1_PhDataInd_t *data_in
process_meas_res(trx, chan_nr, &data_ind->measParam, fn);
- DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
+ DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
get_value_string(oc2gbts_l1sapi_names, data_ind->sapi), (uint32_t)data_ind->hLayer2,
- osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size));
- dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
+ osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
+ LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -1041,11 +1084,10 @@ static int handle_ph_data_ind(struct oc2gl1_hdl *fl1, GsmL1_PhDataInd_t *data_in
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.fn = fn;
l1sap->u.data.rssi = rssi;
- if (!pcu_direct) {
- l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
- l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
- l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
- }
+ l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
+ l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
+ l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
+
return l1sap_up(trx, l1sap);
}
@@ -1058,7 +1100,9 @@ static int handle_ph_ra_ind(struct oc2gl1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
int rc;
struct ph_rach_ind_param rach_ind_param;
- dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
+ set_log_ctx_sapi(ra_ind->sapi);
+ LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
+ LOG_PARAM_MEAS(&ra_ind->measParam));
if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) {
@@ -1283,17 +1327,12 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
/* signal availability */
- 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 (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
} else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
- oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
msgb_free(resp);
@@ -1436,6 +1475,30 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_FATAL, "BTS band %s not supported by hw\n",
gsm_band_name(trx->bts->band));
+ /* Frequency bands indicated to the BSC */
+ switch (fl1h->hw_info.band_support) {
+ case GSM_BAND_450:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_450;
+ break;
+ case GSM_BAND_480:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_480;
+ break;
+ case GSM_BAND_850:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
+ break;
+ case GSM_BAND_900:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
+ break;
+ case GSM_BAND_1800:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
+ break;
+ case GSM_BAND_1900:
+ trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
+ break;
+ }
+
/* Request the activation */
l1if_activate_rf(fl1h, 1);
@@ -1489,7 +1552,7 @@ static int reset_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
return 0;
}
-/* FIXME: This delays the TRX initalization by 5 sec in order to avoid the
+/* FIXME: This delays the TRX initialization by 5 sec in order to avoid the
* occurrence of a race condition in the OML bringup. This a work around and
* should be fixed properly. See also OS#3782, OS#2470 and OS#2469 */
void l1if_reset_cb(void *arg)
@@ -1617,7 +1680,7 @@ int l1if_close(struct oc2gl1_hdl *fl1h)
/* TODO(oramadan) MERGE */
#ifdef MERGE_ME
-static void dsp_alive_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
+static int dsp_alive_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
{
Oc2g_Prim_t *sysp = msgb_sysprim(resp);
Oc2g_IsAliveCnf_t *sac = &sysp->u.isAliveCnf;
@@ -1628,9 +1691,10 @@ static void dsp_alive_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void
get_value_string(oc2gbts_sysprim_names, sysp->id), sac->status, trx->nr);
msgb_free(resp);
+ return 0;
}
-static int dsp_alive_timer_cb(void *data)
+static void dsp_alive_timer_cb(void *data)
{
struct oc2gl1_hdl *fl1h = data;
struct gsm_bts_trx *trx = fl1h->phy_inst->trx;
@@ -1665,7 +1729,7 @@ static int dsp_alive_timer_cb(void *data)
/* allocate new list of sent alarms */
alarm_sent = talloc_zero(fl1h, struct oml_alarm_list);
if (!alarm_sent)
- return -EIO;
+ return;
alarm_sent->alarm_signal = S_NM_OML_BTS_DSP_ALIVE_ALARM;
/* add alarm to sent list */
@@ -1681,14 +1745,14 @@ static int dsp_alive_timer_cb(void *data)
rc = l1if_req_compl(fl1h, msg, dsp_alive_compl_cb, NULL);
if (rc < 0) {
LOGP(DL1C, LOGL_FATAL, "Failed to send %s primitive\n", get_value_string(oc2gbts_sysprim_names, sys_prim->id));
- return -EIO;
+ return;
}
/* restart timer */
fl1h->hw_alive.dsp_alive_cnt = 0;
osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0);
- return 0;
+ return;
}
#endif
@@ -1752,8 +1816,7 @@ int bts_model_phy_link_open(struct phy_link *plink)
}
/ * initialize DSP heart beat alive timer * /
- fl1h->hw_alive.dsp_alive_timer.cb = dsp_alive_timer_cb;
- fl1h->hw_alive.dsp_alive_timer.data = fl1h;
+ osmo_timer_setup(&fl1h->hw_alive.dsp_alive_timer, dsp_alive_timer_cb, fl1h);
fl1h->hw_alive.dsp_alive_cnt = 0;
fl1h->hw_alive.dsp_alive_period = pinst->u.oc2g.dsp_alive_period;
osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0); */
diff --git a/src/osmo-bts-oc2g/l1_if.h b/src/osmo-bts-oc2g/l1_if.h
index 38699e01..8e8a2edb 100644
--- a/src/osmo-bts-oc2g/l1_if.h
+++ b/src/osmo-bts-oc2g/l1_if.h
@@ -30,6 +30,13 @@ enum {
_NUM_MQ_WRITE
};
+/* gsm_bts->model_priv, specific to Open Cellular 2G BTS */
+struct bts_oc2g_priv {
+ uint8_t led_ctrl_mode; /* 0: control by BTS, 1: not control by BTS */
+ struct llist_head ceased_alarm_list; /* ceased alarm list*/
+ unsigned int rtp_drift_thres_ms; /* RTP timestamp drift detection threshold */
+};
+
struct calib_send_state {
FILE *fp;
const char *path;
@@ -129,9 +136,9 @@ int bts_check_for_ciph_cmd(struct oc2gl1_hdl *fl1h,
int l1if_ms_pwr_ctrl(struct gsm_lchan *lchan, const int uplink_target,
const uint8_t ms_power, const float rxLevel);
-static inline struct oc2gl1_hdl *trx_oc2gl1_hdl(struct gsm_bts_trx *trx)
+static inline struct oc2gl1_hdl *trx_oc2gl1_hdl(const struct gsm_bts_trx *trx)
{
- struct phy_instance *pinst = trx_phy_instance(trx);
+ const struct phy_instance *pinst = trx_phy_instance(trx);
OSMO_ASSERT(pinst);
return pinst->u.oc2g.hdl;
}
diff --git a/src/osmo-bts-oc2g/l1_transp_hw.c b/src/osmo-bts-oc2g/l1_transp_hw.c
index e1d46581..5ffd6568 100644
--- a/src/osmo-bts-oc2g/l1_transp_hw.c
+++ b/src/osmo-bts-oc2g/l1_transp_hw.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -88,18 +88,18 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
queue = container_of(fd, struct osmo_wqueue, bfd);
- if (what & BSC_FD_READ)
+ if (what & OSMO_FD_READ)
queue->read_cb(fd);
- if (what & BSC_FD_EXCEPT)
+ if (what & OSMO_FD_EXCEPT)
queue->except_cb(fd);
- if (what & BSC_FD_WRITE) {
+ if (what & OSMO_FD_WRITE) {
struct iovec iov[5];
struct msgb *msg, *tmp;
int written, count = 0;
- fd->when &= ~BSC_FD_WRITE;
+ osmo_fd_write_disable(fd);
llist_for_each_entry(msg, &queue->msg_queue, list) {
/* more writes than we have */
@@ -117,7 +117,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
/* Nothing scheduled? This should not happen. */
if (count == 0) {
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -125,7 +125,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
if (written < 0) {
/* nothing written?! */
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -144,7 +144,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
}
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
}
return 0;
@@ -265,11 +265,7 @@ int l1if_transport_open(int q, struct oc2gl1_hdl *hdl)
buf, 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;
+ osmo_fd_setup(read_ofd, rc, OSMO_FD_READ, l1if_fd_cb, hdl, q);
rc = osmo_fd_register(read_ofd);
if (rc < 0) {
close(read_ofd->fd);
@@ -288,11 +284,7 @@ int l1if_transport_open(int q, struct oc2gl1_hdl *hdl)
}
osmo_wqueue_init(wq, 10);
wq->write_cb = l1fd_write_cb;
- write_ofd->cb = wqueue_vector_cb;
- write_ofd->fd = rc;
- write_ofd->priv_nr = q;
- write_ofd->data = hdl;
- write_ofd->when = BSC_FD_WRITE;
+ osmo_fd_setup(write_ofd, rc, OSMO_FD_WRITE, wqueue_vector_cb, hdl, q);
rc = osmo_fd_register(write_ofd);
if (rc < 0) {
close(write_ofd->fd);
diff --git a/src/osmo-bts-oc2g/main.c b/src/osmo-bts-oc2g/main.c
index 5b66c6f3..75ad3149 100644
--- a/src/osmo-bts-oc2g/main.c
+++ b/src/osmo-bts-oc2g/main.c
@@ -2,7 +2,7 @@
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
* Copyright (C) 2016 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* Based on sysmoBTS:
* (C) 2011-2013 by Harald Welte <laforge@gnumonks.org>
*
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -76,7 +76,6 @@ static int write_status_file(char *status_file, char *status_str)
#include "utils.h"
#include "l1_if.h"
#include "hw_misc.h"
-#include "oml_router.h"
#include "misc/oc2gbts_bid.h"
unsigned int dsp_trace = 0x00000000;
@@ -84,48 +83,63 @@ unsigned int dsp_trace = 0x00000000;
int bts_model_init(struct gsm_bts *bts)
{
struct stat st;
- static struct osmo_fd accept_fd, read_fd;
- int rc;
+ struct bts_oc2g_priv *bts_oc2g = talloc(bts, struct bts_oc2g_priv);
+ bts->model_priv = bts_oc2g;
bts->variant = BTS_OSMO_OC2G;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
+ | NM_IPAC_MASK_GPRS_CODING_MCS;
/* specific default values for OC2G platform */
/* TODO(oramadan) MERGE
- bts->oc2g.led_ctrl_mode = OC2G_BTS_LED_CTRL_MODE_DEFAULT;
+ bts_oc2g->led_ctrl_mode = OC2G_BTS_LED_CTRL_MODE_DEFAULT;
*/
/* RTP drift threshold default */
- /* bts->oc2g.rtp_drift_thres_ms = OC2G_BTS_RTP_DRIFT_THRES_DEFAULT; */
-
- rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd);
- if (rc < 0) {
- fprintf(stderr, "Error creating the OML router: %s rc=%d\n",
- OML_ROUTER_PATH, rc);
- exit(1);
- }
+ /* bts_oc2g->rtp_drift_thres_ms = OC2G_BTS_RTP_DRIFT_THRES_DEFAULT; */
if (stat(OC2GBTS_RF_LOCK_PATH, &st) == 0) {
LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n");
exit(23);
}
- gsm_bts_set_feature(bts, BTS_FEAT_GPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_EGPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
- gsm_bts_set_feature(bts, BTS_FEAT_AGCH_PCH_PROP);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_EFR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
-
- bts_model_vty_init(bts);
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_AGCH_PCH_PROP);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_EFR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
+
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP);
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER);
+
+ /* The default HR codec output format in the absence of saved
+ * vty config needs to match what was implemented previously,
+ * for the sake of existing deployments, i.e., to avoid
+ * a surprise functional change upon software update. */
+ bts->emit_hr_rfc5993 = false;
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = 0x00; /* updated in info_compl_cb() */
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH;
+
trx->nominal_power = 25;
trx->power_params.trx_p_max_out_mdBm = to_mdB(trx->bts->c0->nominal_power);
return 0;
@@ -165,9 +179,11 @@ void bts_update_status(enum bts_global_status which, int on)
void bts_model_print_help()
{
- printf( " -w --hw-version Print the targeted HW Version\n"
- " -M --pcu-direct Force PCU to access message queue for PDCH dchannel directly\n"
- " -p --dsp-trace Set DSP trace flags\n"
+ printf( "\nModel specific options:\n"
+ " -w --hw-version Print the targeted HW Version\n"
+ " -M --pcu-direct Force PCU to access message queue for "
+ "PDCH dchannel directly\n"
+ " -p --dsp-trace Set DSP trace flags\n"
);
}
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_bid.c b/src/osmo-bts-oc2g/misc/oc2gbts_bid.c
index c2cd483d..0589e3f0 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_bid.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_bid.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_bts.c b/src/osmo-bts-oc2g/misc/oc2gbts_bts.c
index b3dae76e..3e5db829 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_bts.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_bts.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_clock.c b/src/osmo-bts-oc2g/misc/oc2gbts_clock.c
index 5263e3ec..10b97a31 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_clock.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_clock.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_led.c b/src/osmo-bts-oc2g/misc/oc2gbts_led.c
index 40d4b722..c2c807b6 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_led.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_led.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_mgr.c b/src/osmo-bts-oc2g/misc/oc2gbts_mgr.c
index 25948b0e..843fbb38 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_mgr.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_mgr.c
@@ -1,7 +1,7 @@
/* Main program for NuRAN Wireless OC-2G BTS management daemon */
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
- *
+ *
* Based on sysmoBTS:
* sysmobts_mgr.c
* (C) 2012 by Harald Welte <laforge@gnumonks.org>
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -201,11 +201,11 @@ static int parse_options(int argc, char **argv)
return 0;
}
-static void signal_handler(int signal)
+static void signal_handler(int signum)
{
- fprintf(stderr, "signal %u received\n", signal);
+ fprintf(stderr, "signal %u received\n", signum);
- switch (signal) {
+ switch (signum) {
case SIGINT:
oc2gbts_check_temp(no_rom_write);
oc2gbts_check_power(no_rom_write);
@@ -214,6 +214,16 @@ static void signal_handler(int signal)
exit(0);
break;
case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report and
+ * then run default SIGABRT handler, who will generate coredump
+ * and abort the process. abort() should do this for us after we
+ * return, but program wouldn't exit if an external SIGABRT is
+ * received.
+ */
+ talloc_report_full(tall_mgr_ctx, stderr);
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ break;
case SIGUSR1:
case SIGUSR2:
talloc_report_full(tall_mgr_ctx, stderr);
@@ -228,31 +238,31 @@ static struct log_info_cat mgr_log_info_cat[] = {
.name = "DTEMP",
.description = "Temperature monitoring",
.color = "\033[1;35m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFW] = {
.name = "DFW",
.description = "Firmware management",
.color = "\033[1;36m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFIND] = {
.name = "DFIND",
.description = "ipaccess-find handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DCALIB] = {
.name = "DCALIB",
.description = "Calibration handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DSWD] = {
.name = "DSWD",
.description = "Software Watchdog",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
};
@@ -280,6 +290,7 @@ int main(int argc, char **argv)
osmo_init_ignore_signals();
signal(SIGINT, &signal_handler);
+ signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
@@ -295,7 +306,7 @@ int main(int argc, char **argv)
exit(1);
}
- rc = telnet_init(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
+ rc = telnet_init_default(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
if (rc < 0) {
fprintf(stderr, "Error initializing telnet\n");
exit(1);
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_calib.c b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_calib.c
index 3ddf0e8c..cf904aea 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_calib.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_calib.c
@@ -17,7 +17,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -171,7 +171,12 @@ static void mgr_gps_checkfix(struct oc2gbts_mgr_instance *mgr)
return;
}
+#if GPSD_API_MAJOR_VERSION >= 9
+ mgr->gps.gps_fix_now = data->fix.time.tv_sec;
+#else
mgr->gps.gps_fix_now = (time_t) data->fix.time;
+#endif
+
LOGP(DCALIB, LOGL_INFO, "Got a GPS fix, satellites used: %d, timestamp: %ld\n",
data->satellites_used, mgr->gps.gps_fix_now);
osmo_timer_del(&mgr->gps.fix_timeout);
@@ -220,10 +225,8 @@ static void mgr_gps_open(struct oc2gbts_mgr_instance *mgr)
mgr->gps.gps_open = 1;
gps_stream(&mgr->gps.gpsdata, WATCH_ENABLE, NULL);
- mgr->gps.gpsfd.data = mgr;
- mgr->gps.gpsfd.cb = mgr_gps_read;
- mgr->gps.gpsfd.when = BSC_FD_READ | BSC_FD_EXCEPT;
- mgr->gps.gpsfd.fd = mgr->gps.gpsdata.gps_fd;
+ osmo_fd_setup(&mgr->gps.gpsfd, mgr->gps.gpsdata.gps_fd, OSMO_FD_READ | OSMO_FD_EXCEPT,
+ mgr_gps_read, mgr, 0);
if (osmo_fd_register(&mgr->gps.gpsfd) < 0) {
LOGP(DCALIB, LOGL_ERROR, "Failed to register GPSD fd\n");
calib_state_reset(mgr, CALIB_FAIL_GPSFIX);
@@ -607,7 +610,7 @@ static void bts_recon_timer_cb(void *data)
select_led_pattern(mgr);
/* The connection failures are to be expected during boot */
- mgr->oc2gbts_ctrl.bts_conn->ofd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(mgr->oc2gbts_ctrl.bts_conn->ofd);
rc = ipa_client_conn_open(mgr->oc2gbts_ctrl.bts_conn);
if (rc < 0) {
LOGP(DLCTRL, LOGL_NOTICE, "Failed to connect to BTS.\n");
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_nl.c b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_nl.c
index db67caf2..1091f622 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_nl.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_nl.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_temp.c b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_temp.c
index f9efd9cd..9a92a075 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_temp.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_temp.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_vty.c b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_vty.c
index 7e80e030..10dda21f 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_mgr_vty.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_mgr_vty.c
@@ -1,5 +1,5 @@
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
- *
+ *
* Based on sysmoBTS:
* sysmobts_mgr_vty.c
* (C) 2014 by oc2gcom - s.f.m.c. GmbH
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -86,35 +86,10 @@ static int go_to_parent(struct vty *vty)
return vty->node;
}
-static int is_config_node(struct vty *vty, int node)
-{
- switch (node) {
- case MGR_NODE:
- case ACT_NORM_NODE:
- case ACT_WARN_NODE:
- case ACT_CRIT_NODE:
- case LIMIT_SUPPLY_TEMP_NODE:
- case LIMIT_SOC_NODE:
- case LIMIT_FPGA_NODE:
- case LIMIT_RMSDET_NODE:
- case LIMIT_OCXO_NODE:
- case LIMIT_TX_TEMP_NODE:
- case LIMIT_PA_TEMP_NODE:
- case LIMIT_SUPPLY_VOLT_NODE:
- case LIMIT_VSWR_NODE:
- case LIMIT_SUPPLY_PWR_NODE:
- case LIMIT_PA_PWR_NODE:
- return 1;
- default:
- return 0;
- }
-}
-
static struct vty_app_info vty_info = {
.name = "oc2gbts-mgr",
.version = PACKAGE_VERSION,
.go_parent_cb = go_to_parent,
- .is_config_node = is_config_node,
.copyright = copyright,
};
@@ -512,35 +487,35 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
oc2gbts_mgr_sensor_get_state(s_mgr->state.state), VTY_NEWLINE);
vty_out(vty, "Current Temperatures%s", VTY_NEWLINE);
oc2gbts_temp_get(OC2GBTS_TEMP_SUPPLY, &temp);
- vty_out(vty, " Main Supply : %4.2f Celcius%s",
+ vty_out(vty, " Main Supply : %4.2f Celsius%s",
temp/ 1000.0f,
VTY_NEWLINE);
oc2gbts_temp_get(OC2GBTS_TEMP_SOC, &temp);
- vty_out(vty, " SoC : %4.2f Celcius%s",
+ vty_out(vty, " SoC : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
oc2gbts_temp_get(OC2GBTS_TEMP_FPGA, &temp);
- vty_out(vty, " FPGA : %4.2f Celcius%s",
+ vty_out(vty, " FPGA : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
if (oc2gbts_option_get(OC2GBTS_OPTION_RMS_FWD) ||
oc2gbts_option_get(OC2GBTS_OPTION_RMS_REFL)) {
oc2gbts_temp_get(OC2GBTS_TEMP_RMSDET, &temp);
- vty_out(vty, " RMSDet : %4.2f Celcius%s",
+ vty_out(vty, " RMSDet : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
}
oc2gbts_temp_get(OC2GBTS_TEMP_OCXO, &temp);
- vty_out(vty, " OCXO : %4.2f Celcius%s",
+ vty_out(vty, " OCXO : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
oc2gbts_temp_get(OC2GBTS_TEMP_TX, &temp);
- vty_out(vty, " TX : %4.2f Celcius%s",
+ vty_out(vty, " TX : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
if (oc2gbts_option_get(OC2GBTS_OPTION_PA_TEMP)) {
oc2gbts_temp_get(OC2GBTS_TEMP_PA, &temp);
- vty_out(vty, " Power Amp : %4.2f Celcius%s",
+ vty_out(vty, " Power Amp : %4.2f Celsius%s",
temp / 1000.0f,
VTY_NEWLINE);
}
@@ -649,7 +624,7 @@ DEFUN(show_thresh, show_thresh_cmd, "show thresholds",
DEFUN(calibrate_clock, calibrate_clock_cmd,
"calibrate clock",
- "Calibration commands\n"
+ "Calibration commands\n"
"Calibrate clock against GPS PPS\n")
{
if (oc2gbts_mgr_calib_run(s_mgr) < 0) {
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_misc.c b/src/osmo-bts-oc2g/misc/oc2gbts_misc.c
index bacf07bd..c3b91ec1 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_misc.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_misc.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -361,7 +361,7 @@ int oc2gbts_firmware_reload(enum oc2gbts_firmware_type type)
case OC2GBTS_FW_DSP:
fd = open(fw_sysfs[type], O_WRONLY);
if (fd < 0) {
- LOGP(DFW, LOGL_ERROR, "unable ot open firmware device %s: %s\n",
+ LOGP(DFW, LOGL_ERROR, "unable to open firmware device %s: %s\n",
fw_sysfs[type], strerror(errno));
close(fd);
return fd;
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_nl.c b/src/osmo-bts-oc2g/misc/oc2gbts_nl.c
index 39f64aae..d1d1bd13 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_nl.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_nl.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_nl.h b/src/osmo-bts-oc2g/misc/oc2gbts_nl.h
index 340cf117..b5a15403 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_nl.h
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_nl.h
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_par.c b/src/osmo-bts-oc2g/misc/oc2gbts_par.c
index 7dc77c90..fef350f2 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_par.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_par.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_power.c b/src/osmo-bts-oc2g/misc/oc2gbts_power.c
index 4e2fc95a..46b8fc03 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_power.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_power.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_swd.c b/src/osmo-bts-oc2g/misc/oc2gbts_swd.c
index 59b795ac..6358d4e2 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_swd.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_swd.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -161,7 +161,7 @@ int oc2gbts_swd_init(struct oc2gbts_mgr_instance *mgr, int swd_num_events)
the value must be in the range of [0,'swd_num_events'[ (see oc2gbts_swd_init).
For example, if 'swd_num_events' was 64, 'swd_event' events are numbered 0 to 63.
WARNING: if this function can be used from multiple threads at the same time,
- it must be protected with a kind of mutex to avoid loosing event notification.
+ it must be protected with a kind of mutex to avoid losing event notification.
*/
int oc2gbts_swd_event(struct oc2gbts_mgr_instance *mgr, enum mgr_swd_events swd_event)
{
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_temp.c b/src/osmo-bts-oc2g/misc/oc2gbts_temp.c
index 8425dda3..d7afa4e6 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_temp.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_temp.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/misc/oc2gbts_util.c b/src/osmo-bts-oc2g/misc/oc2gbts_util.c
index b71f0383..0919da93 100644
--- a/src/osmo-bts-oc2g/misc/oc2gbts_util.c
+++ b/src/osmo-bts-oc2g/misc/oc2gbts_util.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/oc2gbts.c b/src/osmo-bts-oc2g/oc2gbts.c
index 012d705c..5860a566 100644
--- a/src/osmo-bts-oc2g/oc2gbts.c
+++ b/src/osmo-bts-oc2g/oc2gbts.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-oc2g/oc2gbts.h b/src/osmo-bts-oc2g/oc2gbts.h
index 9eb87452..80fd1d59 100644
--- a/src/osmo-bts-oc2g/oc2gbts.h
+++ b/src/osmo-bts-oc2g/oc2gbts.h
@@ -39,26 +39,26 @@ enum oc2g_auto_pwr_adjust_mode{
};
enum l1prim_type oc2gbts_get_l1prim_type(GsmL1_PrimId_t id);
-const struct value_string oc2gbts_l1prim_names[GsmL1_PrimId_NUM+1];
+extern const struct value_string oc2gbts_l1prim_names[GsmL1_PrimId_NUM+1];
GsmL1_PrimId_t oc2gbts_get_l1prim_conf(GsmL1_PrimId_t id);
enum l1prim_type oc2gbts_get_sysprim_type(Oc2g_PrimId_t id);
-const struct value_string oc2gbts_sysprim_names[Oc2g_PrimId_NUM+1];
+extern const struct value_string oc2gbts_sysprim_names[Oc2g_PrimId_NUM+1];
Oc2g_PrimId_t oc2gbts_get_sysprim_conf(Oc2g_PrimId_t id);
-const struct value_string oc2gbts_l1sapi_names[GsmL1_Sapi_NUM+1];
-const struct value_string oc2gbts_l1status_names[GSML1_STATUS_NUM+1];
+extern const struct value_string oc2gbts_l1sapi_names[GsmL1_Sapi_NUM+1];
+extern const struct value_string oc2gbts_l1status_names[GSML1_STATUS_NUM+1];
-const struct value_string oc2gbts_tracef_names[29];
-const struct value_string oc2gbts_tracef_docs[29];
+extern const struct value_string oc2gbts_tracef_names[29];
+extern const struct value_string oc2gbts_tracef_docs[29];
-const struct value_string oc2gbts_tch_pl_names[15];
+extern const struct value_string oc2gbts_tch_pl_names[15];
-const struct value_string oc2gbts_clksrc_names[10];
+extern const struct value_string oc2gbts_clksrc_names[10];
-const struct value_string oc2gbts_dir_names[6];
+extern const struct value_string oc2gbts_dir_names[6];
-const struct value_string oc2gbts_rsl_ho_causes[IPAC_HO_RQD_CAUSE_MAX];
+extern const struct value_string oc2gbts_rsl_ho_causes[IPAC_HO_RQD_CAUSE_MAX];
enum pdch_cs {
PDCH_CS_1,
@@ -77,7 +77,7 @@ enum pdch_cs {
_NUM_PDCH_CS
};
-const uint8_t pdch_msu_size[_NUM_PDCH_CS];
+extern const uint8_t pdch_msu_size[_NUM_PDCH_CS];
/* OC2G default parameters */
#define OC2G_BTS_MAX_CELL_SIZE_DEFAULT 166 /* 166 qbits is default value */
diff --git a/src/osmo-bts-oc2g/oc2gbts_vty.c b/src/osmo-bts-oc2g/oc2gbts_vty.c
index 1f092dde..051528ab 100644
--- a/src/osmo-bts-oc2g/oc2gbts_vty.c
+++ b/src/osmo-bts-oc2g/oc2gbts_vty.c
@@ -2,7 +2,7 @@
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
* Copyright (C) 2016 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* Based on sysmoBTS:
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2012,2013 by Holger Hans Peter Freyther
@@ -47,6 +47,7 @@
#include <osmo-bts/signal.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
@@ -69,8 +70,6 @@ extern int rsl_tx_preproc_meas_res(struct gsm_lchan *lchan);
TRX_STR
#define DSP_TRACE_F_STR "DSP Trace Flag\n"
-static struct gsm_bts *vty_bts;
-
static const struct value_string oc2g_pedestal_mode_strs[] = {
{ OC2G_PEDESTAL_OFF, "off" },
{ OC2G_PEDESTAL_ON, "on" },
@@ -113,7 +112,7 @@ DEFUN(cfg_phy_dsp_trace_f, cfg_phy_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(oc2gbts_tracef_names, argv[1]);
+ flag = get_string_value(oc2gbts_tracef_names, argv[0]);
pinst->u.oc2g.dsp_trace_f |= flag;
return CMD_SUCCESS;
@@ -125,7 +124,7 @@ DEFUN(cfg_phy_no_dsp_trace_f, cfg_phy_no_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(oc2gbts_tracef_names, argv[1]);
+ flag = get_string_value(oc2gbts_tracef_names, argv[0]);
pinst->u.oc2g.dsp_trace_f &= ~flag;
return CMD_SUCCESS;
@@ -135,11 +134,11 @@ DEFUN(cfg_phy_no_dsp_trace_f, cfg_phy_no_dsp_trace_f_cmd,
/* runtime */
DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd,
- "show trx <0-0> dsp-trace-flags",
+ "show dsp-trace-flags trx <0-0>",
SHOW_TRX_STR "Display the current setting of the DSP trace flags")
{
int trx_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct oc2gl1_hdl *fl1h;
int i;
@@ -261,7 +260,7 @@ DEFUN(activate_lchan, activate_lchan_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[3]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -282,9 +281,9 @@ DEFUN(set_tx_power, set_tx_power_cmd,
{
int trx_nr = atoi(argv[0]);
int power = atoi(argv[1]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
- power_ramp_start(trx, to_mdB(power), 1);
+ power_ramp_start(trx, to_mdB(power), 1, NULL);
return CMD_SUCCESS;
}
@@ -299,7 +298,7 @@ DEFUN(loopback, loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -318,7 +317,7 @@ DEFUN(no_loopback, no_loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -335,12 +334,6 @@ DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
int nominal_power = atoi(argv[0]);
struct gsm_bts_trx *trx = vty->index;
- if (( nominal_power > 25 ) || ( nominal_power < 0 )) {
- vty_out(vty, "Nominal Tx power level must be between 0 and 25 dBm (%d) %s",
- nominal_power, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
trx->nominal_power = nominal_power;
trx->power_params.trx_p_max_out_mdBm = to_mdB(nominal_power);
@@ -354,12 +347,6 @@ DEFUN(cfg_phy_max_cell_size, cfg_phy_max_cell_size_cmd,
struct phy_instance *pinst = vty->index;
int cell_size = (uint8_t)atoi(argv[0]);
- if (( cell_size > 166 ) || ( cell_size < 0 )) {
- vty_out(vty, "Max cell size must be between 0 and 166 qbits (%d) %s",
- cell_size, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
pinst->u.oc2g.max_cell_size = (uint8_t)cell_size;
return CMD_SUCCESS;
}
@@ -372,10 +359,7 @@ DEFUN(cfg_phy_pedestal_mode, cfg_phy_pedestal_mode_cmd,
struct phy_instance *pinst = vty->index;
int val = get_string_value(oc2g_pedestal_mode_strs, argv[0]);
- if((val < OC2G_PEDESTAL_OFF) || (val > OC2G_PEDESTAL_ON)) {
- vty_out(vty, "Invalid unused time-slot transmission mode %d%s", val, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ OSMO_ASSERT(val != -EINVAL);
pinst->u.oc2g.pedestal_mode = (uint8_t)val;
return CMD_SUCCESS;
@@ -388,12 +372,6 @@ DEFUN(cfg_phy_dsp_alive_timer, cfg_phy_dsp_alive_timer_cmd,
struct phy_instance *pinst = vty->index;
uint8_t period = (uint8_t)atoi(argv[0]);
- if (( period > 60 ) || ( period < 0 )) {
- vty_out(vty, "DSP heart beat alive timer period must be between 0 and 60 seconds (%d) %s",
- period, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
pinst->u.oc2g.dsp_alive_period = period;
return CMD_SUCCESS;
}
@@ -405,10 +383,7 @@ DEFUN(cfg_phy_auto_tx_pwr_adj, cfg_phy_auto_tx_pwr_adj_cmd,
struct phy_instance *pinst = vty->index;
int val = get_string_value(oc2g_auto_adj_pwr_strs, argv[0]);
- if((val < OC2G_TX_PWR_ADJ_NONE) || (val > OC2G_TX_PWR_ADJ_AUTO)) {
- vty_out(vty, "Invalid output power adjustment mode %d%s", val, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ OSMO_ASSERT(val != -EINVAL);
pinst->u.oc2g.tx_pwr_adj_mode = (uint8_t)val;
return CMD_SUCCESS;
@@ -421,12 +396,6 @@ DEFUN(cfg_phy_tx_red_pwr_8psk, cfg_phy_tx_red_pwr_8psk_cmd,
struct phy_instance *pinst = vty->index;
int val = atoi(argv[0]);
- if ((val > 40) || (val < 0)) {
- vty_out(vty, "Reduction Tx power level must be between 0 and 40 dB (%d) %s",
- val, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
pinst->u.oc2g.tx_pwr_red_8psk = (uint8_t)val;
return CMD_SUCCESS;
}
@@ -438,19 +407,12 @@ DEFUN(cfg_phy_c0_idle_red_pwr, cfg_phy_c0_idle_red_pwr_cmd,
struct phy_instance *pinst = vty->index;
int val = atoi(argv[0]);
- if ((val > 40) || (val < 0)) {
- vty_out(vty, "Reduction Tx power level must be between 0 and 40 dB (%d) %s",
- val, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
pinst->u.oc2g.tx_c0_idle_pwr_red = (uint8_t)val;
return CMD_SUCCESS;
}
DEFUN(trigger_ho_cause, trigger_ho_cause_cmd, "HIDDEN", TRX_STR)
{
- struct gsm_network *net = gsmnet_from_vty(vty);
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
@@ -460,7 +422,7 @@ DEFUN(trigger_ho_cause, trigger_ho_cause_cmd, "HIDDEN", TRX_STR)
/* uint8_t old_ho_cause; */
/* get BTS pointer */
- bts = gsm_bts_num(net, 0);
+ bts = gsm_bts_num(g_bts_sm, 0);
if (!bts) {
vty_out(vty, "Can not get BTS node %s", VTY_NEWLINE);
return CMD_WARNING;
@@ -541,7 +503,7 @@ DEFUN(cfg_bts_rtp_drift_threshold, cfg_bts_rtp_drift_threshold_cmd,
}
*/
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
{
/* TODO(oramadan) MERGE
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
@@ -555,16 +517,16 @@ 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_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,VTY_NEWLINE);
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
int i;
@@ -599,44 +561,42 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst
pinst->u.oc2g.tx_c0_idle_pwr_red, VTY_NEWLINE);
}
-int bts_model_vty_init(struct gsm_bts *bts)
+int bts_model_vty_init(void *ctx)
{
- vty_bts = bts;
-
/* runtime-patch the command strings with debug levels */
- dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, oc2gbts_tracef_names,
+ dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, oc2gbts_tracef_names,
"phy <0-1> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, oc2gbts_tracef_docs,
+ dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, oc2gbts_tracef_docs,
TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
- no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, oc2gbts_tracef_names,
+ no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, oc2gbts_tracef_names,
"no phy <0-1> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, oc2gbts_tracef_docs,
+ no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, oc2gbts_tracef_docs,
NO_STR TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
- cfg_phy_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts,
+ cfg_phy_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx,
oc2gbts_tracef_names,
"dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- cfg_phy_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts,
+ cfg_phy_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx,
oc2gbts_tracef_docs,
DSP_TRACE_F_STR,
"\n", "", 0);
- cfg_phy_no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts,
+ cfg_phy_no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx,
oc2gbts_tracef_names,
"no dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- cfg_phy_no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts,
+ cfg_phy_no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx,
oc2gbts_tracef_docs,
NO_STR DSP_TRACE_F_STR,
"\n", "", 0);
- trigger_ho_cause_cmd.string = vty_cmd_string_from_valstr(bts,
+ trigger_ho_cause_cmd.string = vty_cmd_string_from_valstr(ctx,
oc2gbts_rsl_ho_causes,
"trigger-ho-cause trx <0-1> ts <0-7> lchan <0-1> cause (",
"|",")", VTY_DO_LOWER);
diff --git a/src/osmo-bts-oc2g/oml.c b/src/osmo-bts-oc2g/oml.c
index 32024090..4b434e83 100644
--- a/src/osmo-bts-oc2g/oml.c
+++ b/src/osmo-bts-oc2g/oml.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -26,6 +26,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
#include <nrw/oc2g/gsml1prim.h>
#include <nrw/oc2g/gsml1const.h>
@@ -42,11 +43,14 @@
#include <osmo-bts/phy_link.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
#include "l1_if.h"
#include "oc2gbts.h"
#include "utils.h"
+static void dump_lch_par(int logl, GsmL1_LogChParam_t *lch_par, GsmL1_Sapi_t sapi);
+
static int mph_info_chan_confirm(struct gsm_lchan *lchan,
enum osmo_mph_info_type type, uint8_t cause)
{
@@ -91,7 +95,7 @@ static const enum GsmL1_LogChComb_t pchan_to_logChComb[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII,
[GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0,
/*
- * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be
+ * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_OSMO_DYN should not be
* part of this, only "real" pchan values will be looked up here.
* See the callers of ts_connect_as().
*/
@@ -268,36 +272,48 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);
GsmL1_Status_t status = prim_status(l1p);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);
if (status != GsmL1_Status_Success) {
LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",
get_value_string(oc2gbts_l1prim_names, l1p->id),
get_value_string(oc2gbts_l1status_names, status));
msgb_free(l1_msg);
- return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ case NM_OC_CHANNEL:
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ default:
+ OSMO_ASSERT(0);
+ }
}
msgb_free(l1_msg);
-
- /* Set to Operational State: Enabled */
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
-
- /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
- if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&
- mo->obj_inst.ts_nr == 0) {
- struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
- DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
- mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
- LCHAN_REL_ACT_OML;
- lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
- if (cbch) {
- cbch->rel_act_kind = LCHAN_REL_ACT_OML;
- lchan_activate(cbch);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ case NM_OC_CHANNEL:
+ /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
+ if (mo->obj_inst.trx_nr == 0 &&
+ mo->obj_inst.ts_nr == 0) {
+ struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
+ DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
+ mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
+ LCHAN_REL_ACT_OML;
+ lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
+ if (cbch) {
+ cbch->rel_act_kind = LCHAN_REL_ACT_OML;
+ lchan_activate(cbch);
+ }
}
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi,
+ NM_EV_OPSTART_ACK, NULL);
+ default:
+ OSMO_ASSERT(0);
}
-
- /* Send OPSTART ack */
- return oml_mo_opstart_ack(mo);
}
static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
@@ -371,7 +387,7 @@ static int trx_init_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
*/
/* Begin to ramp up the power */
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
return opstart_compl(&trx->mo, l1_msg);
}
@@ -433,9 +449,16 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->freqBand = oc2g_band;
dev_par->u16Arfcn = trx->arfcn;
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
- dev_par->u8NbTsc = trx->bts->bsic & 7;
- dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
- ? 0.0 : trx->bts->ul_power_target;
+ dev_par->u8NbTsc = BTS_TSC(trx->bts);
+
+ if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+ /* Target is in the middle between lower and upper RxLev thresholds */
+ int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+ int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+ dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+ } else {
+ dev_par->fRxPowerLevel = 0.0;
+ }
dev_par->fTxPowerLevel = 0.0;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (Band %d, ARFCN %u, TSC %u, RxPower % 2f dBm, "
@@ -446,9 +469,9 @@ static int trx_init(struct gsm_bts_trx *trx)
return l1if_gsm_req_compl(fl1h, msg, trx_init_compl_cb, NULL);
}
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
- struct oc2gl1_hdl *fl1h = trx_oc2gl1_hdl(trx);
+ const struct oc2gl1_hdl *fl1h = trx_oc2gl1_hdl(trx);
return fl1h->hLayer1;
}
@@ -457,20 +480,24 @@ static int trx_close_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
void *data)
{
msgb_free(l1_msg);
+ bts_model_trx_close_cb(trx, 0);
return 0;
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
struct oc2gl1_hdl *fl1h = trx_oc2gl1_hdl(trx);
struct msgb *msg;
+ int rc;
msg = l1p_msgb_alloc();
prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphCloseReq, fl1h,
l1p_handle_for_trx(trx));
LOGP(DL1C, LOGL_NOTICE, "Close TRX %u\n", trx->nr);
- return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ rc = l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ if (rc < 0)
+ bts_model_trx_close_cb(trx, rc);
}
static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb)
@@ -515,7 +542,7 @@ static int ts_connect_as(struct gsm_bts_trx_ts *ts,
GsmL1_MphConnectReq_t *cr;
if (pchan == GSM_PCHAN_TCH_F_PDCH
- || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ || pchan == GSM_PCHAN_OSMO_DYN) {
LOGP(DL1C, LOGL_ERROR,
"%s Requested TS connect as %s,"
" expected a specific pchan instead\n",
@@ -535,7 +562,7 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts)
{
enum gsm_phys_chan_config pchan = ts->pchan;
switch (pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
/* First connect as NONE, until first RSL CHAN ACT. */
pchan = GSM_PCHAN_NONE;
@@ -559,8 +586,7 @@ GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan)
case GSM_LCHAN_TCH_H:
return GsmL1_Sapi_TchH;
default:
- LOGP(DL1C, LOGL_NOTICE, "%s cannot determine L1 SAPI\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "cannot determine L1 SAPI\n");
break;
}
return GsmL1_Sapi_Idle;
@@ -570,7 +596,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
{
enum gsm_phys_chan_config pchan = lchan->ts->pchan;
- if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH)
+ if (pchan == GSM_PCHAN_OSMO_DYN)
pchan = lchan->ts->dyn.pchan_want;
switch (pchan) {
@@ -589,7 +615,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
case GSM_PCHAN_PDCH:
case GSM_PCHAN_UNKNOWN:
default:
- /* case GSM_PCHAN_TCH_F_TCH_H_PDCH: is caught above */
+ /* case GSM_PCHAN_OSMO_DYN: is caught above */
return GsmL1_SubCh_NA;
}
@@ -652,10 +678,6 @@ static const struct sapi_dir pdtch_sapis[] = {
#endif
};
-static const struct sapi_dir ho_sapis[] = {
- { GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink },
-};
-
struct lchan_sapis {
const struct sapi_dir *sapis;
unsigned int num_sapis;
@@ -688,11 +710,6 @@ static const struct lchan_sapis sapis_for_lchan[_GSM_LCHAN_MAX] = {
},
};
-static const struct lchan_sapis sapis_for_ho = {
- .sapis = ho_sapis,
- .num_sapis = ARRAY_SIZE(ho_sapis),
-};
-
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
@@ -780,12 +797,8 @@ static void sapi_queue_dispatch(struct gsm_lchan *lchan, int status)
talloc_free(cmd);
if (end || llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_DEBUG,
- "%s End of SAPI cmd queue encountered.%s\n",
- gsm_lchan_name(lchan),
- llist_empty(&lchan->sapi_cmds)
- ? " Queue is now empty."
- : " More pending.");
+ LOGPLCHAN(lchan, DL1C, LOGL_DEBUG, "End of SAPI cmd queue encountered.%s\n",
+ llist_empty(&lchan->sapi_cmds) ? " Queue is now empty." : " More pending.");
return;
}
@@ -825,9 +838,8 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_l1sapi_names, ic->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.conf (%s ",
+ get_value_string(oc2gbts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(oc2gbts_dir_names, ic->dir));
@@ -848,19 +860,15 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
lchan->sapis_ul[ic->sapi] = status;
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_ACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -934,15 +942,14 @@ static void set_payload_format(GsmL1_LogChParam_t *lch_par)
lch_par->tch.tchPlFmt = GsmL1_TchPlFmt_Rtp;
}
-static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
+static int lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
{
struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
struct gsm48_multi_rate_conf *mr_conf =
(struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
int j;
- LOGP(DL1C, LOGL_INFO, "%s: %s tch_mode=0x%02x\n",
- gsm_lchan_name(lchan), __FUNCTION__, lchan->tch_mode);
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s tch_mode=0x%02x\n", __func__, lchan->tch_mode);
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
@@ -970,7 +977,9 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_SPEECH_AMR:
lch_par->tch.tchPlType = GsmL1_TchPlType_Amr;
set_payload_format(lch_par);
- lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd; /* FIXME? */
+ /* At call set-up, after every successful handover and after a channel mode modify, the
+ * default phase (odd) shall be used in downlink direction. */
+ lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd;
lch_par->tch.amrInitCodecMode = amr_get_initial_mode(lchan);
/* initialize to clean state */
@@ -1019,10 +1028,13 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
- LOGP(DL1C, LOGL_ERROR, "%s: CSD not supported!\n",
- gsm_lchan_name(lchan));
- break;
+ default:
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Channel mode %s is not supported!\n",
+ gsm48_chan_mode_name(lchan->tch_mode));
+ return -ENOTSUP;
}
+
+ return 0;
}
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
@@ -1031,6 +1043,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
struct msgb *msg = l1p_msgb_alloc();
int sapi = cmd->sapi;
int dir = cmd->dir;
+ int rc;
GsmL1_MphActivateReq_t *act_req;
GsmL1_LogChParam_t *lch_par;
@@ -1053,7 +1066,10 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
case GsmL1_Sapi_TchH:
case GsmL1_Sapi_TchF:
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/*
* Be sure that every packet is received, even if it
* fails. In this case the length might be lower or 0.
@@ -1086,9 +1102,9 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.req (hL2=0x%08x, %s ",
- gsm_lchan_name(lchan), (uint32_t)act_req->hLayer2,
- get_value_string(oc2gbts_l1sapi_names, act_req->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.req (hL2=0x%08x, %s ",
+ (uint32_t)act_req->hLayer2, get_value_string(oc2gbts_l1sapi_names, act_req->sapi));
+ dump_lch_par(LOGL_INFO, lch_par, act_req->sapi);
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(oc2gbts_dir_names, act_req->dir));
@@ -1112,9 +1128,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status)
/* FIXME: Error handling */
if (status != GsmL1_Status_Success) {
- LOGP(DL1C, LOGL_ERROR,
- "%s act failed mark broken due status: %d\n",
- gsm_lchan_name(lchan), status);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "act failed mark broken due status: %d\n", status);
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_PROCESSOR_OVERLOAD);
@@ -1161,14 +1175,12 @@ int lchan_activate(struct gsm_lchan *lchan)
lchan_set_state(lchan, LCHAN_S_ACT_REQ);
if (!llist_empty(&lchan->sapi_cmds))
- LOGP(DL1C, LOGL_ERROR,
- "%s Trying to activate lchan, but commands in queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate lchan, but commands in queue\n");
- /* override the regular SAPIs if this is the first hand-over
- * related activation of the LCHAN */
- if (lchan->ho.active == HANDOVER_ENABLED)
- s4l = &sapis_for_ho;
+ /* For handover, always start the main channel immediately. lchan->want_dl_sacch_active indicates whether dl
+ * SACCH should be activated. Also, for HO, start the RACH SAPI. */
+ if (lchan->ho.active == HANDOVER_ENABLED || rsl_chan_rt_is_asci(lchan->rsl_chan_rt))
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
for (i = 0; i < s4l->num_sapis; i++) {
int sapi = s4l->sapis[i].sapi;
@@ -1181,12 +1193,14 @@ int lchan_activate(struct gsm_lchan *lchan)
fl1h->alive_prim_cnt = 0;
osmo_timer_schedule(&fl1h->alive_timer, 5, 0);
}
- enqueue_sapi_act_cmd(lchan, sapi, dir);
- }
-#warning "FIXME: Should this be in sapi_activate_cb?"
- lchan_init_lapdm(lchan);
+ /* For handover, possibly postpone activating the dl SACCH until the HO RACH is received. */
+ if (sapi == GsmL1_Sapi_Sacch && dir == GsmL1_Dir_TxDownlink
+ && !lchan->want_dl_sacch_active)
+ continue;
+ enqueue_sapi_act_cmd(lchan, sapi, dir);
+ }
return 0;
}
@@ -1318,9 +1332,8 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_l1cfgt_names, cc->cfgParamId));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.conf (%s) ",
+ get_value_string(oc2gbts_l1cfgt_names, cc->cfgParamId));
switch (cc->cfgParamId) {
case GsmL1_ConfigParamId_SetLogChParams:
@@ -1352,9 +1365,7 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
break;
}
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got ciphering conf with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got ciphering conf with empty queue\n");
goto err;
}
@@ -1379,6 +1390,7 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
struct msgb *msg = l1p_msgb_alloc();
GsmL1_MphConfigReq_t *conf_req;
GsmL1_LogChParam_t *lch_par;
+ int rc;
/* channel mode, encryption and/or multirate have changed */
@@ -1393,7 +1405,10 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
conf_req->hLayer3 = (HANDLE)l1if_lchan_to_hLayer(lchan);
lch_par = &conf_req->cfgParams.setLogChParams.logChParams;
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/* Update the MS Power Level */
if (cmd->sapi == GsmL1_Sapi_Sacch && trx_ms_pwr_ctrl_is_osmo(trx))
@@ -1401,10 +1416,8 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
/* FIXME: update encryption */
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.req (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_l1sapi_names,
- conf_req->cfgParams.setLogChParams.sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.req (%s) ",
+ get_value_string(oc2gbts_l1sapi_names, conf_req->cfgParams.setLogChParams.sapi));
LOGPC(DL1C, LOGL_INFO, "cfgParams Tn=%u, subCh=%u, dir=0x%x ",
conf_req->cfgParams.setLogChParams.u8Tn,
conf_req->cfgParams.setLogChParams.subCh,
@@ -1512,11 +1525,9 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c
return -EINVAL;
cfgr->cfgParams.setCipheringParams.cipherId = rsl2l1_ciph[lchan->encr.alg_id];
- LOGP(DL1C, LOGL_NOTICE, "%s SET_CIPHERING (ALG=%u %s)\n",
- gsm_lchan_name(lchan),
- cfgr->cfgParams.setCipheringParams.cipherId,
- get_value_string(oc2gbts_dir_names,
- cfgr->cfgParams.setCipheringParams.dir));
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "SET_CIPHERING (ALG=%u %s)\n",
+ cfgr->cfgParams.setCipheringParams.cipherId,
+ get_value_string(oc2gbts_dir_names, cfgr->cfgParams.setCipheringParams.dir));
memcpy(cfgr->cfgParams.setCipheringParams.u8Kc,
lchan->encr.key, lchan->encr.key_len);
@@ -1594,9 +1605,8 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_l1sapi_names, ic->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.conf (%s ",
+ get_value_string(oc2gbts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(oc2gbts_dir_names, ic->dir));
@@ -1618,19 +1628,15 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got de-activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got de-activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_DEACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -1655,9 +1661,8 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd
deact_req->sapi = cmd->sapi;
deact_req->hLayer3 = (HANDLE)l1if_lchan_to_hLayer(lchan);
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.req (%s ",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_l1sapi_names, deact_req->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.req (%s ",
+ get_value_string(oc2gbts_l1sapi_names, deact_req->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(oc2gbts_dir_names, deact_req->dir));
@@ -1669,8 +1674,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status)
{
/* FIXME: Error handling. There is no NACK... */
if (status != GsmL1_Status_Success && lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s is now broken. Stopping the release.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "is now broken. Stopping the release.\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
@@ -1727,17 +1731,9 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir)
return enqueue_sapi_deact_cmd(lchan, sapi, dir);
}
-static int release_sapis_for_ho(struct gsm_lchan *lchan)
+static int release_sapi_ul_rach(struct gsm_lchan *lchan)
{
- int res = 0;
- int i;
-
- const struct lchan_sapis *s4l = &sapis_for_ho;
-
- for (i = s4l->num_sapis-1; i >= 0; i--)
- res |= check_sapi_release(lchan,
- s4l->sapis[i].sapi, s4l->sapis[i].dir);
- return res;
+ return check_sapi_release(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
}
static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
@@ -1759,12 +1755,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
}
/* always attempt to disable the RACH burst */
- res |= release_sapis_for_ho(lchan);
+ res |= release_sapi_ul_rach(lchan);
/* nothing was queued */
if (res == 0) {
- LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "all SAPIs already released?\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
}
@@ -1811,33 +1806,24 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
void *obj)
{
/* FIXME: more checks if the attributes are valid */
-
- switch (msg_type) {
- case NM_MT_SET_CHAN_ATTR:
- /* our L1 only supports one global TSC for all channels
- * one one TRX, so we need to make sure not to activate
- * channels with a different TSC!! */
- if (TLVP_PRESENT(new_attr, NM_ATT_TSC) &&
- TLVP_LEN(new_attr, NM_ATT_TSC) >= 1 &&
- *TLVP_VAL(new_attr, NM_ATT_TSC) != (bts->bsic & 7)) {
- LOGP(DOML, LOGL_ERROR, "Channel TSC %u != BSIC-TSC %u\n",
- *TLVP_VAL(new_attr, NM_ATT_TSC), bts->bsic & 7);
- return -NM_NACK_PARAM_RANGE;
- }
- break;
- }
return 0;
}
/* callback from OML */
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
-{
- if (kind == NM_OC_RADIO_CARRIER) {
- struct gsm_bts_trx *trx = obj;
- struct oc2gl1_hdl *fl1h = trx_oc2gl1_hdl(trx);
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
+{
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx;
+ struct oc2gl1_hdl *fl1h;
+ uint8_t cell_size;
+
+ switch (foh->msg_type) {
+ case NM_MT_SET_RADIO_ATTR:
+ trx = obj;
+ fl1h = trx_oc2gl1_hdl(trx);
/* convert max TA to max cell size in qbits */
- uint8_t cell_size = bts->max_ta << 2;
+ cell_size = bts->max_ta << 2;
/* We do not need to check for L1 handle
* because the max cell size parameter can receive before MphInit */
@@ -1850,7 +1836,7 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
/* Did we go through MphInit yet? If yes fire and forget */
if (fl1h->hLayer1) {
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
if (fl1h->phy_inst->u.oc2g.tx_pwr_red_8psk != trx->max_power_backoff_8psk) {
/* update current Tx power backoff for 8-PSK */
@@ -1866,40 +1852,37 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
l1if_set_txpower_c0_idle_pwr_red(fl1h, fl1h->phy_inst->u.oc2g.tx_c0_idle_pwr_red);
}
}
-
+ break;
}
- /* FIXME: we actaully need to send a ACK or NACK for the OML message */
- return oml_fom_ack_nack(msg, 0);
+ return 0;
}
/* callback from OML */
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj)
{
+ struct gsm_bts_bb_trx *bb_transc;
+ struct gsm_bts_trx* trx;
+ struct gsm_bts_trx_ts *ts;
int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- rc = trx_init(obj);
- break;
- case NM_OC_CHANNEL:
- rc = ts_opstart(obj);
- break;
- case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
+ case NM_OC_BTS:
case NM_OC_BASEB_TRANSC:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, -1);
- rc = oml_mo_opstart_ack(mo);
- if (mo->obj_class == NM_OC_BTS) {
- oml_mo_state_chg(&bts->mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nse.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.cell.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK);
- }
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ trx = (struct gsm_bts_trx *) obj;
+ rc = trx_init(trx);
+ break;
+ case NM_OC_CHANNEL:
+ ts = (struct gsm_bts_trx_ts*) obj;
+ rc = ts_opstart(ts);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -1970,24 +1953,17 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
*/
int l1if_rsl_chan_mod(struct gsm_lchan *lchan)
{
- const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
- unsigned int i;
-
if (lchan->ho.active == HANDOVER_NONE)
return -1;
- LOGP(DHO, LOGL_ERROR, "%s modifying channel for handover\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DHO, LOGL_ERROR, "modifying channel for handover\n");
/* Give up listening to RACH bursts */
- release_sapis_for_ho(lchan);
+ release_sapi_ul_rach(lchan);
- /* Activate the normal SAPIs */
- for (i = 0; i < s4l->num_sapis; i++) {
- int sapi = s4l->sapis[i].sapi;
- int dir = s4l->sapis[i].dir;
- enqueue_sapi_act_cmd(lchan, sapi, dir);
- }
+ /* All the normal SAPIs have already been activated, only DL SACCH may still be missing. */
+ if (lchan->want_dl_sacch_active)
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Sacch, GsmL1_Dir_TxDownlink);
return 0;
}
@@ -1996,8 +1972,7 @@ int l1if_rsl_chan_rel(struct gsm_lchan *lchan)
{
/* A duplicate RF Release Request, ignore it */
if (lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s already in release request state.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "already in release request state.\n");
return 0;
}
@@ -2033,8 +2008,7 @@ static int ts_disconnect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- LOGP(DL1C, LOGL_DEBUG, "%s Rx mphDisconnectCnf\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "Rx mphDisconnectCnf\n");
cb_ts_disconnected(ts);
@@ -2049,7 +2023,7 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
struct oc2gl1_hdl *fl1h = trx_oc2gl1_hdl(ts->trx);
GsmL1_MphDisconnectReq_t *cr;
- DEBUGP(DRSL, "%s TS disconnect\n", gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "TS disconnect\n");
cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphDisconnectReq, fl1h,
l1p_handle_for_ts(ts));
cr->u8Tn = ts->nr;
@@ -2065,12 +2039,11 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- DEBUGP(DL1C, "%s %s Rx mphConnectCnf flags=%s%s%s\n",
- gsm_lchan_name(ts->lchan),
- gsm_pchan_name(ts->pchan),
- ts->flags & TS_F_PDCH_ACTIVE ? "ACTIVE " : "",
- ts->flags & TS_F_PDCH_ACT_PENDING ? "ACT_PENDING " : "",
- ts->flags & TS_F_PDCH_DEACT_PENDING ? "DEACT_PENDING " : "");
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "%s Rx mphConnectCnf flags=%s%s%s\n",
+ gsm_pchan_name(ts->pchan),
+ ts->flags & TS_F_PDCH_ACTIVE ? "ACTIVE " : "",
+ ts->flags & TS_F_PDCH_ACT_PENDING ? "ACT_PENDING " : "",
+ ts->flags & TS_F_PDCH_DEACT_PENDING ? "DEACT_PENDING " : "");
cb_ts_connected(ts, 0);
diff --git a/src/osmo-bts-oc2g/oml_router.c b/src/osmo-bts-oc2g/oml_router.c
deleted file mode 100644
index 198d5e30..00000000
--- a/src/osmo-bts-oc2g/oml_router.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Beginnings of an OML router */
-
-/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
- *
- * Based on sysmoBTS:
- * (C) 2014 by sysmocom s.f.m.c. GmbH
- *
- * 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 "oml_router.h"
-
-#include <osmo-bts/bts.h>
-#include <osmo-bts/logging.h>
-#include <osmo-bts/oml.h>
-#include <osmo-bts/msg_utils.h>
-
-#include <osmocom/core/socket.h>
-#include <osmocom/core/select.h>
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-static int oml_router_read_cb(struct osmo_fd *fd, unsigned int what)
-{
- struct msgb *msg;
- int rc;
-
- msg = oml_msgb_alloc();
- if (!msg) {
- LOGP(DL1C, LOGL_ERROR, "Failed to allocate oml msgb.\n");
- return -1;
- }
-
- rc = recv(fd->fd, msg->tail, msg->data_len, 0);
- if (rc <= 0) {
- close(fd->fd);
- osmo_fd_unregister(fd);
- fd->fd = -1;
- goto err;
- }
-
- msg->l1h = msgb_put(msg, rc);
- rc = msg_verify_ipa_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid IPA message rc(%d)\n", rc);
- goto err;
- }
-
- rc = msg_verify_oml_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid OML message rc(%d)\n", rc);
- goto err;
- }
-
- /* todo dispatch message */
-
-err:
- msgb_free(msg);
- return -1;
-}
-
-static int oml_router_accept_cb(struct osmo_fd *accept_fd, unsigned int what)
-{
- int fd;
- struct osmo_fd *read_fd = (struct osmo_fd *) accept_fd->data;
-
- /* Accept only one connection at a time. De-register it */
- if (read_fd->fd > -1) {
- LOGP(DL1C, LOGL_NOTICE,
- "New OML router connection. Closing old one.\n");
- close(read_fd->fd);
- osmo_fd_unregister(read_fd);
- read_fd->fd = -1;
- }
-
- fd = accept(accept_fd->fd, NULL, NULL);
- if (fd < 0) {
- LOGP(DL1C, LOGL_ERROR, "Failed to accept. errno: %s.\n",
- strerror(errno));
- return -1;
- }
-
- read_fd->fd = fd;
- if (osmo_fd_register(read_fd) != 0) {
- LOGP(DL1C, LOGL_ERROR, "Registering the read fd failed.\n");
- close(fd);
- read_fd->fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-int oml_router_init(struct gsm_bts *bts, const char *path,
- struct osmo_fd *accept_fd, struct osmo_fd *read_fd)
-{
- int rc;
-
- memset(accept_fd, 0, sizeof(*accept_fd));
- memset(read_fd, 0, sizeof(*read_fd));
-
- accept_fd->cb = oml_router_accept_cb;
- accept_fd->data = read_fd;
-
- read_fd->cb = oml_router_read_cb;
- read_fd->data = bts;
- read_fd->when = BSC_FD_READ;
- read_fd->fd = -1;
-
- rc = osmo_sock_unix_init_ofd(accept_fd, SOCK_SEQPACKET, 0,
- path,
- OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK);
- return rc;
-}
diff --git a/src/osmo-bts-oc2g/oml_router.h b/src/osmo-bts-oc2g/oml_router.h
deleted file mode 100644
index 4b22e9c5..00000000
--- a/src/osmo-bts-oc2g/oml_router.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-struct gsm_bts;
-struct osmo_fd;
-
-/**
- * The default path oc2gbts will listen for incoming
- * registrations for OML routing and sending.
- */
-#define OML_ROUTER_PATH "/var/run/oc2gbts_oml_router"
-
-
-int oml_router_init(struct gsm_bts *bts, const char *path, struct osmo_fd *accept, struct osmo_fd *read);
diff --git a/src/osmo-bts-oc2g/tch.c b/src/osmo-bts-oc2g/tch.c
index 1bd93e4b..4ea1eb61 100644
--- a/src/osmo-bts-oc2g/tch.c
+++ b/src/osmo-bts-oc2g/tch.c
@@ -15,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -68,7 +68,7 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
cur = msgb_put(msg, GSM_FR_BYTES);
memcpy(cur, l1_payload, GSM_FR_BYTES);
- lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan);
+ lchan_set_marker(osmo_fr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -101,12 +101,8 @@ static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload,
/* new L1 can deliver bits like we need them */
cur = msgb_put(msg, GSM_EFR_BYTES);
memcpy(cur, l1_payload, GSM_EFR_BYTES);
- enum osmo_amr_type ft;
- enum osmo_amr_quality bfi;
- uint8_t cmr;
- int8_t sti, cmi;
- osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti);
- lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan);
+
+ lchan_set_marker(osmo_efr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -259,7 +255,10 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Efr;
rc = rtppayload_to_l1_efr(l1_payload, rtp_pl,
rtp_pl_len);
- /* FIXME: detect and save EFR SID */
+ if (rc && lchan->ts->trx->bts->dtxd)
+ is_sid = osmo_efr_check_sid(rtp_pl, rtp_pl_len);
+ if (is_sid)
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
break;
case GSM48_CMODE_SPEECH_AMR:
if (use_cache) {
@@ -360,7 +359,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
- uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
+ uint8_t *payload, payload_type, payload_len;
struct msgb *rmsg = NULL;
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
@@ -368,12 +367,12 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
return -EAGAIN;
if (data_ind->msgUnitParam.u8Size < 1) {
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx Payload size 0\n", chan_nr);
/* Push empty payload to upper layers */
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
}
payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -403,6 +402,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (lchan->type != GSM_LCHAN_TCH_H &&
lchan->type != GSM_LCHAN_TCH_F)
goto err_payload_match;
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received ONSET from L1 " "(%d bytes)\n",
+ payload_len);
/* according to 3GPP TS 26.093 ONSET frames precede the first
speech frame of a speech burst - set the marker for next RTP
frame */
@@ -412,43 +413,40 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
case GsmL1_TchPlType_Amr_SidFirstP1:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P1 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstP2:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P2 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->tch.dtx.is_speech_resume = true;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidUpdateInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->tch.dtx.is_speech_resume = true;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_UPDATE_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
default:
- LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "%s Rx Payload Type %s is unsupported\n",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_NOTICE, "%s Rx Payload Type %s is unsupported\n",
+ gsm_lchan_name(lchan), get_value_string(oc2gbts_tch_pl_names, payload_type));
break;
}
- LOGP(DL1P, LOGL_DEBUG, "%s %s lchan->rtp_tx_marker = %s, len=%u\n",
- gsm_lchan_name(lchan),
- get_value_string(oc2gbts_tch_pl_names, payload_type),
- lchan->rtp_tx_marker ? "true" : "false",
- payload_len);
+ LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "%s lchan->rtp_tx_marker = %s, len=%u\n",
+ get_value_string(oc2gbts_tch_pl_names, payload_type),
+ lchan->rtp_tx_marker ? "true" : "false", payload_len);
switch (payload_type) {
case GsmL1_TchPlType_Fr:
@@ -461,27 +459,21 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
rmsg = l1_to_rtppayload_efr(payload, payload_len, lchan);
break;
case GsmL1_TchPlType_Amr:
- rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
- break;
case GsmL1_TchPlType_Amr_SidFirstP1:
- memcpy(sid_first, payload, payload_len);
- int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
- if (len < 0)
- return 0;
- rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
+ rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
break;
}
if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
return 0;
err_payload_match:
- LOGPFN(DL1P, LOGL_ERROR, data_ind->u32Fn, "%s Rx Payload Type %s incompatible with lchan\n",
- gsm_lchan_name(lchan), get_value_string(oc2gbts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_ERROR, "%s Rx Payload Type %s incompatible with lchan\n",
+ gsm_lchan_name(lchan), get_value_string(oc2gbts_tch_pl_names, payload_type));
return -EINVAL;
}
diff --git a/src/osmo-bts-oc2g/utils.c b/src/osmo-bts-oc2g/utils.c
index cb65f45a..f98e88af 100644
--- a/src/osmo-bts-oc2g/utils.c
+++ b/src/osmo-bts-oc2g/utils.c
@@ -16,7 +16,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-octphy/Makefile.am b/src/osmo-bts-octphy/Makefile.am
index 43d9cd7d..fb3f6691 100644
--- a/src/osmo-bts-octphy/Makefile.am
+++ b/src/osmo-bts-octphy/Makefile.am
@@ -1,12 +1,42 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(OCTSDR2G_INCDIR)
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS)
+
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
EXTRA_DIST = l1_if.h l1_oml.h l1_utils.h octphy_hw_api.h octpkt.h
bin_PROGRAMS = osmo-bts-octphy
-COMMON_SOURCES = main.c l1_if.c l1_oml.c l1_utils.c l1_tch.c octphy_hw_api.c octphy_vty.c octpkt.c
+COMMON_SOURCES = \
+ main.c \
+ l1_if.c \
+ l1_oml.c \
+ l1_utils.c \
+ l1_tch.c \
+ octphy_hw_api.c \
+ octphy_vty.c \
+ octpkt.c \
+ $(NULL)
osmo_bts_octphy_SOURCES = $(COMMON_SOURCES)
osmo_bts_octphy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index 612c29ad..074a1a7f 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -36,6 +36,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/socket.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/bts_model.h>
@@ -43,6 +44,8 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/handover.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/nm_common_fsm.h>
#include "l1_if.h"
#include "l1_oml.h"
@@ -307,22 +310,13 @@ 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 gsm_bts_trx *trx, int on)
{
- int i;
if (on) {
/* signal availability */
- 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 (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_DEPENDENCY);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
} else {
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_OFF_LINE);
- oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_OFF_LINE);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
return 0;
@@ -335,7 +329,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
if (ts->flags & TS_F_PDCH_ACTIVE)
return GSM_PCHAN_PDCH;
return GSM_PCHAN_TCH_F;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return ts->dyn.pchan_is;
default:
return ts->pchan;
@@ -350,7 +344,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
enum gsm_phys_chan_config pchan = pick_pchan(ts);
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
switch (sapi) {
case cOCTVC1_GSM_SAPI_ENUM_BCCH:
@@ -485,7 +479,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -595,11 +589,10 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
if (msg) {
nmsg = l1p_msgb_alloc();
if (!nmsg) {
- LOGPFN(DL1C, LOGL_FATAL, u32Fn, "L1SAP PH-TCH.req msg alloc failed\n");
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_FATAL, "L1SAP PH-TCH.req msg alloc failed\n");
return -ENOMEM;
}
- msgb_pull(msg, sizeof(*l1sap));
tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CMD *data_req =
(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CMD *)
msgb_put(nmsg, sizeof(*data_req));
@@ -621,7 +614,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
&data_req->Data.ulPayloadType,
data_req->Data.abyDataContent,
&data_req->Data.ulDataLength,
- msg->data, msg->len);
+ msgb_l2(msg), msgb_l2len(msg));
mOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CMD_SWAP(data_req);
} else {
@@ -775,25 +768,48 @@ int bts_model_init(struct gsm_bts *bts)
bts->variant = BTS_OSMO_OCTPHY;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS;
/* FIXME: what is the nominal transmit power of the PHY/board? */
bts->c0->nominal_power = 15;
- gsm_bts_set_feature(bts, BTS_FEAT_GPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
+ /* order alphabetically */
#if defined(cOCTVC1_GSM_LOGICAL_CHANNEL_COMBINATION_ENUM_FCCH_SCH_BCCH_CCCH_SDCCH4_CBCH_SACCHC4) && defined(cOCTVC1_GSM_LOGICAL_CHANNEL_COMBINATION_ENUM_SDCCH8_CBCH_SACCHC8)
- gsm_bts_set_feature(bts, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
#endif
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
-
- bts_model_vty_init(bts);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = NM_IPAC_F_FREQ_BAND_PGSM
+ | NM_IPAC_F_FREQ_BAND_EGSM
+ | NM_IPAC_F_FREQ_BAND_RGSM
+ | NM_IPAC_F_FREQ_BAND_DCS
+ | NM_IPAC_F_FREQ_BAND_PCS
+ | NM_IPAC_F_FREQ_BAND_850
+ | NM_IPAC_F_FREQ_BAND_480
+ | NM_IPAC_F_FREQ_BAND_450;
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+#if defined(cOCTVC1_GSM_LOGICAL_CHANNEL_COMBINATION_ENUM_FCCH_SCH_BCCH_CCCH_SDCCH4_CBCH_SACCHC4)
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+#endif
+#if defined(cOCTVC1_GSM_LOGICAL_CHANNEL_COMBINATION_ENUM_SDCCH8_CBCH_SACCHC8)
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+#endif
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_F_CHANM_SPEECH_FS
+ | NM_IPAC_F_CHANM_SPEECH_HS;
+
return 0;
}
@@ -906,14 +922,9 @@ static void process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
l1sap_up(trx, &l1sap);
}
-static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m)
-{
- LOGP(DMEAS, ll,
- "Meas: RSSI %d dBm, Burst Timing %d Quarter of bits :%d, "
- "BER Error Count %d , BER Toatal Bit count %d in last decoded frame\n",
- m->sRSSIDbm, m->sBurstTiming, m->sBurstTiming4x, m->usBERCnt,
- m->usBERTotalBitCnt);
-}
+
+#define LOG_FMT_MEAS "Meas: RSSI %d dBm, Burst Timing %d Quarter of bits: %d, BER Error Count %d, BER Toatal Bit count %d in last decoded frame"
+#define LOG_PARAM_MEAS(meas_param) (meas_param)->sRSSIDbm, (meas_param)->sBurstTiming, (meas_param)->sBurstTiming4x, (meas_param)->usBERCnt, (meas_param)->usBERTotalBitCnt
static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn)
{
@@ -938,6 +949,47 @@ static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t
return 0;
}
+/* octv1_gsm_api.h does not have an end marker for CTVC1_GSM_SAPI_ENUM */
+#define _OCTVC1_GSM_SAPI_ENUM_LENGTH (cOCTVC1_GSM_SAPI_ENUM_PRACH + 1)
+
+static const enum l1sap_common_sapi common_sapi_by_oct_sapi[] = {
+ [cOCTVC1_GSM_SAPI_ENUM_IDLE] = L1SAP_COMMON_SAPI_IDLE,
+ [cOCTVC1_GSM_SAPI_ENUM_FCCH] = L1SAP_COMMON_SAPI_FCCH,
+ [cOCTVC1_GSM_SAPI_ENUM_SCH] = L1SAP_COMMON_SAPI_SCH,
+ [cOCTVC1_GSM_SAPI_ENUM_SACCH] = L1SAP_COMMON_SAPI_SACCH,
+ [cOCTVC1_GSM_SAPI_ENUM_SDCCH] = L1SAP_COMMON_SAPI_SDCCH,
+ [cOCTVC1_GSM_SAPI_ENUM_BCCH] = L1SAP_COMMON_SAPI_BCCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PCH_AGCH] = L1SAP_COMMON_SAPI_PCH,
+ [cOCTVC1_GSM_SAPI_ENUM_CBCH] = L1SAP_COMMON_SAPI_CBCH,
+ [cOCTVC1_GSM_SAPI_ENUM_RACH] = L1SAP_COMMON_SAPI_RACH,
+ [cOCTVC1_GSM_SAPI_ENUM_TCHF] = L1SAP_COMMON_SAPI_TCH_F,
+ [cOCTVC1_GSM_SAPI_ENUM_FACCHF] = L1SAP_COMMON_SAPI_FACCH_F,
+ [cOCTVC1_GSM_SAPI_ENUM_TCHH] = L1SAP_COMMON_SAPI_TCH_H,
+ [cOCTVC1_GSM_SAPI_ENUM_FACCHH] = L1SAP_COMMON_SAPI_FACCH_H,
+ [cOCTVC1_GSM_SAPI_ENUM_NCH] = L1SAP_COMMON_SAPI_NCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PDTCH] = L1SAP_COMMON_SAPI_PDTCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PACCH] = L1SAP_COMMON_SAPI_PACCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PBCCH] = L1SAP_COMMON_SAPI_PBCCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PAGCH] = L1SAP_COMMON_SAPI_PAGCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PPCH] = L1SAP_COMMON_SAPI_PPCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PNCH] = L1SAP_COMMON_SAPI_PNCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PTCCH] = L1SAP_COMMON_SAPI_PTCCH,
+ [cOCTVC1_GSM_SAPI_ENUM_PRACH] = L1SAP_COMMON_SAPI_PRACH,
+};
+
+static enum l1sap_common_sapi get_common_sapi(tOCT_UINT8 sapi)
+{
+ if (sapi >= _OCTVC1_GSM_SAPI_ENUM_LENGTH)
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ return common_sapi_by_oct_sapi[sapi];
+}
+
+static void set_log_ctx_sapi(tOCT_UINT8 sapi)
+{
+ l1sap_log_ctx_sapi = get_common_sapi(sapi);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+}
+
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)
@@ -955,7 +1007,9 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1,
struct msgb *resp_msg;
tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CMD *data_req;
- /* Retrive the data */
+ set_log_ctx_sapi(evt->LchId.bySAPI);
+
+ /* Retrieve the data */
fn = evt->ulFrameNumber;
ts_num = (uint8_t) evt->LchId.byTimeslotNb;
sc = (uint8_t) evt->LchId.bySubChannelNb;
@@ -1079,6 +1133,8 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1,
uint8_t ts_num = (uint8_t) data_ind->LchId.byTimeslotNb;
uint8_t sc = (uint8_t) data_ind->LchId.bySubChannelNb;
+ set_log_ctx_sapi(data_ind->LchId.bySAPI);
+
/* Need to combine two 16bit MSB and LSB to form 32bit FN */
fn = data_ind->Data.ulFrameNumber;
@@ -1149,7 +1205,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1,
/* burst timing in 1x but PCU is expecting 4X */
l1sap->u.data.ta_offs_256bits = data_ind->MeasurementInfo.sBurstTiming4x*64;
snr = data_ind->MeasurementInfo.sSNRDb;
- /* FIXME: better converion formulae for SnR -> C / I?
+ /* FIXME: better conversion formulae for SnR -> C / I?
l1sap->u.data.lqual_cb = (snr ? snr : (snr - 65536)) * 10 / 256;
LOGP(DL1C, LOGL_ERROR, "SnR: raw %d, computed %d\n", snr, l1sap->u.data.lqual_cb);
*/
@@ -1171,7 +1227,10 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1,
int rc;
struct ph_rach_ind_param rach_ind_param;
- dump_meas_res(LOGL_DEBUG, &ra_ind->MeasurementInfo);
+ set_log_ctx_sapi(ra_ind->LchId.bySAPI);
+
+ LOGPFN(DL1C, LOGL_DEBUG, ra_ind->ulFrameNumber, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
+ LOG_PARAM_MEAS(&ra_ind->MeasurementInfo));
if (ra_ind->ulMsgLength != 1) {
LOGPFN(DL1C, LOGL_ERROR, ra_ind->ulFrameNumber,
@@ -1267,7 +1326,11 @@ static int retransmit_wlc_upto(struct octphy_hdl *fl1h, uint32_t trans_id)
wlc->num_retrans++;
msg = msgb_copy(wlc->cmd_msg, "PHY CMD Retrans");
msg_set_retrans_flag(msg);
- osmo_wqueue_enqueue(&fl1h->phy_wq, msg);
+ if (osmo_wqueue_enqueue(&fl1h->phy_wq, msg) < 0) {
+ LOGP(DL1C, LOGL_ERROR, "Queue full on wlc retransmit\n");
+ msgb_free(msg);
+ return 0;
+ }
osmo_timer_schedule(&wlc->timer, CMD_TIMEOUT, 0);
count++;
LOGP(DL1C, LOGL_INFO, "Re-transmitting %s "
@@ -1634,7 +1697,7 @@ static int rx_octphy_msg(struct msgb *msg)
}
/* we first need to decode the common OCTPKT header and dispatch
- * based on contrl (command/resp) or data (event=indication) */
+ * based on control (command/resp) or data (event=indication) */
switch (format) {
case cOCTVOCNET_PKT_FORMAT_CTRL:
ctlh = (tOCTVOCNET_PKT_CTL_HEADER *) (msg->l1h + 4);
@@ -1782,10 +1845,7 @@ struct octphy_hdl *l1if_open(struct phy_link *plink)
osmo_wqueue_init(&fl1h->phy_wq, 10);
fl1h->phy_wq.write_cb = octphy_write_cb;
fl1h->phy_wq.read_cb = octphy_read_cb;
- fl1h->phy_wq.bfd.fd = sfd;
- fl1h->phy_wq.bfd.when = BSC_FD_READ;
- fl1h->phy_wq.bfd.cb = osmo_wqueue_bfd_cb;
- fl1h->phy_wq.bfd.data = fl1h;
+ osmo_fd_setup(&fl1h->phy_wq.bfd, sfd, OSMO_FD_READ, osmo_wqueue_bfd_cb, fl1h, 0);
rc = osmo_fd_register(&fl1h->phy_wq.bfd);
if (rc < 0) {
close(sfd);
diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c
index d44f7211..bb519a04 100644
--- a/src/osmo-bts-octphy/l1_oml.c
+++ b/src/osmo-bts-octphy/l1_oml.c
@@ -28,6 +28,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
@@ -38,6 +39,7 @@
#include <osmo-bts/bts.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
#include "l1_if.h"
#include "l1_oml.h"
@@ -54,7 +56,7 @@
bool no_fw_check = 0;
-#define LOGPTRX(byTrxId, level, fmt, args...) \
+#define LOGPOCTTRX(byTrxId, level, fmt, args...) \
LOGP(DL1C, level, "(byTrxId %u) " fmt, byTrxId, ## args)
/* Map OSMOCOM logical channel type to OctPHY Logical channel type */
@@ -185,26 +187,31 @@ extern uint8_t rach_detected_Other_g;
static int opstart_compl(struct gsm_abis_mo *mo)
{
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);
/* TODO: Send NACK in case of error! */
- /* Set to Operational State: Enabled */
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
-
- /* hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
- if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&
- mo->obj_inst.ts_nr == 7) {
- struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
- mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
- LCHAN_REL_ACT_OML;
- lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
- if (cbch) {
- cbch->rel_act_kind = LCHAN_REL_ACT_OML;
- lchan_activate(cbch);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ case NM_OC_CHANNEL:
+ /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
+ if (mo->obj_inst.trx_nr == 0 &&
+ mo->obj_inst.ts_nr == 0) {
+ struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
+ DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
+ mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
+ LCHAN_REL_ACT_OML;
+ lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
+ if (cbch) {
+ cbch->rel_act_kind = LCHAN_REL_ACT_OML;
+ lchan_activate(cbch);
+ }
}
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi,
+ NM_EV_OPSTART_ACK, NULL);
+ default:
+ OSMO_ASSERT(0);
}
-
- /* Send OPSTART ack */
- return oml_mo_opstart_ack(mo);
}
static
@@ -243,7 +250,7 @@ static void clear_amr_params(tOCTVC1_GSM_LOGICAL_CHANNEL_CONFIG * p_Config)
p_Config->abyRate[i] = cOCTVC1_GSM_AMR_CODEC_MODE_ENUM_UNSET;
}
-static void lchan2lch_par(struct gsm_lchan *lchan,
+static int lchan2lch_par(struct gsm_lchan *lchan,
tOCTVC1_GSM_LOGICAL_CHANNEL_CONFIG * p_Config)
{
struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
@@ -252,7 +259,7 @@ static void lchan2lch_par(struct gsm_lchan *lchan,
int j;
LOGP(DL1C, LOGL_INFO, "%s: %s tch_mode=0x%02x\n",
- gsm_lchan_name(lchan), __FUNCTION__, lchan->tch_mode);
+ gsm_lchan_name(lchan), __func__, lchan->tch_mode);
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
@@ -341,11 +348,13 @@ static void lchan2lch_par(struct gsm_lchan *lchan,
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
- LOGP(DL1C, LOGL_ERROR, "%s: CSD not supported!\n",
- gsm_lchan_name(lchan));
- break;
-
+ default:
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Channel mode %s is not supported!\n",
+ gsm48_chan_mode_name(lchan->tch_mode));
+ return -ENOTSUP;
}
+
+ return 0;
}
/***********************************************************************
@@ -381,7 +390,7 @@ static int lchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *d
mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ar);
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during lchan activation\n");
+ LOGPOCTTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during lchan activation\n");
return -EINVAL;
}
@@ -437,6 +446,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
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;
+ int rc;
lac = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD *)
msgb_put(msg, sizeof(*lac));
@@ -449,10 +459,12 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
lac->LchId.bySAPI = cmd->sapi;
lac->LchId.byDirection = cmd->dir;
- lac->Config.byTimingAdvance = lchan->rqd_ta;
+ lac->Config.byTimingAdvance = lchan->ta_ctrl.current;
lac->Config.byBSIC = lchan->ts->trx->bts->bsic;
-
- lchan2lch_par(lchan, &lac->Config);
+ if ((rc = lchan2lch_par(lchan, &lac->Config)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD_SWAP(lac);
@@ -496,7 +508,7 @@ static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *da
trx = trx_by_l1h(fl1, pcr->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(pcr->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during cipher mode activation\n");
+ LOGPOCTTRX(pcr->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during cipher mode activation\n");
return -EINVAL;
}
@@ -506,7 +518,7 @@ static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *da
* sub-channel, only th request contains this information :( */
lchan = &ts->lchan[(unsigned long) data];
- /* TODO: This state machine should be shared accross BTS models? */
+ /* TODO: This state machine should be shared across BTS models? */
switch (lchan->ciph_state) {
case LCHAN_CIPH_RX_REQ:
lchan->ciph_state = LCHAN_CIPH_RX_CONF;
@@ -700,7 +712,7 @@ static int lchan_deact_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void
mOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ldr);
trx = trx_by_l1h(fl1, ldr->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(ldr->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during lchan deactivation\n");
+ LOGPOCTTRX(ldr->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during lchan deactivation\n");
return -EINVAL;
}
@@ -1095,9 +1107,6 @@ int lchan_activate(struct gsm_lchan *lchan)
}
enqueue_sapi_act_cmd(lchan, sapi, dir);
}
-
- lchan_init_lapdm(lchan);
-
return 0;
}
@@ -1107,13 +1116,6 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
return 0;
}
-#define talloc_replace(dst, ctx, src) \
- do { \
- if (dst) \
- talloc_free(dst); \
- dst = talloc_strdup(ctx, (const char *) src); \
- } while (0)
-
static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data)
{
tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *aisr =
@@ -1133,8 +1135,10 @@ static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, voi
LOGP(DL1C, LOGL_INFO, "Note: compiled without multi-trx support.\n");
#endif
- talloc_replace(fl1h->info.system.platform, fl1h, aisr->szPlatform);
- talloc_replace(fl1h->info.system.version, fl1h, aisr->szVersion);
+ osmo_talloc_replace_string(fl1h, &fl1h->info.system.platform,
+ (const char *) aisr->szPlatform);
+ osmo_talloc_replace_string(fl1h, &fl1h->info.system.version,
+ (const char *) aisr->szVersion);
msgb_free(resp);
@@ -1169,7 +1173,7 @@ static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp,
tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air =
(tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h;
- snprintf(ver_hdr, sizeof(ver_hdr), "%02i.%02i.%02i-B%i",
+ snprintf(ver_hdr, sizeof(ver_hdr), "%02d.%02d.%02d-B%d",
cOCTVC1_MAIN_VERSION_MAJOR, cOCTVC1_MAIN_VERSION_MINOR,
cOCTVC1_MAIN_VERSION_MAINTENANCE, cOCTVC1_MAIN_VERSION_BUILD);
@@ -1191,16 +1195,19 @@ static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp,
if (!no_fw_check) {
LOGP(DL1C, LOGL_ERROR,
- "use option -I to override the check (not recommened)\n");
+ "use option -I to override the check (not recommended)\n");
LOGP(DL1C, LOGL_ERROR,
"exiting...\n");
exit(1);
}
}
- talloc_replace(fl1h->info.app.name, fl1h, air->szName);
- talloc_replace(fl1h->info.app.description, fl1h, air->szDescription);
- talloc_replace(fl1h->info.app.version, fl1h, air->szVersion);
+ osmo_talloc_replace_string(fl1h, &fl1h->info.app.name,
+ (const char *) air->szName);
+ osmo_talloc_replace_string(fl1h, &fl1h->info.app.description,
+ (const char *) air->szDescription);
+ osmo_talloc_replace_string(fl1h, &fl1h->info.app.version,
+ (const char *) air->szVersion);
OSMO_ASSERT(strlen(ver_hdr) < sizeof(pinst->version));
osmo_strlcpy(pinst->version, ver_hdr, strlen(ver_hdr));
@@ -1283,7 +1290,7 @@ static int trx_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *d
mOCTVC1_GSM_MSG_TRX_OPEN_RSP_SWAP(or);
trx = trx_by_l1h(fl1h, or->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(or->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during TRX opening procedure -- abort\n");
+ LOGPOCTTRX(or->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during TRX opening procedure -- abort\n");
exit(1);
}
@@ -1340,13 +1347,13 @@ int l1if_trx_open(struct gsm_bts_trx *trx)
}
oc->Config.usBcchArfcn = trx->bts->c0->arfcn;
#endif
- oc->Config.usTsc = trx->bts->bsic & 0x7;
+ oc->Config.usTsc = BTS_TSC(trx->bts);
oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db;
/* FIXME: compute this based on nominal transmit power, etc. */
if (plink->u.octphy.tx_atten_flag) {
oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db;
} else {
- /* Take the Tx Attn received in set radio attribures
+ /* Take the Tx Attn received in set radio attributes
* x4 is for the value in db */
oc->RfConfig.ulTxAttndB = (trx->max_power_red) << 2;
}
@@ -1426,7 +1433,7 @@ static int l1if_over_sample_16x_modif(struct gsm_bts_trx *trx)
}
#endif
-uint32_t trx_get_hlayer1(struct gsm_bts_trx * trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
return 0;
}
@@ -1437,8 +1444,9 @@ static int trx_init(struct gsm_bts_trx *trx)
ARRAY_SIZE(trx_rqd_attr))) {
/* HACK: spec says we need to decline, but openbsc
* doesn't deal with this very well */
- return oml_mo_opstart_ack(&trx->mo);
- /* return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM); */
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ // (void*)(intptr_t)NM_NACK_CANT_PERFORM);
}
l1if_check_app_version(trx);
@@ -1470,7 +1478,7 @@ static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *d
mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar);
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during physical channel activation -- abort\n");
+ LOGPOCTTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during physical channel activation -- abort\n");
exit(1);
}
@@ -1507,8 +1515,7 @@ static int ts_connect_as(struct gsm_bts_trx_ts *ts,
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;
+ tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *oc;
oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD*)
msgb_put(msg, sizeof(*oc));
@@ -1553,7 +1560,7 @@ static int ts_disconnect_cb(struct octphy_hdl *fl1, struct msgb *resp,
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during ts disconnection\n");
+ LOGPOCTTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id during ts disconnection\n");
return -EINVAL;
}
@@ -1581,7 +1588,7 @@ static int ts_connect_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar);
trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
if (!trx) {
- LOGPTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id while connecting ts\n");
+ LOGPOCTTRX(ar->TrxId.byTrxId, LOGL_ERROR, "response with unexpected physical transceiver-id while connecting ts\n");
return -EINVAL;
}
@@ -1678,7 +1685,7 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
bts_model_trx_deact_rf(trx);
/* Close TRX */
- rc = bts_model_trx_close(trx);
+ rc = trx_close(trx);
if (rc != 0) {
LOGP(DL1C, LOGL_ERROR,
"Cannot close TRX %d, it is already closed.\n",
@@ -1716,10 +1723,11 @@ int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
return l1if_activate_rf(trx, 0);
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
/* FIXME: close only one TRX */
- return trx_close(trx);
+ int rc = trx_close(trx);
+ bts_model_trx_close_cb(trx, rc);
}
@@ -1733,41 +1741,46 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
}
/* callback from OML */
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{
- if (kind == NM_OC_RADIO_CARRIER) {
- struct gsm_bts_trx *trx = obj;
- /*struct octphy_hdl *fl1h = trx_octphy_hdl(trx); */
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx;
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ switch (foh->msg_type) {
+ case NM_MT_SET_RADIO_ATTR:
+ trx = obj;
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
+ break;
}
- return oml_fom_ack_nack(msg, 0);
+
+ return 0;
}
/* callback from OML */
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)
{
- int rc = -1;
+ struct gsm_bts_trx* trx;
struct gsm_bts_trx_ts *ts;
+ int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- rc = trx_init(obj);
- break;
- case NM_OC_CHANNEL:
- ts = (struct gsm_bts_trx_ts*) obj;
- rc = ts_connect_as(ts, ts->pchan, pchan_act_compl_cb, NULL);
- break;
- case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
+ case NM_OC_BTS:
case NM_OC_BASEB_TRANSC:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, -1);
- rc = oml_mo_opstart_ack(mo);
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ trx = (struct gsm_bts_trx*) obj;
+ rc = trx_init(trx);
+ break;
+ case NM_OC_CHANNEL:
+ ts = (struct gsm_bts_trx_ts*) obj;
+ rc = ts_connect_as(ts, ts->pchan, pchan_act_compl_cb, NULL);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -1786,8 +1799,7 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
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_DEACTIVATE_PHYSICAL_CHANNEL_CMD *oc =
- (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD *) oc;
+ tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD *oc;
oc = (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD *)
msgb_put(msg, sizeof(*oc));
@@ -1810,7 +1822,7 @@ void bts_model_ts_connect(struct gsm_bts_trx_ts *ts,
{
int rc;
if (as_pchan == GSM_PCHAN_TCH_F_PDCH
- || as_pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ || as_pchan == GSM_PCHAN_OSMO_DYN) {
LOGP(DL1C, LOGL_ERROR,
"%s Requested TS connect as %s,"
" expected a specific pchan instead\n",
diff --git a/src/osmo-bts-octphy/l1_oml.h b/src/osmo-bts-octphy/l1_oml.h
index 4729df5b..3c814c7f 100644
--- a/src/osmo-bts-octphy/l1_oml.h
+++ b/src/osmo-bts-octphy/l1_oml.h
@@ -10,7 +10,7 @@ int l1if_rsl_mode_modify(struct gsm_lchan *lchan);
int l1if_set_ciphering(struct gsm_lchan *lchan, int dir_downlink);
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx);
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx);
int gsm_abis_mo_check_attr(const struct gsm_abis_mo *mo,
const uint8_t * attr_ids, unsigned int num_attr_ids);
diff --git a/src/osmo-bts-octphy/l1_tch.c b/src/osmo-bts-octphy/l1_tch.c
index df0469dd..4b542d11 100644
--- a/src/osmo-bts-octphy/l1_tch.c
+++ b/src/osmo-bts-octphy/l1_tch.c
@@ -146,12 +146,12 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
&trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
if (data_ind->Data.ulDataLength < 1) {
- LOGPFN(DL1P, LOGL_DEBUG, fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
+ LOGPLCFN(lchan, fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx Payload size 0\n", chan_nr);
/* Push empty payload to upper layers */
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr,
data_ind->Data.ulFrameNumber,
- ber10k, lqual_cb);
+ ber10k, lqual_cb, 0, 0, 0);
}
payload_len = data_ind->Data.ulDataLength;
@@ -173,13 +173,13 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
goto err_payload_match;
break;
default:
- LOGPFN(DL1P, LOGL_NOTICE, fn, "%s Rx Payload Type %d is unsupported\n",
- gsm_lchan_name(lchan), payload_type);
+ LOGPLCFN(lchan, fn, DL1P, LOGL_NOTICE, "%s Rx Payload Type %d is unsupported\n",
+ gsm_lchan_name(lchan), payload_type);
break;
}
- LOGPFN(DL1P, LOGL_DEBUG, fn, "%s Rx codec frame (%u): %s\n", gsm_lchan_name(lchan),
- payload_len, osmo_hexdump(payload, payload_len));
+ LOGPLCFN(lchan, fn, DL1P, LOGL_DEBUG, "%s Rx codec frame (%u): %s\n", gsm_lchan_name(lchan), payload_len,
+ osmo_hexdump(payload, payload_len));
switch (payload_type) {
case cOCTVC1_GSM_PAYLOAD_TYPE_ENUM_FULL_RATE:
@@ -201,7 +201,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
rmsg = l1_to_rtppayload_amr(payload, payload_len,
&lchan->tch.amr_mr);
#else
- LOGPFN(DL1P, LOGL_ERROR, fn, "OctPHY only supports FR!\n");
+ LOGPLCFN(lchan, fn, DL1P, LOGL_ERROR, "OctPHY only supports FR!\n");
return -1;
#endif
break;
@@ -210,13 +210,13 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr,
data_ind->Data.ulFrameNumber,
- ber10k, lqual_cb);
+ ber10k, lqual_cb, 0, 0, 0);
return 0;
err_payload_match:
- LOGPFN(DL1P, LOGL_ERROR, fn, "%s Rx Payload Type %d incompatible with lchan\n",
- gsm_lchan_name(lchan), payload_type);
+ LOGPLCFN(lchan, fn, DL1P, LOGL_ERROR, "%s Rx Payload Type %d incompatible with lchan\n",
+ gsm_lchan_name(lchan), payload_type);
return -EINVAL;
}
@@ -241,8 +241,7 @@ void l1if_tch_encode(struct gsm_lchan *lchan, uint32_t *payload_type,
uint8_t *l1_payload;
int rc = -1;
- DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan),
- osmo_hexdump(rtp_pl, rtp_pl_len));
+ LOGPLCHAN(lchan, DRTP, LOGL_DEBUG, "RTP IN: %s\n", osmo_hexdump(rtp_pl, rtp_pl_len));
l1_payload = &data[0];
@@ -271,13 +270,11 @@ void l1if_tch_encode(struct gsm_lchan *lchan, uint32_t *payload_type,
}
if (rc < 0) {
- LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DRTP, LOGL_ERROR, "unable to parse RTP payload\n");
return;
}
*len = rc;
- DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan),
- osmo_hexdump(data, *len));
+ LOGPLCHAN(lchan, DRTP, LOGL_DEBUG, "RTP->L1: %s\n", osmo_hexdump(data, *len));
}
diff --git a/src/osmo-bts-octphy/l1_utils.h b/src/osmo-bts-octphy/l1_utils.h
index d1a87170..1c1d2225 100644
--- a/src/osmo-bts-octphy/l1_utils.h
+++ b/src/osmo-bts-octphy/l1_utils.h
@@ -2,8 +2,8 @@
#include <osmocom/core/utils.h>
-const struct value_string octphy_l1sapi_names[23];
-const struct value_string octphy_dir_names[5];
-const struct value_string octphy_clkmgr_state_vals[8];
-const struct value_string octphy_cid_vals[37];
-const struct value_string octphy_eid_vals[7];
+extern const struct value_string octphy_l1sapi_names[23];
+extern const struct value_string octphy_dir_names[5];
+extern const struct value_string octphy_clkmgr_state_vals[8];
+extern const struct value_string octphy_cid_vals[37];
+extern const struct value_string octphy_eid_vals[7];
diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c
index 928a4c81..56849b55 100644
--- a/src/osmo-bts-octphy/main.c
+++ b/src/osmo-bts-octphy/main.c
@@ -55,7 +55,8 @@ extern bool no_fw_check;
int bts_model_print_help()
{
- printf(" -I --no-fw-check Override firmware version check\n");
+ printf("\nModel specific options:\n");
+ printf(" -I --no-fw-check Override firmware version check\n");
return 0;
}
diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c
index 6da038b1..271ed04f 100644
--- a/src/osmo-bts-octphy/octphy_hw_api.c
+++ b/src/osmo-bts-octphy/octphy_hw_api.c
@@ -119,7 +119,7 @@ static int rf_port_stats_compl_cb(struct octphy_hdl *fl1, struct msgb *resp,
LOGP(DL1C, LOGL_INFO, "RF-PORT-STATS.resp Idx=%u RadioStandard=%s, "
"Rx(Bytes=%u, Overflow=%u, AvgBps=%u, Period=%uus, Freq=%u) "
- "Tx(Bytes=%i, Underflow=%u, AvgBps=%u, Period=%uus, Freq=%u)\n",
+ "Tx(Bytes=%d, Underflow=%u, AvgBps=%u, Period=%uus, Freq=%u)\n",
psr->ulPortIndex,
get_value_string(radio_std_vals, psr->ulRadioStandard),
psr->RxStats.ulRxByteCnt, psr->RxStats.ulRxOverflowCnt,
diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c
index d250a957..308252bb 100644
--- a/src/osmo-bts-octphy/octphy_vty.c
+++ b/src/osmo-bts-octphy/octphy_vty.c
@@ -54,13 +54,11 @@
#define OCT_STR "OCTPHY Um interface\n"
-static struct gsm_bts *vty_bts;
-
/* configuration */
DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd,
"octphy hw-addr HWADDR",
- OCT_STR "Configure the hardware addess of the OCTPHY\n"
+ OCT_STR "Configure the hardware address of the OCTPHY\n"
"hardware address in aa:bb:cc:dd:ee:ff format\n")
{
struct phy_link *plink = vty->index;
@@ -360,7 +358,7 @@ DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd,
return CMD_SUCCESS;
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
if (plink->u.octphy.netdev_name)
vty_out(vty, " octphy net-device %s%s",
@@ -399,15 +397,15 @@ void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
#endif
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
}
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
{
}
-void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
}
@@ -437,10 +435,8 @@ DEFUN(show_sys_info, show_sys_info_cmd,
}
-int bts_model_vty_init(struct gsm_bts *bts)
+int bts_model_vty_init(void *ctx)
{
- vty_bts = bts;
-
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);
diff --git a/src/osmo-bts-octphy/octpkt.c b/src/osmo-bts-octphy/octpkt.c
index d96d93d8..c6aea1f7 100644
--- a/src/osmo-bts-octphy/octpkt.c
+++ b/src/osmo-bts-octphy/octpkt.c
@@ -101,7 +101,7 @@ void octvc1_fill_msg_hdr(tOCTVC1_MSG_HEADER *mh, uint32_t len,
#include <net/ethernet.h>
/*! \brief Initialize a packet socket
- * \param[in] tye Socket type like SOCK_RAW or SOCK_DGRAM
+ * \param[in] type Socket type like SOCK_RAW or SOCK_DGRAM
* \param[in] proto The link-layer protocol in network byte order
* \param[in] bind_dev The name of the interface to bind to (if any)
* \param[in] flags flags like \ref OSMO_SOCK_F_BIND
diff --git a/src/osmo-bts-omldummy/Makefile.am b/src/osmo-bts-omldummy/Makefile.am
index 5a4ce7c5..f7a05047 100644
--- a/src/osmo-bts-omldummy/Makefile.am
+++ b/src/osmo-bts-omldummy/Makefile.am
@@ -1,6 +1,28 @@
-AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS)
+AM_CFLAGS = \
+ -Wall -fno-strict-aliasing \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(LIBGPS_CFLAGS) \
+ $(NULL)
+
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -Iinclude
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) -ldl
+
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ -ldl \
+ $(NULL)
bin_PROGRAMS = osmo-bts-omldummy
diff --git a/src/osmo-bts-omldummy/bts_model.c b/src/osmo-bts-omldummy/bts_model.c
index c0114015..0690d9db 100644
--- a/src/osmo-bts-omldummy/bts_model.c
+++ b/src/osmo-bts-omldummy/bts_model.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -23,6 +23,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/codec/codec.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
@@ -34,6 +35,7 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
/* TODO: check if dummy method is sufficient, else implement */
int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
@@ -50,10 +52,9 @@ int osmo_amr_rtp_dec(const uint8_t *rtppayload, int payload_len, uint8_t *cmr,
return -1;
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
- LOGP(DL1C, LOGL_NOTICE, "Unimplemented %s\n", __func__);
- return 0;
+ bts_model_trx_close_cb(trx, 0);
}
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
@@ -72,18 +73,11 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
static uint8_t vbts_set_bts(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
- uint8_t tn;
llist_for_each_entry(trx, &bts->trx_list, list) {
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
-
- for (tn = 0; tn < TRX_NR_TS; tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
-
/* report availability of trx to the bts. this will trigger the rsl connection */
- oml_mo_tx_sw_act_rep(&trx->mo);
- oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
}
return 0;
}
@@ -99,24 +93,28 @@ static uint8_t vbts_set_ts(struct gsm_bts_trx_ts *ts)
return 0;
}
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- int cause = 0;
+ int rc;
switch (foh->msg_type) {
case NM_MT_SET_BTS_ATTR:
- cause = vbts_set_bts(obj);
+ rc = vbts_set_bts(obj);
break;
case NM_MT_SET_RADIO_ATTR:
- cause = vbts_set_trx(obj);
+ rc = vbts_set_trx(obj);
break;
case NM_MT_SET_CHAN_ATTR:
- cause = vbts_set_ts(obj);
+ rc = vbts_set_ts(obj);
+ break;
+ default:
+ rc = 0;
break;
}
- return oml_fom_ack_nack(msg, cause);
+
+ return rc;
}
/* MO: TS 12.21 Managed Object */
@@ -125,16 +123,15 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)
int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- case NM_OC_CHANNEL:
case NM_OC_SITE_MANAGER:
- case NM_OC_BASEB_TRANSC:
case NM_OC_BTS:
+ case NM_OC_BASEB_TRANSC:
+ case NM_OC_RADIO_CARRIER:
+ case NM_OC_CHANNEL:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
- rc = oml_mo_opstart_ack(mo);
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -151,14 +148,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)
{
- LOGP(DL1C, LOGL_NOTICE, "Unimplemented %s\n", __func__);
return 0;
}
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
{
- LOGP(DL1C, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ power_trx_change_compl(trx, p_trxout_mdBm);
return 0;
}
@@ -168,7 +164,7 @@ int bts_model_ctrl_cmds_install(struct gsm_bts *bts)
return 0;
}
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
return 0;
}
@@ -176,11 +172,20 @@ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
int bts_model_init(struct gsm_bts *bts)
{
bts->variant = BTS_OSMO_OMLDUMMY;
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_BCCH_POWER_RED);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_HOPPING);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VBS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VGCS);
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ struct trx_power_params *tpp = &trx->power_params;
+ /* Speed up shutdown, we don't care about power ramping in omldummy */
+ tpp->ramp.step_interval_sec = 0;
return 0;
}
@@ -220,3 +225,8 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
return 0;
}
+
+int bts_model_phy_link_open(struct phy_link *plink)
+{
+ return 0;
+}
diff --git a/src/osmo-bts-omldummy/main.c b/src/osmo-bts-omldummy/main.c
index 3f1d58c5..167d43a2 100644
--- a/src/osmo-bts-omldummy/main.c
+++ b/src/osmo-bts-omldummy/main.c
@@ -1,35 +1,136 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/application.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/oml.h>
+static void print_usage(const char *prog_name)
+{
+ printf("Usage: %s [-h] [--features FOO,BAR,BAZ] dst_host site_id [trx_num]\n", prog_name);
+}
+
+static void print_help(const char *prog_name)
+{
+ print_usage(prog_name);
+ printf(" -h --help This text.\n");
+ printf(" -f --features FOO,BAR,BAZ BTS features to issue on OML startup.\n"
+ " The names correspond to BTS_FEAT_* constants\n"
+ " as defined in osmocom/gsm/bts_features.h,\n"
+ " e.g. '-f VAMOS'\n");
+}
+
+struct {
+ char *dst_host;
+ int site_id;
+ int trx_num;
+ char *features;
+} cmdline = {
+ .trx_num = 8,
+};
+
+void parse_cmdline(int argc, char **argv)
+{
+ while (1) {
+ int option_index = 0, c;
+ static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"features", 1, 0, 'f'},
+ {0}
+ };
+
+ c = getopt_long(argc, argv, "hf:", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help(argv[0]);
+ exit(0);
+ case 'f':
+ cmdline.features = optarg;
+ break;
+ default:
+ /* catch unknown options *as well as* missing arguments. */
+ fprintf(stderr, "Error in command line options. Exiting.\n");
+ exit(-1);
+ }
+ }
+
+ if (optind + 2 > argc) {
+ print_usage(argv[0]);
+ exit(1);
+ }
+
+ cmdline.dst_host = argv[optind];
+ cmdline.site_id = atoi(argv[optind + 1]);
+ if (optind + 2 < argc)
+ cmdline.trx_num = atoi(argv[optind + 2]);
+
+ if (optind + 3 < argc) {
+ print_usage(argv[0]);
+ exit(1);
+ }
+}
+
+void set_bts_features(struct bitvec *features, char *features_str)
+{
+ char *saveptr = NULL;
+ char *token;
+
+ if (!features_str)
+ return;
+
+ while ((token = strtok_r(features_str, ",", &saveptr))) {
+ enum osmo_bts_features feat;
+ features_str = NULL;
+
+ feat = get_string_value(osmo_bts_features_names, token);
+
+ if ((int)feat < 0) {
+ fprintf(stderr, "Unknown BTS feature: '%s'\n", token);
+ exit(-1);
+ }
+
+ osmo_bts_set_feature(features, feat);
+ }
+}
int main(int argc, char **argv)
{
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
- struct e1inp_line *line;
+ struct bsc_oml_host *bsc_oml_host;
int i;
- char *dst_host = argv[1];
- int site_id = atoi(argv[2]);
+ parse_cmdline(argc, argv);
tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
msgb_talloc_ctx_init(tall_bts_ctx, 10*1024);
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm)
+ exit(1);
+
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (!bts)
exit(1);
- bts->ip_access.site_id = site_id;
+
+ bts->ip_access.site_id = cmdline.site_id;
bts->ip_access.bts_id = 0;
/* Additional TRXs */
- for (i = 1; i < 8; i++) {
+ for (i = 1; i < cmdline.trx_num; i++) {
trx = gsm_bts_trx_alloc(bts);
if (!trx)
exit(1);
@@ -37,13 +138,25 @@ int main(int argc, char **argv)
if (bts_init(bts) < 0)
exit(1);
+
+ set_bts_features(bts->features, cmdline.features);
+
+ /* VAMOS: allocate shadow timeslots for each TRX */
+ if (osmo_bts_has_feature(bts->features, BTS_FEAT_VAMOS)) {
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ gsm_bts_trx_init_shadow_ts(trx);
+ }
+
//btsb = bts_role_bts(bts);
abis_init(bts);
-
- line = abis_open(bts, dst_host, "OMLdummy");
- if (!line)
- exit(2);
+ bsc_oml_host = talloc_zero(bts, struct bsc_oml_host);
+ OSMO_ASSERT(bsc_oml_host);
+ bsc_oml_host->addr = talloc_strdup(bsc_oml_host, cmdline.dst_host);
+ OSMO_ASSERT(bsc_oml_host->addr);
+ llist_add_tail(&bsc_oml_host->list, &bts->bsc_oml_hosts);
+ if (abis_open(bts, "OMLdummy") != 0)
+ exit(1);
while (1) {
osmo_select_main(0);
diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am
index 4901ea3c..12dea3b4 100644
--- a/src/osmo-bts-sysmo/Makefile.am
+++ b/src/osmo-bts-sysmo/Makefile.am
@@ -1,16 +1,62 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(SYSMOBTS_INCDIR)
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS)
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS)
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(LIBGPS_CFLAGS) \
+ $(NULL)
-EXTRA_DIST = misc/sysmobts_mgr.h misc/sysmobts_misc.h misc/sysmobts_par.h \
- misc/sysmobts_eeprom.h misc/sysmobts_nl.h femtobts.h hw_misc.h \
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+EXTRA_DIST = \
+ misc/sysmobts_mgr.h \
+ misc/sysmobts_misc.h \
+ misc/sysmobts_par.h \
+ misc/sysmobts_eeprom.h \
+ misc/sysmobts_nl.h \
misc/sysmobts-layer1.h \
- l1_fwd.h l1_if.h l1_transp.h eeprom.h utils.h oml_router.h
+ femtobts.h \
+ hw_misc.h \
+ l1_fwd.h \
+ l1_if.h \
+ l1_transp.h \
+ eeprom.h \
+ utils.h \
+ $(NULL)
bin_PROGRAMS = osmo-bts-sysmo osmo-bts-sysmo-remote l1fwd-proxy sysmobts-mgr sysmobts-util
-COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c calib_file.c \
- eeprom.c calib_fixup.c utils.c misc/sysmobts_par.c oml_router.c sysmobts_ctrl.c
+COMMON_SOURCES = \
+ main.c \
+ femtobts.c \
+ l1_if.c \
+ oml.c \
+ sysmobts_vty.c \
+ tch.c \
+ hw_misc.c \
+ calib_file.c \
+ eeprom.c \
+ calib_fixup.c \
+ utils.c \
+ misc/sysmobts_par.c \
+ sysmobts_ctrl.c \
+ $(NULL)
+
osmo_bts_sysmo_SOURCES = $(COMMON_SOURCES) l1_transp_hw.c
osmo_bts_sysmo_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
@@ -22,7 +68,7 @@ l1fwd_proxy_SOURCES = l1_fwd_main.c l1_transp_hw.c
l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
if ENABLE_SYSMOBTS_CALIB
-bin_PROGRAMS = sysmobts-calib
+bin_PROGRAMS += sysmobts-calib
sysmobts_calib_SOURCES = misc/sysmobts-calib.c misc/sysmobts-layer1.c
sysmobts_calib_LDADD = -lrt $(COMMON_LDADD)
@@ -37,7 +83,15 @@ sysmobts_mgr_SOURCES = \
misc/sysmobts_mgr_temp.c \
misc/sysmobts_mgr_calib.c \
eeprom.c
-sysmobts_mgr_LDADD = $(LIBGPS_LIBS) $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
+sysmobts_mgr_LDADD = \
+ $(LIBGPS_LIBS) \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(NULL)
-sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c eeprom.c
+sysmobts_util_SOURCES = \
+ misc/sysmobts_util.c \
+ misc/sysmobts_par.c \
+ eeprom.c \
+ $(NULL)
sysmobts_util_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/src/osmo-bts-sysmo/calib_file.c b/src/osmo-bts-sysmo/calib_file.c
index 2f723dd0..bb6cabfd 100644
--- a/src/osmo-bts-sysmo/calib_file.c
+++ b/src/osmo-bts-sysmo/calib_file.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/eeprom.c b/src/osmo-bts-sysmo/eeprom.c
index 472b78e2..6c887d41 100644
--- a/src/osmo-bts-sysmo/eeprom.c
+++ b/src/osmo-bts-sysmo/eeprom.c
@@ -226,12 +226,12 @@ typedef struct
char szSn[16]; ///< Serial number
uint32_t u8Rev : 8; ///< Board revision
- uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknows)
- uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknows)
- uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknows)
+ uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknown)
+ uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknown)
+ uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknown)
uint32_t : 12; ///< unused
} __attribute__((packed)) sysInfo;
@@ -307,12 +307,12 @@ typedef struct
uint32_t u32Time; ///< Epoch time
char szSn[16]; ///< Serial number
uint32_t u8Rev : 8; ///< Board revision
- uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknows)
- uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknows)
- uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknows)
- uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknows)
+ uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknown)
+ uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknown)
+ uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknown)
+ uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknown)
uint32_t : 12; ///< unused
} __attribute__((packed)) sysInfo;
diff --git a/src/osmo-bts-sysmo/femtobts.c b/src/osmo-bts-sysmo/femtobts.c
index 480fe06b..7b02adc5 100644
--- a/src/osmo-bts-sysmo/femtobts.c
+++ b/src/osmo-bts-sysmo/femtobts.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h
index 9163ebbf..b048fc4e 100644
--- a/src/osmo-bts-sysmo/femtobts.h
+++ b/src/osmo-bts-sysmo/femtobts.h
@@ -68,25 +68,25 @@ enum uperfemto_clk_src {
};
#endif
-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];
+extern const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM];
+extern const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1];
+extern 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];
+extern const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM];
+extern const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1];
+extern 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];
+extern const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1];
+extern const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1];
-const struct value_string femtobts_tracef_names[29];
-const struct value_string femtobts_tracef_docs[29];
+extern const struct value_string femtobts_tracef_names[29];
+extern const struct value_string femtobts_tracef_docs[29];
-const struct value_string femtobts_tch_pl_names[15];
-const struct value_string femtobts_chcomb_names[8];
-const struct value_string femtobts_clksrc_names[10];
+extern const struct value_string femtobts_tch_pl_names[15];
+extern const struct value_string femtobts_chcomb_names[8];
+extern const struct value_string femtobts_clksrc_names[10];
-const struct value_string femtobts_dir_names[6];
+extern const struct value_string femtobts_dir_names[6];
enum pdch_cs {
PDCH_CS_1,
@@ -105,6 +105,6 @@ enum pdch_cs {
_NUM_PDCH_CS
};
-const uint8_t pdch_msu_size[_NUM_PDCH_CS];
+extern const uint8_t pdch_msu_size[_NUM_PDCH_CS];
#endif /* FEMTOBTS_H */
diff --git a/src/osmo-bts-sysmo/hw_misc.c b/src/osmo-bts-sysmo/hw_misc.c
index 6aa3b83f..21d8dfdf 100644
--- a/src/osmo-bts-sysmo/hw_misc.c
+++ b/src/osmo-bts-sysmo/hw_misc.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/l1_fwd_main.c b/src/osmo-bts-sysmo/l1_fwd_main.c
index bc9fc21c..76c45e17 100644
--- a/src/osmo-bts-sysmo/l1_fwd_main.c
+++ b/src/osmo-bts-sysmo/l1_fwd_main.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -213,9 +213,7 @@ int main(int argc, char **argv)
wq->write_cb = udp_write_cb;
wq->read_cb = udp_read_cb;
- wq->bfd.when |= BSC_FD_READ;
- wq->bfd.data = l1fh;
- wq->bfd.priv_nr = i;
+ osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, l1fh, i);
rc = osmo_sock_init_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM,
IPPROTO_UDP, NULL, fwd_udp_ports[i],
OSMO_SOCK_F_BIND);
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index df39e2f4..9ca1c323 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -51,6 +51,7 @@
#include <osmo-bts/msg_utils.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <osmo-bts/tx_power.h>
+#include <osmo-bts/nm_common_fsm.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1prim.h>
@@ -343,7 +344,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -391,9 +392,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
sapi = GsmL1_Sapi_Agch;
} else {
- LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
- "chan_nr %d link_id %d\n", l1sap->oph.primitive,
- l1sap->oph.operation, chan_nr, link_id);
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n",
+ l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
msgb_free(l1msg);
return -EINVAL;
}
@@ -454,9 +454,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
msgb_l2len(msg));
}
- LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -466,7 +465,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(l1msg);
} else
dtx_int_signal(lchan);
@@ -504,7 +503,6 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* create new message and fill data */
if (msg) {
- msgb_pull(msg, sizeof(*l1sap));
/* create new message */
nmsg = l1p_msgb_alloc();
if (!nmsg)
@@ -513,7 +511,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
rc = l1if_tch_encode(lchan,
l1p->u.phDataReq.msgUnitParam.u8Buffer,
&l1p->u.phDataReq.msgUnitParam.u8Size,
- msg->data, msg->len, u32Fn, use_cache,
+ msgb_l2(msg), msgb_l2len(msg), u32Fn, use_cache,
l1sap->u.tch.marker);
if (rc < 0) {
/* no data encoded for L1: smth will be generated below */
@@ -550,7 +548,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(nmsg);
return -ENOBUFS;
}
@@ -606,6 +604,15 @@ static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
l1if_rsl_chan_rel(lchan);
break;
+ case PRIM_INFO_ACT_UL_ACC:
+ case PRIM_INFO_DEACT_UL_ACC:
+ chan_nr = l1sap->u.info.u.ulacc_req.chan_nr;
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ if (l1sap->u.info.type == PRIM_INFO_ACT_UL_ACC)
+ l1if_set_ul_acc(lchan, true);
+ else
+ l1if_set_ul_acc(lchan, false);
+ break;
default:
LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n",
l1sap->u.info.type);
@@ -682,7 +689,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
if (ts->flags & TS_F_PDCH_ACTIVE)
return GSM_PCHAN_PDCH;
return GSM_PCHAN_TCH_F;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return ts->dyn.pchan_is;
default:
return ts->pchan;
@@ -696,7 +703,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
uint8_t cbits = 0;
enum gsm_phys_chan_config pchan = pick_pchan(ts);
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
switch (sapi) {
case GsmL1_Sapi_Bcch:
@@ -796,6 +803,45 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
return (cbits << 3) | u8Tn;
}
+static const enum l1sap_common_sapi common_sapi_by_sapi_t[] = {
+ [GsmL1_Sapi_Idle] = L1SAP_COMMON_SAPI_IDLE,
+ [GsmL1_Sapi_Fcch] = L1SAP_COMMON_SAPI_FCCH,
+ [GsmL1_Sapi_Sch] = L1SAP_COMMON_SAPI_SCH,
+ [GsmL1_Sapi_Sacch] = L1SAP_COMMON_SAPI_SACCH,
+ [GsmL1_Sapi_Sdcch] = L1SAP_COMMON_SAPI_SDCCH,
+ [GsmL1_Sapi_Bcch] = L1SAP_COMMON_SAPI_BCCH,
+ [GsmL1_Sapi_Pch] = L1SAP_COMMON_SAPI_PCH,
+ [GsmL1_Sapi_Agch] = L1SAP_COMMON_SAPI_AGCH,
+ [GsmL1_Sapi_Cbch] = L1SAP_COMMON_SAPI_CBCH,
+ [GsmL1_Sapi_Rach] = L1SAP_COMMON_SAPI_RACH,
+ [GsmL1_Sapi_TchF] = L1SAP_COMMON_SAPI_TCH_F,
+ [GsmL1_Sapi_FacchF] = L1SAP_COMMON_SAPI_FACCH_F,
+ [GsmL1_Sapi_TchH] = L1SAP_COMMON_SAPI_TCH_H,
+ [GsmL1_Sapi_FacchH] = L1SAP_COMMON_SAPI_FACCH_H,
+ [GsmL1_Sapi_Nch] = L1SAP_COMMON_SAPI_NCH,
+ [GsmL1_Sapi_Pdtch] = L1SAP_COMMON_SAPI_PDTCH,
+ [GsmL1_Sapi_Pacch] = L1SAP_COMMON_SAPI_PACCH,
+ [GsmL1_Sapi_Pbcch] = L1SAP_COMMON_SAPI_PBCCH,
+ [GsmL1_Sapi_Pagch] = L1SAP_COMMON_SAPI_PAGCH,
+ [GsmL1_Sapi_Ppch] = L1SAP_COMMON_SAPI_PPCH,
+ [GsmL1_Sapi_Pnch] = L1SAP_COMMON_SAPI_PNCH,
+ [GsmL1_Sapi_Ptcch] = L1SAP_COMMON_SAPI_PTCCH,
+ [GsmL1_Sapi_Prach] = L1SAP_COMMON_SAPI_PRACH,
+};
+
+static enum l1sap_common_sapi get_common_sapi(GsmL1_Sapi_t sapi)
+{
+ if (sapi >= GsmL1_Sapi_NUM)
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ return common_sapi_by_sapi_t[sapi];
+}
+
+static void set_log_ctx_sapi(GsmL1_Sapi_t sapi)
+{
+ l1sap_log_ctx_sapi = get_common_sapi(sapi);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+}
+
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
GsmL1_PhReadyToSendInd_t *rts_ind,
struct msgb *l1p_msg)
@@ -812,6 +858,8 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
uint8_t chan_nr, link_id;
uint32_t fn;
+ set_log_ctx_sapi(rts_ind->sapi);
+
/* check if primitive should be handled by common part */
chan_nr = chan_nr_by_sapi(&trx->ts[rts_ind->u8Tn], rts_ind->sapi,
rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
@@ -896,31 +944,8 @@ empty_frame:
goto tx;
}
-static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
-{
- LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, "
- "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality,
- m->fBer, m->i16BurstTiming);
-}
-
-static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
- uint32_t fn, GsmL1_MeasParam_t *m)
-{
- struct osmo_phsap_prim l1sap;
- memset(&l1sap, 0, sizeof(l1sap));
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
- l1sap.u.info.type = PRIM_INFO_MEAS;
- l1sap.u.info.u.meas_ind.chan_nr = chan_nr;
- l1sap.u.info.u.meas_ind.ta_offs_256bits = m->i16BurstTiming * 64;
- l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 10000);
- l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1);
- l1sap.u.info.u.meas_ind.fn = fn;
-
- /* l1sap wants to take msgb ownership. However, as there is no
- * msg, it will msgb_free(l1sap.oph.msg == NULL) */
- return l1sap_up(trx, &l1sap);
-}
+#define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d"
+#define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming
static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind,
struct msgb *l1p_msg)
@@ -933,6 +958,8 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
struct gsm_time g_time;
int rc = 0;
+ set_log_ctx_sapi(data_ind->sapi);
+
chan_nr = chan_nr_by_sapi(&trx->ts[data_ind->u8Tn], data_ind->sapi,
data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn);
if (!chan_nr) {
@@ -944,14 +971,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
fn = data_ind->u32Fn;
link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC;
- process_meas_res(trx, chan_nr, fn, &data_ind->measParam);
-
gsm_fn2gsmtime(&g_time, fn);
- DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
+ DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
get_value_string(femtobts_l1sapi_names, data_ind->sapi), data_ind->hLayer2,
- osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size));
- dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
+ osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
+ LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -962,6 +987,25 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
return rc;
}
+ /* If we got FACCH, the RTP clock needs to account for it,
+ * and if we have rtp continuous-streaming enabled,
+ * an actual BFI packet will be emitted.
+ *
+ * Only the case of TCH/F is currently handled; the task of
+ * supporting TCH/H is left as a FIXME for other/later
+ * developers. The difficulty with supporting FACCH/H is that
+ * only one GsmL1_Sapi_FacchH message will be received,
+ * covering 40 ms of time, but two RTP "tick" output calls
+ * will need to be made, with appropriately adjusted frame
+ * numbers. As a further consideration for rtp continuous-streaming
+ * mode, having the two RTP BFI packets sent directly back to back,
+ * as opposed to proper 20 ms timing, may be so undesirable
+ * that some deployments may rather disable TCH/H (use only TCH/F)
+ * than deal with the extra pain, or use TCH/H only on SDR-based
+ * BTS with osmo-bts-trx where correct timing is easily achieved. */
+ if (data_ind->sapi == GsmL1_Sapi_FacchF)
+ l1if_tch_rx_facch(trx, chan_nr, l1p_msg);
+
/* fill L1SAP header */
sap_msg = l1sap_msgb_alloc(data_ind->msgUnitParam.u8Size);
l1sap = msgb_l1sap_prim(sap_msg);
@@ -971,11 +1015,10 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.fn = fn;
l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi);
- if (!pcu_direct) { /* FIXME: if pcu_direct=1, then this is not set, what to do in pcu_tx_data_ind() in this case ?*/
- l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
- l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64;
- l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
- }
+ l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
+ l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64;
+ l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
+
/* copy data from L1 primitive to L1SAP primitive */
sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size);
memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer,
@@ -996,7 +1039,9 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
int rc;
struct ph_rach_ind_param rach_ind_param;
- dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
+ set_log_ctx_sapi(ra_ind->sapi);
+ LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
+ LOG_PARAM_MEAS(&ra_ind->measParam));
if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) {
@@ -1192,13 +1237,127 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
return l1if_handle_ind(fl1h, msg);
}
+static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
+ struct gsm_lchan *lchan = &ts->lchan[i];
+
+ if (!is_muted)
+ continue;
+
+ if (lchan->state != LCHAN_S_ACTIVE)
+ continue;
+
+ /* skip channels that might be active for another reason */
+ if (lchan->type == GSM_LCHAN_CCCH)
+ continue;
+ if (lchan->type == GSM_LCHAN_PDTCH)
+ continue;
+
+ if (lchan->s <= 0)
+ continue;
+
+ lchan->s = 0;
+ rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
+ }
+}
+
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
+ void *data)
+{
+ struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
+ GsmL1_Status_t status;
+
+ status = sysp->u.muteRfCnf.status;
+
+ if (status != GsmL1_Status_Success) {
+ LOGP(DL1C, LOGL_ERROR, "Rx RF-MUTE.conf with status %s\n",
+ get_value_string(femtobts_l1status_names, status));
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0);
+ } else {
+ int i;
+
+ LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
+ get_value_string(femtobts_l1status_names, status));
+ bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
+
+ osmo_static_assert(
+ ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
+ ts_array_size);
+
+ for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
+ mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
+ }
+
+ msgb_free(resp);
+
+ return 0;
+}
+#endif
+
+/* mute/unmute RF time slots */
+int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
+{
+
+ LOGP(DL1C, LOGL_INFO, "Tx RF-MUTE.req (%d, %d, %d, %d, %d, %d, %d, %d)\n",
+ mute[0], mute[1], mute[2], mute[3],
+ mute[4], mute[5], mute[6], mute[7]
+ );
+
+#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3, 6, 0)
+ const uint8_t unmuted[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct gsm_bts_trx *trx = hdl->phy_inst->trx;
+ int i;
+ LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
+ /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
+ if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
+ bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
+ oml_mo_rf_lock_chg(&trx->mo, mute, 1);
+ for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
+ mute_handle_ts(&trx->ts[i], mute[i]);
+ return 0;
+ }
+ return -ENOTSUP;
+#else
+ struct msgb *msg = sysp_msgb_alloc();
+ SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
+ sysp->id = SuperFemto_PrimId_MuteRfReq;
+ memcpy(sysp->u.muteRfReq.u8Mute, mute, sizeof(sysp->u.muteRfReq.u8Mute));
+ /* save for later use */
+ memcpy(hdl->last_rf_mute, mute, sizeof(hdl->last_rf_mute));
+
+ return l1if_req_compl(hdl, msg, cb ? cb : mute_rf_compl_cb, NULL);
+#endif /* < 3.6.0 */
+}
+
+static int activate_rf_mute_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
+{
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ mute_rf_compl_cb(trx, resp, data);
+#endif
+
+ /* signal availability */
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
+
+ return 0;
+}
+
+int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb);
+
static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
{
SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
GsmL1_Status_t status;
int on = 0;
- unsigned int i;
if (sysp->id == SuperFemto_PrimId_ActivateRfCnf)
on = 1;
@@ -1217,21 +1376,18 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_FATAL, "RF-ACT.conf with status %s\n",
get_value_string(femtobts_l1status_names, status));
bts_shutdown(trx->bts, "RF-ACT failure");
- } else
+ } else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
-
- /* signal availability */
- 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 (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ trx_rf_lock(trx, 1, activate_rf_mute_compl_cb);
+#else
+ activate_rf_mute_compl_cb(trx, resp, NULL);
+#endif
+ }
} else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
- oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
msgb_free(resp);
@@ -1325,104 +1481,6 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on)
return l1if_req_compl(hdl, msg, activate_rf_compl_cb, NULL);
}
-static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
- struct gsm_lchan *lchan = &ts->lchan[i];
-
- if (!is_muted)
- continue;
-
- if (lchan->state != LCHAN_S_ACTIVE)
- continue;
-
- /* skip channels that might be active for another reason */
- if (lchan->type == GSM_LCHAN_CCCH)
- continue;
- if (lchan->type == GSM_LCHAN_PDTCH)
- continue;
-
- if (lchan->s <= 0)
- continue;
-
- lchan->s = 0;
- rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
- }
-}
-
-#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0)
-static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
- void *data)
-{
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
- SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
- GsmL1_Status_t status;
-
- status = sysp->u.muteRfCnf.status;
-
- if (status != GsmL1_Status_Success) {
- LOGP(DL1C, LOGL_ERROR, "Rx RF-MUTE.conf with status %s\n",
- get_value_string(femtobts_l1status_names, status));
- oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0);
- } else {
- int i;
-
- LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
- get_value_string(femtobts_l1status_names, status));
- bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
-
- osmo_static_assert(
- ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
- ts_array_size);
-
- for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
- mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
- }
-
- msgb_free(resp);
-
- return 0;
-}
-#endif
-
-/* mute/unmute RF time slots */
-int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
-{
-
- LOGP(DL1C, LOGL_INFO, "Tx RF-MUTE.req (%d, %d, %d, %d, %d, %d, %d, %d)\n",
- mute[0], mute[1], mute[2], mute[3],
- mute[4], mute[5], mute[6], mute[7]
- );
-
-#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3,6,0)
- const uint8_t unmuted[8] = { 0,0,0,0,0,0,0,0 };
- struct gsm_bts_trx *trx = hdl->phy_inst->trx;
- int i;
- LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
- /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
- if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
- bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, mute, 1);
- for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
- mute_handle_ts(&trx->ts[i], mute[i]);
- return 0;
- }
- return -ENOTSUP;
-#else
- struct msgb *msg = sysp_msgb_alloc();
- SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
- sysp->id = SuperFemto_PrimId_MuteRfReq;
- memcpy(sysp->u.muteRfReq.u8Mute, mute, sizeof(sysp->u.muteRfReq.u8Mute));
- /* save for later use */
- memcpy(hdl->last_rf_mute, mute, sizeof(hdl->last_rf_mute));
-
- return l1if_req_compl(hdl, msg, cb ? cb : mute_rf_compl_cb, NULL);
-#endif /* < 3.6.0 */
-}
-
/* call-back on arrival of DSP+FPGA version + band capability */
static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
@@ -1444,10 +1502,12 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
fl1h->hw_info.ver_minor = sic->boardVersion.option;
#endif
- LOGP(DL1C, LOGL_INFO, "DSP v%u.%u.%u, FPGA v%u.%u.%u\nn",
- sic->dspVersion.major, sic->dspVersion.minor,
- sic->dspVersion.build, sic->fpgaVersion.major,
- sic->fpgaVersion.minor, sic->fpgaVersion.build);
+ snprintf(trx->pinst->version, sizeof(trx->pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
+ fl1h->hw_info.ver_major, fl1h->hw_info.ver_minor,
+ fl1h->hw_info.dsp_version[0], fl1h->hw_info.dsp_version[1], fl1h->hw_info.dsp_version[2],
+ fl1h->hw_info.fpga_version[0], fl1h->hw_info.fpga_version[1], fl1h->hw_info.fpga_version[2]);
+
+ LOGP(DL1C, LOGL_INFO, "%s\n", trx->pinst->version);
#ifdef HW_SYSMOBTS_V1
if (sic->rfBand.gsm850)
@@ -1483,6 +1543,8 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
msgb_free(resp);
+ phy_link_state_set(trx->pinst->phy_link, PHY_LINK_CONNECTED);
+
/* FIXME: clock related */
return 0;
}
@@ -1846,7 +1908,8 @@ static void fill_trx_power_params(struct gsm_bts_trx *trx,
LOGP(DL1C, LOGL_NOTICE, "Assuming 1002 for sysmoBTS "
"Model number %u\n", fl1h->hw_info.model_nr);
/* fall-through */
- case 1002:
+ case 1002: /* sysmoBTS 1002 */
+ case 1003: /* sysmoBTS 1002 with GPS and PoE */
set_power_param(&trx->power_params, 23, 0);
}
}
@@ -1883,12 +1946,28 @@ int bts_model_phy_link_open(struct phy_link *plink)
hdl = pinst->u.sysmobts.hdl;
osmo_strlcpy(bts->sub_model, sysmobts_model(hdl->hw_info.model_nr, hdl->hw_info.trx_nr), sizeof(bts->sub_model));
- snprintf(pinst->version, sizeof(pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
- hdl->hw_info.ver_major, hdl->hw_info.ver_minor,
- hdl->hw_info.dsp_version[0], hdl->hw_info.dsp_version[1], hdl->hw_info.dsp_version[2],
- hdl->hw_info.fpga_version[0], hdl->hw_info.fpga_version[1], hdl->hw_info.fpga_version[2]);
- phy_link_state_set(plink, PHY_LINK_CONNECTED);
+ /* Frequency bands indicated to the BSC */
+ for (unsigned int i = 0; i < sizeof(hdl->hw_info.band_support) * 8; i++) {
+ if (~hdl->hw_info.band_support & (1 << i))
+ continue;
+ switch (1 << i) {
+ case GSM_BAND_850:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
+ break;
+ case GSM_BAND_900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
+ break;
+ case GSM_BAND_1800:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
+ break;
+ case GSM_BAND_1900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
+ break;
+ }
+ }
return 0;
}
diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h
index 1b214be7..c81b6bd4 100644
--- a/src/osmo-bts-sysmo/l1_if.h
+++ b/src/osmo-bts-sysmo/l1_if.h
@@ -129,6 +129,8 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn,
bool use_cache, bool marker);
int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg);
+int l1if_tch_rx_facch(struct gsm_bts_trx *trx, uint8_t chan_nr,
+ 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, uint32_t fn);
@@ -143,6 +145,7 @@ int l1if_rsl_chan_rel(struct gsm_lchan *lchan);
int l1if_rsl_chan_mod(struct gsm_lchan *lchan);
int l1if_rsl_deact_sacch(struct gsm_lchan *lchan);
int l1if_rsl_mode_modify(struct gsm_lchan *lchan);
+int l1if_set_ul_acc(struct gsm_lchan *lchan, bool active);
/* calibration loading */
int calib_load(struct femtol1_hdl *fl1h);
@@ -156,9 +159,9 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h);
int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h,
struct msgb *msg, struct gsm_lchan *lchan);
-static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx)
+static inline struct femtol1_hdl *trx_femtol1_hdl(const struct gsm_bts_trx *trx)
{
- struct phy_instance *pinst = trx_phy_instance(trx);
+ const struct phy_instance *pinst = trx_phy_instance(trx);
OSMO_ASSERT(pinst);
return pinst->u.sysmobts.hdl;
}
diff --git a/src/osmo-bts-sysmo/l1_transp_fwd.c b/src/osmo-bts-sysmo/l1_transp_fwd.c
index 87c230bb..ac510eda 100644
--- a/src/osmo-bts-sysmo/l1_transp_fwd.c
+++ b/src/osmo-bts-sysmo/l1_transp_fwd.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -126,10 +126,7 @@ int l1if_transport_open(int q, struct femtol1_hdl *fl1h)
wq->write_cb = prim_write_cb;
wq->read_cb = fwd_read_cb;
- ofd->data = fl1h;
- ofd->priv_nr = q;
- ofd->when |= BSC_FD_READ;
-
+ osmo_fd_setup(ofd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, fl1h, q);
rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
bts_host, fwd_udp_ports[q],
OSMO_SOCK_F_CONNECT);
diff --git a/src/osmo-bts-sysmo/l1_transp_hw.c b/src/osmo-bts-sysmo/l1_transp_hw.c
index 01bc2005..cfbc77c9 100644
--- a/src/osmo-bts-sysmo/l1_transp_hw.c
+++ b/src/osmo-bts-sysmo/l1_transp_hw.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -95,18 +95,18 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
queue = container_of(fd, struct osmo_wqueue, bfd);
- if (what & BSC_FD_READ)
+ if (what & OSMO_FD_READ)
queue->read_cb(fd);
- if (what & BSC_FD_EXCEPT)
+ if (what & OSMO_FD_EXCEPT)
queue->except_cb(fd);
- if (what & BSC_FD_WRITE) {
+ if (what & OSMO_FD_WRITE) {
struct iovec iov[5];
struct msgb *msg, *tmp;
int written, count = 0;
- fd->when &= ~BSC_FD_WRITE;
+ osmo_fd_write_disable(fd);
llist_for_each_entry(msg, &queue->msg_queue, list) {
/* more writes than we have */
@@ -124,7 +124,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
/* Nothing scheduled? This should not happen. */
if (count == 0) {
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -132,7 +132,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
if (written < 0) {
/* nothing written?! */
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
return 0;
}
@@ -151,7 +151,7 @@ static int wqueue_vector_cb(struct osmo_fd *fd, unsigned int what)
}
if (!llist_empty(&queue->msg_queue))
- fd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(fd);
}
return 0;
@@ -271,11 +271,7 @@ int l1if_transport_open(int q, struct femtol1_hdl *hdl)
q, rd_devnames[q], 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;
+ osmo_fd_setup(read_ofd, rc, OSMO_FD_READ, l1if_fd_cb, hdl, q);
rc = osmo_fd_register(read_ofd);
if (rc < 0) {
close(read_ofd->fd);
@@ -291,11 +287,7 @@ int l1if_transport_open(int q, struct femtol1_hdl *hdl)
}
osmo_wqueue_init(wq, 10);
wq->write_cb = l1fd_write_cb;
- write_ofd->cb = wqueue_vector_cb;
- write_ofd->fd = rc;
- write_ofd->priv_nr = q;
- write_ofd->data = hdl;
- write_ofd->when = BSC_FD_WRITE;
+ osmo_fd_setup(write_ofd, rc, OSMO_FD_WRITE, wqueue_vector_cb, hdl, q);
rc = osmo_fd_register(write_ofd);
if (rc < 0) {
close(write_ofd->fd);
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c
index ad7118ae..20b425da 100644
--- a/src/osmo-bts-sysmo/main.c
+++ b/src/osmo-bts-sysmo/main.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -53,47 +53,61 @@
#include "eeprom.h"
#include "l1_if.h"
#include "hw_misc.h"
-#include "oml_router.h"
int bts_model_init(struct gsm_bts *bts)
{
struct stat st;
- static struct osmo_fd accept_fd, read_fd;
- int rc;
bts->variant = BTS_OSMO_SYSMO;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
-
- rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd);
- if (rc < 0) {
- fprintf(stderr, "Error creating the OML router: %s rc=%d\n",
- OML_ROUTER_PATH, rc);
- exit(1);
- }
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
+ | NM_IPAC_MASK_GPRS_CODING_MCS;
if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) {
LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n");
exit(23);
}
- gsm_bts_set_feature(bts, BTS_FEAT_CBCH);
- gsm_bts_set_feature(bts, BTS_FEAT_GPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_EGPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
- gsm_bts_set_feature(bts, BTS_FEAT_AGCH_PCH_PROP);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_EFR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
-
- bts_model_vty_init(bts);
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_AGCH_PCH_PROP);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_EFR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VBS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VGCS);
+
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB);
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP);
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER);
+
+ /* The default HR codec output format in the absence of saved
+ * vty config needs to match what was implemented previously,
+ * for the sake of existing deployments, i.e., to avoid
+ * a surprise functional change upon software update. */
+ bts->emit_hr_rfc5993 = false;
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = 0x00; /* updated in bts_model_phy_link_open() */
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH;
+
return 0;
}
@@ -128,10 +142,10 @@ void bts_update_status(enum bts_global_status which, int on)
void bts_model_print_help()
{
- printf(
- " -w --hw-version Print the targeted HW Version\n"
- " -M --pcu-direct Force PCU to access message queue for "
- "PDCH dchannel directly\n"
+ printf( "\nModel specific options:\n"
+ " -w --hw-version Print the targeted HW Version\n"
+ " -M --pcu-direct Force PCU to access message queue for "
+ "PDCH dchannel directly\n"
);
};
diff --git a/src/osmo-bts-sysmo/misc/sysmobts-layer1.c b/src/osmo-bts-sysmo/misc/sysmobts-layer1.c
index 4b34f50e..20ca6f51 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts-layer1.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts-layer1.c
@@ -622,7 +622,7 @@ int set_clock_cor(int clock_cor, int calib, int source)
return -1;
}
if (prim.u.rfClockSetupCnf.status != GsmL1_Status_Success) {
- printf("Clock setup was not successfull.\n");
+ printf("Clock setup was not successful.\n");
return -2;
}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h
index b7a27fb7..9c2b839a 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h
@@ -32,6 +32,7 @@ struct sysmobts_eeprom { /* offset */
enum sysmobts_model_number {
MODEL_SYSMOBTS_1002 = 1002,
+ MODEL_SYSMOBTS_1003 = 1003,
MODEL_SYSMOBTS_1020 = 1020,
MODEL_SYSMOBTS_2050 = 2050,
};
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
index a8289c25..79bbf77e 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -192,11 +192,11 @@ static int parse_options(int argc, char **argv)
return 0;
}
-static void signal_handler(int signal)
+static void signal_handler(int signum)
{
- fprintf(stderr, "signal %u received\n", signal);
+ fprintf(stderr, "signal %u received\n", signum);
- switch (signal) {
+ switch (signum) {
case SIGINT:
case SIGTERM:
sysmobts_check_temp(no_eeprom_write);
@@ -204,6 +204,16 @@ static void signal_handler(int signal)
exit(0);
break;
case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report and
+ * then run default SIGABRT handler, who will generate coredump
+ * and abort the process. abort() should do this for us after we
+ * return, but program wouldn't exit if an external SIGABRT is
+ * received.
+ */
+ talloc_report_full(tall_mgr_ctx, stderr);
+ signal(SIGABRT, SIG_DFL);
+ raise(SIGABRT);
+ break;
case SIGUSR1:
case SIGUSR2:
talloc_report_full(tall_mgr_ctx, stderr);
@@ -218,25 +228,25 @@ static struct log_info_cat mgr_log_info_cat[] = {
.name = "DTEMP",
.description = "Temperature monitoring",
.color = "\033[1;35m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFW] = {
.name = "DFW",
.description = "DSP/FPGA firmware management",
.color = "\033[1;36m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DFIND] = {
.name = "DFIND",
.description = "ipaccess-find handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
[DCALIB] = {
.name = "DCALIB",
.description = "Calibration handling",
.color = "\033[1;37m",
- .enabled = 1, .loglevel = LOGL_INFO,
+ .enabled = 1, .loglevel = LOGL_NOTICE,
},
};
@@ -262,6 +272,7 @@ int main(int argc, char **argv)
osmo_init_ignore_signals();
signal(SIGINT, &signal_handler);
signal(SIGTERM, &signal_handler);
+ signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
@@ -277,7 +288,7 @@ int main(int argc, char **argv)
exit(1);
}
- rc = telnet_init(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
+ rc = telnet_init_default(tall_mgr_ctx, NULL, OSMO_VTY_PORT_BTSMGR);
if (rc < 0) {
fprintf(stderr, "Error initializing telnet\n");
exit(1);
@@ -312,10 +323,10 @@ int main(int argc, char **argv)
LOGP(DLCTRL, LOGL_ERROR, "Can't connect to CTRL @ localhost:%u\n",
OSMO_CTRL_PORT_BTS);
else
- LOGP(DLCTRL, LOGL_NOTICE, "CTRL connected to locahost:%u\n",
+ LOGP(DLCTRL, LOGL_NOTICE, "CTRL connected to localhost:%u\n",
OSMO_CTRL_PORT_BTS);
- sysmobts_mgr_temp_init(&manager, ccon);
+ sysmobts_mgr_temp_init(&manager, ccon);
if (sysmobts_mgr_calib_init(&manager) != 0)
exit(3);
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
index 12961e3f..45b024e1 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_calib.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_calib.c
index a0ba6493..ac35f392 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_calib.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_calib.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -54,7 +54,7 @@ enum calib_result {
CALIB_FAIL_START,
CALIB_FAIL_GPS,
CALIB_FAIL_CTRL,
- CALIB_SUCESS,
+ CALIB_SUCCESS,
};
static inline int compat_gps_read(struct gps_data_t *data)
@@ -167,10 +167,8 @@ static void mgr_gps_open(struct sysmobts_mgr_instance *mgr)
#else
gps_stream(mgr->calib.gpsdata, WATCH_ENABLE, NULL);
#endif
- mgr->calib.gpsfd.data = mgr;
- mgr->calib.gpsfd.cb = mgr_gps_read;
- mgr->calib.gpsfd.when = BSC_FD_READ | BSC_FD_EXCEPT;
- mgr->calib.gpsfd.fd = mgr->calib.gpsdata->gps_fd;
+ osmo_fd_setup(&mgr->calib.gpsfd, mgr->calib.gpsdata->gps_fd, OSMO_FD_READ | OSMO_FD_EXCEPT,
+ mgr_gps_read, mgr, 0);
if (osmo_fd_register(&mgr->calib.gpsfd) < 0) {
LOGP(DCALIB, LOGL_ERROR, "Failed to register GPSD fd\n");
calib_state_reset(mgr, CALIB_FAIL_GPS);
@@ -271,7 +269,7 @@ static void calib_state_reset(struct sysmobts_mgr_instance *mgr, int outcome)
* and in case of a failure in some minutes.
*/
int timeout = 2 * 60 * 60;
- if (outcome != CALIB_SUCESS)
+ if (outcome != CALIB_SUCCESS)
timeout = 5 * 60;
mgr->calib.calib_timeout.data = mgr;
@@ -390,7 +388,7 @@ static void handle_ctrl_set_cor(
LOGP(DCALIB, LOGL_NOTICE,
"Calibration process completed\n");
- calib_state_reset(mgr, CALIB_SUCESS);
+ calib_state_reset(mgr, CALIB_SUCCESS);
}
static void handle_ctrl(struct sysmobts_mgr_instance *mgr, struct msgb *msg)
@@ -459,7 +457,7 @@ static void bts_recon_timer_cb(void *data)
struct sysmobts_mgr_instance *mgr = data;
/* The connection failures are to be expected during boot */
- mgr->calib.bts_conn->ofd->when |= BSC_FD_WRITE;
+ osmo_fd_write_enable(mgr->calib.bts_conn->ofd);
rc = ipa_client_conn_open(mgr->calib.bts_conn);
if (rc < 0) {
LOGP(DLCTRL, LOGL_NOTICE, "Failed to connect to BTS.\n");
@@ -543,8 +541,8 @@ int sysmobts_mgr_calib_init(struct sysmobts_mgr_instance *mgr)
return 0;
}
- mgr->calib.bts_conn = ipa_client_conn_create(tall_mgr_ctx, NULL, 0,
- "localhost", 4238,
+ mgr->calib.bts_conn = ipa_client_conn_create2(tall_mgr_ctx, NULL, 0,
+ NULL, 0, "localhost", 4238,
bts_updown_cb, bts_read_cb,
NULL, mgr);
if (!mgr->calib.bts_conn) {
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c
index 48a03124..fead4f27 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c
index 1be56ac2..eea68793 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -233,7 +233,7 @@ static void sysmobts_mgr_temp_handle(struct sysmobts_mgr_instance *manager,
rep->variable = "oml-alert";
rep->value = oml_alert;
LOGP(DTEMP, LOGL_ERROR, "OML alert sent: %d\n",
- ctrl_cmd_send(&ctrl->write_queue, rep));
+ ctrl_cmd_send2(ctrl, rep));
talloc_free(rep);
}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
index 444ee7c3..33cf0dcb 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -69,28 +69,10 @@ static int go_to_parent(struct vty *vty)
return vty->node;
}
-static int is_config_node(struct vty *vty, int node)
-{
- switch (node) {
- case MGR_NODE:
- case ACT_NORM_NODE:
- case ACT_WARN_NODE:
- case ACT_CRIT_NODE:
- case LIMIT_RF_NODE:
- case LIMIT_DIGITAL_NODE:
- case LIMIT_BOARD_NODE:
- case LIMIT_PA_NODE:
- return 1;
- default:
- return 0;
- }
-}
-
static struct vty_app_info vty_info = {
.name = "sysmobts-mgr",
.version = PACKAGE_VERSION,
.go_parent_cb = go_to_parent,
- .is_config_node = is_config_node,
.copyright = copyright,
};
@@ -380,11 +362,11 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
vty_out(vty, "Temperature control state: %s%s",
sysmobts_mgr_temp_get_state(s_mgr->state), VTY_NEWLINE);
vty_out(vty, "Current Temperatures%s", VTY_NEWLINE);
- vty_out(vty, " Digital: %f Celcius%s",
+ vty_out(vty, " Digital: %f Celsius%s",
sysmobts_temp_get(SYSMOBTS_TEMP_DIGITAL,
SYSMOBTS_TEMP_INPUT) / 1000.0f,
VTY_NEWLINE);
- vty_out(vty, " RF: %f Celcius%s",
+ vty_out(vty, " RF: %f Celsius%s",
sysmobts_temp_get(SYSMOBTS_TEMP_RF,
SYSMOBTS_TEMP_INPUT) / 1000.0f,
VTY_NEWLINE);
@@ -396,8 +378,8 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
is_sbts2050_master() ? "master" : "slave", VTY_NEWLINE);
sbts2050_uc_check_temp(&temp_pa, &temp_board);
- vty_out(vty, " sysmoBTS 2050 PA: %d Celcius%s", temp_pa, VTY_NEWLINE);
- vty_out(vty, " sysmoBTS 2050 PA: %d Celcius%s", temp_board, VTY_NEWLINE);
+ vty_out(vty, " sysmoBTS 2050 PA: %d Celsius%s", temp_pa, VTY_NEWLINE);
+ vty_out(vty, " sysmoBTS 2050 PA: %d Celsius%s", temp_board, VTY_NEWLINE);
sbts2050_uc_get_status(&status);
vty_out(vty, "Power Status%s", VTY_NEWLINE);
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
index d996d644..b391ce66 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -46,7 +46,7 @@
* Temperature handling
*********************************************************************/
-#define TEMP_PATH "/sys/class/hwmon/hwmon0/device/temp%u_%s"
+#define TEMP_PATH "/sys/class/hwmon/hwmon0/device/hwmon/hwmon0/temp%u_%s"
static const char *temp_type_str[_NUM_TEMP_TYPES] = {
[SYSMOBTS_TEMP_INPUT] = "input",
@@ -234,14 +234,14 @@ int sysmobts_firmware_reload(enum sysmobts_firmware_type type)
fd_in = open(name, O_RDONLY);
if (fd_in < 0) {
- LOGP(DFW, LOGL_ERROR, "unable ot open firmware file %s: %s\n",
+ LOGP(DFW, LOGL_ERROR, "unable to open firmware file %s: %s\n",
name, strerror(errno));
return fd_in;
}
fd_out = open(fw_devs[type], O_WRONLY);
if (fd_out < 0) {
- LOGP(DFW, LOGL_ERROR, "unable ot open firmware device %s: %s\n",
+ LOGP(DFW, LOGL_ERROR, "unable to open firmware device %s: %s\n",
fw_devs[type], strerror(errno));
close(fd_in);
return fd_out;
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_nl.c b/src/osmo-bts-sysmo/misc/sysmobts_nl.c
index 67aa6636..5a937dcb 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_nl.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_nl.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_nl.h b/src/osmo-bts-sysmo/misc/sysmobts_nl.h
index 84f4d9cc..5dda4679 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_nl.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_nl.h
@@ -11,7 +11,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_par.c b/src/osmo-bts-sysmo/misc/sysmobts_par.c
index de81fff5..0e8685f3 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_par.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_par.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -341,6 +341,8 @@ char *sysmobts_model(int bts_type, int trx_num)
case 0xffff:
case 1002:
return "sysmoBTS 1002";
+ case 1003:
+ return "sysmoBTS 1002+GPS+PoE";
case 2050:
switch(trx_num) {
case 0:
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_util.c b/src/osmo-bts-sysmo/misc/sysmobts_util.c
index c9930d8f..bd751431 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_util.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_util.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index ea7527dd..b4f6752d 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -11,7 +11,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -23,6 +23,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
#include <sysmocom/femtobts/gsml1prim.h>
#include <sysmocom/femtobts/gsml1const.h>
@@ -39,11 +40,14 @@
#include <osmo-bts/phy_link.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
#include "l1_if.h"
#include "femtobts.h"
#include "utils.h"
+static void dump_lch_par(int logl, GsmL1_LogChParam_t *lch_par, GsmL1_Sapi_t sapi);
+
static int mph_info_chan_confirm(struct gsm_lchan *lchan,
enum osmo_mph_info_type type, uint8_t cause)
{
@@ -88,13 +92,13 @@ static const enum GsmL1_LogChComb_t pchan_to_logChComb[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_PDCH] = GsmL1_LogChComb_XIII,
[GSM_PCHAN_UNKNOWN] = GsmL1_LogChComb_0,
/*
- * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be
+ * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_OSMO_DYN should not be
* part of this, only "real" pchan values will be looked up here.
* See the callers of ts_connect_as().
*/
};
-static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb);
+int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb);
static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct femtol1_hdl *gl1,
HANDLE hLayer3)
@@ -267,36 +271,48 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);
GsmL1_Status_t status = prim_status(l1p);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);
if (status != GsmL1_Status_Success) {
LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",
get_value_string(femtobts_l1prim_names, l1p->id),
get_value_string(femtobts_l1status_names, status));
msgb_free(l1_msg);
- return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ case NM_OC_CHANNEL:
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
+ default:
+ OSMO_ASSERT(0);
+ }
}
msgb_free(l1_msg);
-
- /* Set to Operational State: Enabled */
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
-
- /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
- if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&
- mo->obj_inst.ts_nr == 0) {
- struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
- DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
- mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
- LCHAN_REL_ACT_OML;
- lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
- if (cbch) {
- cbch->rel_act_kind = LCHAN_REL_ACT_OML;
- lchan_activate(cbch);
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ case NM_OC_CHANNEL:
+ /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */
+ if (mo->obj_inst.trx_nr == 0 &&
+ mo->obj_inst.ts_nr == 0) {
+ struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);
+ DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
+ mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
+ LCHAN_REL_ACT_OML;
+ lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);
+ if (cbch) {
+ cbch->rel_act_kind = LCHAN_REL_ACT_OML;
+ lchan_activate(cbch);
+ }
}
+ return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].mo.fi,
+ NM_EV_OPSTART_ACK, NULL);
+ default:
+ OSMO_ASSERT(0);
}
-
- /* Send OPSTART ack */
- return oml_mo_opstart_ack(mo);
}
static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
@@ -325,6 +341,8 @@ static int trx_mute_on_init_cb(struct gsm_bts_trx *trx, struct msgb *resp,
bts_shutdown(trx->bts, "RF-MUTE failure");
}
+ bts_update_status(BTS_STATUS_RF_MUTE, 1);
+
msgb_free(resp);
return 0;
@@ -358,7 +376,7 @@ static int trx_init_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
#endif
/* Begin to ramp up the power */
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
return opstart_compl(&trx->mo, l1_msg);
}
@@ -394,8 +412,9 @@ static int trx_init(struct gsm_bts_trx *trx)
ARRAY_SIZE(trx_rqd_attr))) {
/* HACK: spec says we need to decline, but openbsc
* doesn't deal with this very well */
- return oml_mo_opstart_ack(&trx->mo);
- //return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
+ //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ // (void*)(intptr_t)NM_NACK_CANT_PERFORM);
}
femto_band = sysmobts_select_femto_band(trx, trx->arfcn);
@@ -412,9 +431,16 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->freqBand = femto_band;
dev_par->u16Arfcn = trx->arfcn;
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
- dev_par->u8NbTsc = trx->bts->bsic & 7;
- dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
- ? 0.0 : trx->bts->ul_power_target;
+ dev_par->u8NbTsc = BTS_TSC(trx->bts);
+
+ if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+ /* Target is in the middle between lower and upper RxLev thresholds */
+ int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+ int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+ dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+ } else {
+ dev_par->fRxPowerLevel = 0.0;
+ }
dev_par->fTxPowerLevel = ((float) initial_mdBm) / 1000;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
@@ -426,9 +452,9 @@ static int trx_init(struct gsm_bts_trx *trx)
return l1if_gsm_req_compl(fl1h, msg, trx_init_compl_cb, NULL);
}
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ const struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
return fl1h->hLayer1;
}
@@ -437,23 +463,27 @@ static int trx_close_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
void *data)
{
msgb_free(l1_msg);
+ bts_model_trx_close_cb(trx, 0);
return 0;
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
struct msgb *msg;
+ int rc;
msg = l1p_msgb_alloc();
prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphCloseReq, fl1h,
l1p_handle_for_trx(trx));
LOGP(DL1C, LOGL_NOTICE, "Close TRX %u\n", trx->nr);
- return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ rc = l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb, NULL);
+ if (rc < 0)
+ bts_model_trx_close_cb(trx, rc);
}
-static int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb)
+int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
uint8_t mute[8];
@@ -495,7 +525,7 @@ static int ts_connect_as(struct gsm_bts_trx_ts *ts,
GsmL1_MphConnectReq_t *cr;
if (pchan == GSM_PCHAN_TCH_F_PDCH
- || pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ || pchan == GSM_PCHAN_OSMO_DYN) {
LOGP(DL1C, LOGL_ERROR,
"%s Requested TS connect as %s,"
" expected a specific pchan instead\n",
@@ -508,10 +538,9 @@ static int ts_connect_as(struct gsm_bts_trx_ts *ts,
cr->u8Tn = ts->nr;
cr->logChComb = pchan_to_logChComb[pchan];
- DEBUGP(DL1C, "%s pchan=%s ts_connect_as(%s) logChComb=%s\n",
- gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan),
- gsm_pchan_name(pchan), get_value_string(femtobts_chcomb_names,
- cr->logChComb));
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "pchan=%s ts_connect_as(%s) logChComb=%s\n",
+ gsm_pchan_name(ts->pchan), gsm_pchan_name(pchan),
+ get_value_string(femtobts_chcomb_names, cr->logChComb));
return l1if_gsm_req_compl(fl1h, msg, cb, NULL);
}
@@ -520,7 +549,7 @@ static int ts_opstart(struct gsm_bts_trx_ts *ts)
{
enum gsm_phys_chan_config pchan = ts->pchan;
switch (pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
/* First connect as NONE, until first RSL CHAN ACT. */
pchan = GSM_PCHAN_NONE;
@@ -544,8 +573,7 @@ GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan)
case GSM_LCHAN_TCH_H:
return GsmL1_Sapi_TchH;
default:
- LOGP(DL1C, LOGL_NOTICE, "%s cannot determine L1 SAPI\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "cannot determine L1 SAPI\n");
break;
}
return GsmL1_Sapi_Idle;
@@ -555,7 +583,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
{
enum gsm_phys_chan_config pchan = lchan->ts->pchan;
- if (pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH)
+ if (pchan == GSM_PCHAN_OSMO_DYN)
pchan = lchan->ts->dyn.pchan_want;
switch (pchan) {
@@ -575,7 +603,7 @@ GsmL1_SubCh_t lchan_to_GsmL1_SubCh_t(const struct gsm_lchan *lchan)
case GSM_PCHAN_TCH_F_PDCH:
case GSM_PCHAN_UNKNOWN:
default:
- /* case GSM_PCHAN_TCH_F_TCH_H_PDCH: is caught above */
+ /* case GSM_PCHAN_OSMO_DYN: is caught above */
return GsmL1_SubCh_NA;
}
@@ -638,10 +666,6 @@ static const struct sapi_dir pdtch_sapis[] = {
#endif
};
-static const struct sapi_dir ho_sapis[] = {
- { GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink },
-};
-
struct lchan_sapis {
const struct sapi_dir *sapis;
unsigned int num_sapis;
@@ -674,11 +698,6 @@ static const struct lchan_sapis sapis_for_lchan[_GSM_LCHAN_MAX] = {
},
};
-static const struct lchan_sapis sapis_for_ho = {
- .sapis = ho_sapis,
- .num_sapis = ARRAY_SIZE(ho_sapis),
-};
-
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
@@ -766,12 +785,8 @@ static void sapi_queue_dispatch(struct gsm_lchan *lchan, int status)
talloc_free(cmd);
if (end || llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_DEBUG,
- "%s End of SAPI cmd queue encountered.%s\n",
- gsm_lchan_name(lchan),
- llist_empty(&lchan->sapi_cmds)
- ? " Queue is now empty."
- : " More pending.");
+ LOGPLCHAN(lchan, DL1C, LOGL_DEBUG, "End of SAPI cmd queue encountered.%s\n",
+ llist_empty(&lchan->sapi_cmds) ? " Queue is now empty." : " More pending.");
return;
}
@@ -811,8 +826,7 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.conf (%s ",
get_value_string(femtobts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(femtobts_dir_names, ic->dir));
@@ -834,19 +848,15 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
lchan->sapis_ul[ic->sapi] = status;
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_ACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -926,15 +936,14 @@ static void set_payload_format(GsmL1_LogChParam_t *lch_par)
#endif /* L1_HAS_RTP_MODE */
}
-static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
+static int lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
{
struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
struct gsm48_multi_rate_conf *mr_conf =
(struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
int j;
- LOGP(DL1C, LOGL_INFO, "%s: %s tch_mode=0x%02x\n",
- gsm_lchan_name(lchan), __FUNCTION__, lchan->tch_mode);
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, ": %s tch_mode=0x%02x\n", __func__, lchan->tch_mode);
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
@@ -962,7 +971,9 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_SPEECH_AMR:
lch_par->tch.tchPlType = GsmL1_TchPlType_Amr;
set_payload_format(lch_par);
- lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd; /* FIXME? */
+ /* At call set-up, after every successful handover and after a channel mode modify, the
+ * default phase (odd) shall be used in downlink direction. */
+ lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd;
lch_par->tch.amrInitCodecMode = amr_get_initial_mode(lchan);
/* initialize to clean state */
@@ -1011,10 +1022,13 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
- LOGP(DL1C, LOGL_ERROR, "%s: CSD not supported!\n",
- gsm_lchan_name(lchan));
- break;
+ default:
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Channel mode %s is not supported!\n",
+ gsm48_chan_mode_name(lchan->tch_mode));
+ return -ENOTSUP;
}
+
+ return 0;
}
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
@@ -1023,6 +1037,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
struct msgb *msg = l1p_msgb_alloc();
int sapi = cmd->sapi;
int dir = cmd->dir;
+ int rc;
GsmL1_MphActivateReq_t *act_req;
GsmL1_LogChParam_t *lch_par;
@@ -1045,7 +1060,10 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
case GsmL1_Sapi_TchH:
case GsmL1_Sapi_TchF:
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/*
* Be sure that every packet is received, even if it
* fails. In this case the length might be lower or 0.
@@ -1078,9 +1096,9 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
break;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.req (hL2=0x%08x, %s ",
- gsm_lchan_name(lchan), act_req->hLayer2,
- get_value_string(femtobts_l1sapi_names, act_req->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.req (hL2=0x%08x, %s ", act_req->hLayer2,
+ get_value_string(femtobts_l1sapi_names, act_req->sapi));
+ dump_lch_par(LOGL_INFO, lch_par, act_req->sapi);
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(femtobts_dir_names, act_req->dir));
@@ -1104,9 +1122,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status)
/* FIXME: Error handling */
if (status != GsmL1_Status_Success) {
- LOGP(DL1C, LOGL_ERROR,
- "%s act failed mark broken due status: %d\n",
- gsm_lchan_name(lchan), status);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "act failed mark broken due status: %d\n", status);
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_PROCESSOR_OVERLOAD);
@@ -1153,14 +1169,12 @@ int lchan_activate(struct gsm_lchan *lchan)
lchan_set_state(lchan, LCHAN_S_ACT_REQ);
if (!llist_empty(&lchan->sapi_cmds))
- LOGP(DL1C, LOGL_ERROR,
- "%s Trying to activate lchan, but commands in queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate lchan, but commands in queue\n");
- /* override the regular SAPIs if this is the first hand-over
- * related activation of the LCHAN */
+ /* For handover, always start the main channel immediately. lchan->want_dl_sacch_active indicates whether dl
+ * SACCH should be activated. */
if (lchan->ho.active == HANDOVER_ENABLED)
- s4l = &sapis_for_ho;
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
for (i = 0; i < s4l->num_sapis; i++) {
int sapi = s4l->sapis[i].sapi;
@@ -1173,12 +1187,13 @@ int lchan_activate(struct gsm_lchan *lchan)
fl1h->alive_prim_cnt = 0;
osmo_timer_schedule(&fl1h->alive_timer, 5, 0);
}
+
+ /* For handover, possibly postpone activating the dl SACCH until the HO RACH is received. */
+ if (sapi == GsmL1_Sapi_Sacch && dir == GsmL1_Dir_TxDownlink
+ && !lchan->want_dl_sacch_active)
+ continue;
enqueue_sapi_act_cmd(lchan, sapi, dir);
}
-
-#warning "FIXME: Should this be in sapi_activate_cb?"
- lchan_init_lapdm(lchan);
-
return 0;
}
@@ -1264,9 +1279,8 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(femtobts_l1cfgt_names, cc->cfgParamId));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.conf (%s) ",
+ get_value_string(femtobts_l1cfgt_names, cc->cfgParamId));
switch (cc->cfgParamId) {
case GsmL1_ConfigParamId_SetLogChParams:
@@ -1298,9 +1312,7 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
break;
}
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got ciphering conf with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got ciphering conf with empty queue\n");
goto err;
}
@@ -1325,6 +1337,7 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
struct msgb *msg = l1p_msgb_alloc();
GsmL1_MphConfigReq_t *conf_req;
GsmL1_LogChParam_t *lch_par;
+ int rc;
/* channel mode, encryption and/or multirate have changed */
@@ -1339,7 +1352,10 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
conf_req->hLayer3 = l1if_lchan_to_hLayer(lchan);
lch_par = &conf_req->cfgParams.setLogChParams.logChParams;
- lchan2lch_par(lch_par, lchan);
+ if ((rc = lchan2lch_par(lch_par, lchan)) != 0) {
+ talloc_free(msg);
+ return rc;
+ }
/* Update the MS Power Level */
if (cmd->sapi == GsmL1_Sapi_Sacch && trx_ms_pwr_ctrl_is_osmo(trx))
@@ -1347,10 +1363,8 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
/* FIXME: update encryption */
- LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.req (%s) ",
- gsm_lchan_name(lchan),
- get_value_string(femtobts_l1sapi_names,
- conf_req->cfgParams.setLogChParams.sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.req (%s) ",
+ get_value_string(femtobts_l1sapi_names, conf_req->cfgParams.setLogChParams.sapi));
LOGPC(DL1C, LOGL_INFO, "cfgParams Tn=%u, subCh=%u, dir=0x%x ",
conf_req->cfgParams.setLogChParams.u8Tn,
conf_req->cfgParams.setLogChParams.subCh,
@@ -1417,11 +1431,9 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c
return -EINVAL;
cfgr->cfgParams.setCipheringParams.cipherId = rsl2l1_ciph[lchan->encr.alg_id];
- LOGP(DL1C, LOGL_NOTICE, "%s SET_CIPHERING (ALG=%u %s)\n",
- gsm_lchan_name(lchan),
- cfgr->cfgParams.setCipheringParams.cipherId,
- get_value_string(femtobts_dir_names,
- cfgr->cfgParams.setCipheringParams.dir));
+ LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "SET_CIPHERING (ALG=%u %s)\n",
+ cfgr->cfgParams.setCipheringParams.cipherId,
+ get_value_string(femtobts_dir_names, cfgr->cfgParams.setCipheringParams.dir));
memcpy(cfgr->cfgParams.setCipheringParams.u8Kc,
lchan->encr.key, lchan->encr.key_len);
@@ -1458,6 +1470,16 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h,
return 0;
}
+int l1if_set_ul_acc(struct gsm_lchan *lchan, bool active)
+{
+ if (active)
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
+ else
+ check_sapi_release(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
+
+ return 0;
+}
+
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
{
if (lchan->state != LCHAN_S_ACTIVE)
@@ -1499,9 +1521,8 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
goto err;
}
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.conf (%s ",
- gsm_lchan_name(lchan),
- get_value_string(femtobts_l1sapi_names, ic->sapi));
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.conf (%s ",
+ get_value_string(femtobts_l1sapi_names, ic->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(femtobts_dir_names, ic->dir));
@@ -1523,19 +1544,15 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
if (llist_empty(&lchan->sapi_cmds)) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Got de-activation confirmation with empty queue\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got de-activation confirmation with empty queue\n");
goto err;
}
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
cmd->type != SAPI_CMD_DEACTIVATE) {
- LOGP(DL1C, LOGL_ERROR,
- "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
- gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
- ic->sapi, ic->dir);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
+ cmd->sapi, cmd->dir, ic->sapi, ic->dir);
goto err;
}
@@ -1560,8 +1577,7 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd
deact_req->sapi = cmd->sapi;
deact_req->hLayer3 = l1if_lchan_to_hLayer(lchan);
- LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.req (%s ",
- gsm_lchan_name(lchan),
+ LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.req (%s ",
get_value_string(femtobts_l1sapi_names, deact_req->sapi));
LOGPC(DL1C, LOGL_INFO, "%s)\n",
get_value_string(femtobts_dir_names, deact_req->dir));
@@ -1574,8 +1590,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status)
{
/* FIXME: Error handling. There is no NACK... */
if (status != GsmL1_Status_Success && lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s is now broken. Stopping the release.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "is now broken. Stopping the release.\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
sapi_clear_queue(&lchan->sapi_cmds);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
@@ -1632,17 +1647,9 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir)
return enqueue_sapi_deact_cmd(lchan, sapi, dir);
}
-static int release_sapis_for_ho(struct gsm_lchan *lchan)
+static int release_sapi_ul_rach(struct gsm_lchan *lchan)
{
- int res = 0;
- int i;
-
- const struct lchan_sapis *s4l = &sapis_for_ho;
-
- for (i = s4l->num_sapis-1; i >= 0; i--)
- res |= check_sapi_release(lchan,
- s4l->sapis[i].sapi, s4l->sapis[i].dir);
- return res;
+ return check_sapi_release(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
}
static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
@@ -1664,12 +1671,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
}
/* always attempt to disable the RACH burst */
- res |= release_sapis_for_ho(lchan);
+ res |= release_sapi_ul_rach(lchan);
/* nothing was queued */
if (res == 0) {
- LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "all SAPIs already released?\n");
lchan_set_state(lchan, LCHAN_S_BROKEN);
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
}
@@ -1716,67 +1722,55 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
void *obj)
{
/* FIXME: more checks if the attributes are valid */
-
- switch (msg_type) {
- case NM_MT_SET_CHAN_ATTR:
- /* our L1 only supports one global TSC for all channels
- * one one TRX, so we need to make sure not to activate
- * channels with a different TSC!! */
- if (TLVP_PRES_LEN(new_attr, NM_ATT_TSC, 1) &&
- *TLVP_VAL(new_attr, NM_ATT_TSC) != (bts->bsic & 7)) {
- LOGP(DOML, LOGL_ERROR, "Channel TSC %u != BSIC-TSC %u\n",
- *TLVP_VAL(new_attr, NM_ATT_TSC), bts->bsic & 7);
- return -NM_NACK_PARAM_RANGE;
- }
- break;
- }
return 0;
}
/* callback from OML */
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{
- if (kind == NM_OC_RADIO_CARRIER) {
- struct gsm_bts_trx *trx = obj;
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx;
+ struct femtol1_hdl *fl1h;
+
+ switch (foh->msg_type) {
+ case NM_MT_SET_RADIO_ATTR:
+ trx = obj;
+ fl1h = trx_femtol1_hdl(trx);
/* Did we go through MphInit yet? If yes fire and forget */
if (fl1h->hLayer1)
- power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0, NULL);
+ break;
}
- /* FIXME: we actaully need to send a ACK or NACK for the OML message */
- return oml_fom_ack_nack(msg, 0);
+ return 0;
}
/* callback from OML */
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj)
{
+ struct gsm_bts_trx* trx;
+ struct gsm_bts_trx_ts *ts;
int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- rc = trx_init(obj);
- break;
- case NM_OC_CHANNEL:
- rc = ts_opstart(obj);
- break;
- case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
+ case NM_OC_BTS:
case NM_OC_BASEB_TRANSC:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, -1);
- rc = oml_mo_opstart_ack(mo);
- if (mo->obj_class == NM_OC_BTS) {
- oml_mo_state_chg(&bts->mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nse.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.cell.mo, -1, NM_AVSTATE_OK);
- oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK);
- }
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ trx = (struct gsm_bts_trx *) obj;
+ rc = trx_init(trx);
+ break;
+ case NM_OC_CHANNEL:
+ ts = (struct gsm_bts_trx_ts*) obj;
+ rc = ts_opstart(ts);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -1847,24 +1841,26 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
*/
int l1if_rsl_chan_mod(struct gsm_lchan *lchan)
{
- const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
- unsigned int i;
-
if (lchan->ho.active == HANDOVER_NONE)
return -1;
- LOGP(DHO, LOGL_ERROR, "%s modifying channel for handover\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DHO, LOGL_ERROR, "modifying channel for handover\n");
/* Give up listening to RACH bursts */
- release_sapis_for_ho(lchan);
-
- /* Activate the normal SAPIs */
- for (i = 0; i < s4l->num_sapis; i++) {
- int sapi = s4l->sapis[i].sapi;
- int dir = s4l->sapis[i].dir;
- enqueue_sapi_act_cmd(lchan, sapi, dir);
- }
+ release_sapi_ul_rach(lchan);
+
+ /* All the normal SAPIs have already been activated, only DL SACCH may still be missing.
+ *
+ * Note: theoretically, it would only be necessary to activate the DL SACCH when it is not active yet. With
+ * repeated HO RACH received, we shouldn't need to re-send the SAPI activation every time. However, tests with
+ * sysmoBTS show that when sending this SAPI activation only once, the lchan will release some seconds after a
+ * handover, with error messages indicating "Lost SACCH block, faking meas reports and ms pwr". When re-sending
+ * the SAPI activation for every RACH received, the problem goes away.
+ * Before introducing lchan->want_dl_sacch_active, this code here would activate all SAPIs for the main channel,
+ * which would also repeat for each RACH received. Now we only activate DL SACCH here.
+ */
+ if (lchan->want_dl_sacch_active)
+ enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Sacch, GsmL1_Dir_TxDownlink);
return 0;
}
@@ -1873,8 +1869,7 @@ int l1if_rsl_chan_rel(struct gsm_lchan *lchan)
{
/* A duplicate RF Release Request, ignore it */
if (lchan->state == LCHAN_S_REL_REQ) {
- LOGP(DL1C, LOGL_ERROR, "%s already in release request state.\n",
- gsm_lchan_name(lchan));
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "already in release request state.\n");
return 0;
}
@@ -1910,8 +1905,7 @@ static int ts_disconnect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- LOGP(DL1C, LOGL_DEBUG, "%s Rx mphDisconnectCnf\n",
- gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "Rx mphDisconnectCnf\n");
cb_ts_disconnected(ts);
@@ -1924,7 +1918,7 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
struct femtol1_hdl *fl1h = trx_femtol1_hdl(ts->trx);
GsmL1_MphDisconnectReq_t *cr;
- DEBUGP(DRSL, "%s TS disconnect\n", gsm_lchan_name(ts->lchan));
+ LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "TS disconnect\n");
cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphDisconnectReq, fl1h,
l1p_handle_for_ts(ts));
cr->u8Tn = ts->nr;
@@ -1940,8 +1934,7 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
- DEBUGP(DL1C, "%s %s Rx mphConnectCnf flags=%s%s%s\n",
- gsm_lchan_name(ts->lchan),
+ LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "%s Rx mphConnectCnf flags=%s%s%s\n",
gsm_pchan_name(ts->pchan),
ts->flags & TS_F_PDCH_ACTIVE ? "ACTIVE " : "",
ts->flags & TS_F_PDCH_ACT_PENDING ? "ACT_PENDING " : "",
diff --git a/src/osmo-bts-sysmo/oml_router.c b/src/osmo-bts-sysmo/oml_router.c
deleted file mode 100644
index f3d08373..00000000
--- a/src/osmo-bts-sysmo/oml_router.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/* Beginnings of an OML router */
-
-/* (C) 2014 by sysmocom s.f.m.c. GmbH
- *
- * 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 "oml_router.h"
-
-#include <osmo-bts/bts.h>
-#include <osmo-bts/logging.h>
-#include <osmo-bts/oml.h>
-#include <osmo-bts/msg_utils.h>
-
-#include <osmocom/core/socket.h>
-#include <osmocom/core/select.h>
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-static int oml_router_read_cb(struct osmo_fd *fd, unsigned int what)
-{
- struct msgb *msg;
- int rc;
-
- msg = oml_msgb_alloc();
- if (!msg) {
- LOGP(DL1C, LOGL_ERROR, "Failed to allocate oml msgb.\n");
- return -1;
- }
-
- rc = recv(fd->fd, msg->tail, msg->data_len, 0);
- if (rc <= 0) {
- close(fd->fd);
- osmo_fd_unregister(fd);
- fd->fd = -1;
- goto err;
- }
-
- msg->l1h = msgb_put(msg, rc);
- rc = msg_verify_ipa_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid IPA message rc(%d)\n", rc);
- goto err;
- }
-
- rc = msg_verify_oml_structure(msg);
- if (rc < 0) {
- LOGP(DL1C, LOGL_ERROR,
- "OML Router: Invalid OML message rc(%d)\n", rc);
- goto err;
- }
-
- /* todo dispatch message */
-
-err:
- msgb_free(msg);
- return -1;
-}
-
-static int oml_router_accept_cb(struct osmo_fd *accept_fd, unsigned int what)
-{
- int fd;
- struct osmo_fd *read_fd = (struct osmo_fd *) accept_fd->data;
-
- /* Accept only one connection at a time. De-register it */
- if (read_fd->fd > -1) {
- LOGP(DL1C, LOGL_NOTICE,
- "New OML router connection. Closing old one.\n");
- close(read_fd->fd);
- osmo_fd_unregister(read_fd);
- read_fd->fd = -1;
- }
-
- fd = accept(accept_fd->fd, NULL, NULL);
- if (fd < 0) {
- LOGP(DL1C, LOGL_ERROR, "Failed to accept. errno: %s.\n",
- strerror(errno));
- return -1;
- }
-
- read_fd->fd = fd;
- if (osmo_fd_register(read_fd) != 0) {
- LOGP(DL1C, LOGL_ERROR, "Registering the read fd failed.\n");
- close(fd);
- read_fd->fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-int oml_router_init(struct gsm_bts *bts, const char *path,
- struct osmo_fd *accept_fd, struct osmo_fd *read_fd)
-{
- int rc;
-
- memset(accept_fd, 0, sizeof(*accept_fd));
- memset(read_fd, 0, sizeof(*read_fd));
-
- accept_fd->cb = oml_router_accept_cb;
- accept_fd->data = read_fd;
-
- read_fd->cb = oml_router_read_cb;
- read_fd->data = bts;
- read_fd->when = BSC_FD_READ;
- read_fd->fd = -1;
-
- rc = osmo_sock_unix_init_ofd(accept_fd, SOCK_SEQPACKET, 0,
- path,
- OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK);
- return rc;
-}
diff --git a/src/osmo-bts-sysmo/oml_router.h b/src/osmo-bts-sysmo/oml_router.h
deleted file mode 100644
index 55f0681d..00000000
--- a/src/osmo-bts-sysmo/oml_router.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-struct gsm_bts;
-struct osmo_fd;
-
-/**
- * The default path sysmobts will listen for incoming
- * registrations for OML routing and sending.
- */
-#define OML_ROUTER_PATH "/var/run/sysmobts_oml_router"
-
-
-int oml_router_init(struct gsm_bts *bts, const char *path, struct osmo_fd *accept, struct osmo_fd *read);
diff --git a/src/osmo-bts-sysmo/sysmobts_ctrl.c b/src/osmo-bts-sysmo/sysmobts_ctrl.c
index 21df88e5..6beeaf62 100644
--- a/src/osmo-bts-sysmo/sysmobts_ctrl.c
+++ b/src/osmo-bts-sysmo/sysmobts_ctrl.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -94,7 +94,7 @@ static int get_clock_info(struct ctrl_cmd *cmd, void *data)
SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
struct ctrl_cmd_def *cd;
- /* geneate a deferred control command */
+ /* generate a deferred control command */
cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10);
sysp->id = SuperFemto_PrimId_RfClockInfoReq;
@@ -136,7 +136,7 @@ static int set_clock_info(struct ctrl_cmd *cmd, void *data)
SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
struct ctrl_cmd_def *cd;
- /* geneate a deferred control command */
+ /* generate a deferred control command */
cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10);
/* Set GPS/PPS as reference */
@@ -197,7 +197,7 @@ static int get_clock_corr(struct ctrl_cmd *cmd, void *data)
* prefer to to ask the actual L1 about the currently used value to
* avoid any mistakes */
- /* geneate a deferred control command */
+ /* generate a deferred control command */
cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10);
sysp->id = SuperFemto_PrimId_RfClockInfoReq;
@@ -241,7 +241,7 @@ static int set_clock_corr(struct ctrl_cmd *cmd, void *data)
fl1h->clk_cal = atoi(cmd->value);
- /* geneate a deferred control command */
+ /* generate a deferred control command */
cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10);
sysp->id = SuperFemto_PrimId_RfClockSetupReq;
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index 3199c8e2..2e853356 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -45,6 +45,7 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/vty.h>
#include <osmo-bts/rsl.h>
+#include <osmo-bts/bts.h>
#include "femtobts.h"
#include "l1_if.h"
@@ -59,8 +60,6 @@ extern int lchan_activate(struct gsm_lchan *lchan);
TRX_STR
#define DSP_TRACE_F_STR "DSP Trace Flag\n"
-static struct gsm_bts *vty_bts;
-
/* configuration */
DEFUN(cfg_phy_clkcal_eeprom, cfg_phy_clkcal_eeprom_cmd,
@@ -153,9 +152,20 @@ DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
"Obsolete alias for bts uplink-power-target\n"
"Target uplink Rx level in dBm\n")
{
+ struct gsm_power_ctrl_meas_params *mp;
struct gsm_bts_trx *trx = vty->index;
+ int rxlev_dbm = atoi(argv[0]);
+
+ mp = &trx->bts->ms_dpc_params.rxlev_meas;
+ mp->lower_thresh = mp->upper_thresh = dbm2rxlev(rxlev_dbm);
- trx->bts->ul_power_target = atoi(argv[0]);
+ vty_out(vty, "%% Command '%s' has been deprecated.%s"
+ "%% MS/BS Power control parameters should be configured in osmo-bsc: "
+ "use 'rxlev-thresh lower %u upper %u'.%s",
+ self->string, VTY_NEWLINE,
+ mp->lower_thresh,
+ mp->upper_thresh,
+ VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -178,7 +188,7 @@ DEFUN(cfg_phy_dsp_trace_f, cfg_phy_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(femtobts_tracef_names, argv[1]);
+ flag = get_string_value(femtobts_tracef_names, argv[0]);
pinst->u.sysmobts.dsp_trace_f |= flag;
return CMD_SUCCESS;
@@ -190,7 +200,7 @@ DEFUN(cfg_phy_no_dsp_trace_f, cfg_phy_no_dsp_trace_f_cmd,
struct phy_instance *pinst = vty->index;
unsigned int flag;
- flag = get_string_value(femtobts_tracef_names, argv[1]);
+ flag = get_string_value(femtobts_tracef_names, argv[0]);
pinst->u.sysmobts.dsp_trace_f &= ~flag;
return CMD_SUCCESS;
@@ -216,11 +226,11 @@ DEFUN(show_phy_clksrc, show_trx_clksrc_cmd,
}
DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd,
- "show trx <0-0> dsp-trace-flags",
+ "show dsp-trace-flags trx <0-0>",
SHOW_TRX_STR "Display the current setting of the DSP trace flags")
{
int trx_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct femtol1_hdl *fl1h;
int i;
@@ -340,7 +350,7 @@ DEFUN(activate_lchan, activate_lchan_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[3]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -360,9 +370,9 @@ DEFUN(set_tx_power, set_tx_power_cmd,
{
int trx_nr = atoi(argv[0]);
int power = atoi(argv[1]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
- power_ramp_start(trx, to_mdB(power), 1);
+ power_ramp_start(trx, to_mdB(power), 1, NULL);
return CMD_SUCCESS;
}
@@ -373,7 +383,7 @@ DEFUN(reset_rf_clock_ctr, reset_rf_clock_ctr_cmd,
"RF Clock Information\n" "Reset the counter\n")
{
int trx_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
l1if_rf_clock_info_reset(fl1h);
@@ -386,7 +396,7 @@ DEFUN(correct_rf_clock_ctr, correct_rf_clock_ctr_cmd,
"RF Clock Information\n" "Apply\n")
{
int trx_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
l1if_rf_clock_info_correct(fl1h);
@@ -403,7 +413,7 @@ DEFUN(loopback, loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -422,7 +432,7 @@ DEFUN(no_loopback, no_loopback_cmd,
int trx_nr = atoi(argv[0]);
int ts_nr = atoi(argv[1]);
int lchan_nr = atoi(argv[2]);
- struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(g_bts, trx_nr);
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
@@ -432,22 +442,22 @@ DEFUN(no_loopback, no_loopback_cmd,
}
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
{
}
-void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
if (trx->nominal_power != get_p_max_out_mdBm(trx))
vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,
VTY_NEWLINE);
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
int i;
@@ -474,39 +484,37 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst
pinst->u.sysmobts.clk_src), VTY_NEWLINE);
}
-int bts_model_vty_init(struct gsm_bts *bts)
+int bts_model_vty_init(void *ctx)
{
- vty_bts = bts;
-
/* runtime-patch the command strings with debug levels */
- dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_tracef_names,
+ dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, femtobts_tracef_names,
"trx <0-0> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_tracef_docs,
+ dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, femtobts_tracef_docs,
TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
- no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_tracef_names,
+ no_dsp_trace_f_cmd.string = vty_cmd_string_from_valstr(ctx, femtobts_tracef_names,
"no trx <0-0> dsp-trace-flag (",
"|",")", VTY_DO_LOWER);
- no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_tracef_docs,
+ no_dsp_trace_f_cmd.doc = vty_cmd_string_from_valstr(ctx, femtobts_tracef_docs,
NO_STR TRX_STR DSP_TRACE_F_STR,
"\n", "", 0);
cfg_phy_dsp_trace_f_cmd.string =
- vty_cmd_string_from_valstr(bts, femtobts_tracef_names,
+ vty_cmd_string_from_valstr(ctx, femtobts_tracef_names,
"dsp-trace-flag (", "|", ")",
VTY_DO_LOWER);
cfg_phy_dsp_trace_f_cmd.doc =
- vty_cmd_string_from_valstr(bts, femtobts_tracef_docs,
+ vty_cmd_string_from_valstr(ctx, femtobts_tracef_docs,
DSP_TRACE_F_STR, "\n", "", 0);
cfg_phy_no_dsp_trace_f_cmd.string =
- vty_cmd_string_from_valstr(bts, femtobts_tracef_names,
+ vty_cmd_string_from_valstr(ctx, femtobts_tracef_names,
"no dsp-trace-flag (", "|", ")",
VTY_DO_LOWER);
cfg_phy_no_dsp_trace_f_cmd.doc =
- vty_cmd_string_from_valstr(bts, femtobts_tracef_docs,
+ vty_cmd_string_from_valstr(ctx, femtobts_tracef_docs,
NO_STR DSP_TRACE_F_STR, "\n",
"", 0);
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c
index 54e73136..2cf784e6 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -77,7 +77,7 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
cur[0] |= 0xD0;
#endif /* USE_L1_RTP_MODE */
- lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan);
+ lchan_set_marker(osmo_fr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -131,12 +131,8 @@ static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload,
cur[0] |= 0xC0;
#endif /* USE_L1_RTP_MODE */
- enum osmo_amr_type ft;
- enum osmo_amr_quality bfi;
- uint8_t cmr;
- int8_t sti, cmi;
- osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti);
- lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan);
+
+ lchan_set_marker(osmo_efr_is_any_sid(l1_payload), lchan);
return msg;
}
@@ -298,7 +294,7 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le
LOGP(DL1P, LOGL_NOTICE, "L1->RTP: overriding CMR IDX %u\n", cmr_idx);
cmr = AMR_CMR_NONE;
} else {
- cmr = amr_mrc->bts_mode[cmr_idx].mode;
+ cmr = amr_mrc->mode[cmr_idx].mode;
lchan->tch.last_cmr = cmr;
}
@@ -403,7 +399,10 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Efr;
rc = rtppayload_to_l1_efr(l1_payload, rtp_pl,
rtp_pl_len);
- /* FIXME: detect and save EFR SID */
+ if (rc && lchan->ts->trx->bts->dtxd)
+ is_sid = osmo_efr_check_sid(rtp_pl, rtp_pl_len);
+ if (is_sid)
+ dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
break;
#endif
case GSM48_CMODE_SPEECH_AMR:
@@ -505,7 +504,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
{
GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
- uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
+ uint8_t *payload, payload_type, payload_len;
struct msgb *rmsg = NULL;
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
@@ -513,12 +512,15 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
return -EAGAIN;
if (data_ind->msgUnitParam.u8Size < 1) {
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx Payload size 0\n", chan_nr);
/* Push empty payload to upper layers */
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10,
+ data_ind->measParam.fRssi,
+ data_ind->measParam.i16BurstTiming * 64,
+ 0);
}
payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -546,6 +548,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (lchan->type != GSM_LCHAN_TCH_H &&
lchan->type != GSM_LCHAN_TCH_F)
goto err_payload_match;
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received ONSET from L1 " "(%d bytes)\n",
+ payload_len);
/* according to 3GPP TS 26.093 ONSET frames precede the first
speech frame of a speech burst - set the marker for next RTP
frame */
@@ -554,33 +558,32 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
case GsmL1_TchPlType_Amr_SidFirstP1:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P1 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstP2:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P2 from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidFirstInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
case GsmL1_TchPlType_Amr_SidUpdateInH:
if (lchan->type != GSM_LCHAN_TCH_H)
goto err_payload_match;
lchan->rtp_tx_marker = true;
- LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
- "(%d bytes)\n", payload_len);
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_UPDATE_INH from L1 "
+ "(%d bytes)\n", payload_len);
break;
default:
- LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "%s Rx Payload Type %s is unsupported\n",
- gsm_lchan_name(lchan),
- get_value_string(femtobts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_NOTICE, "%s Rx Payload Type %s is unsupported\n",
+ gsm_lchan_name(lchan), get_value_string(femtobts_tch_pl_names, payload_type));
break;
}
@@ -598,14 +601,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
break;
#endif
case GsmL1_TchPlType_Amr:
- rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
- break;
case GsmL1_TchPlType_Amr_SidFirstP1:
- memcpy(sid_first, payload, payload_len);
- int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
- if (len < 0)
- return 0;
- rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
+ rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
break;
/* FIXME: what about GsmL1_TchPlType_Amr_SidBad? not well documented. */
}
@@ -613,17 +610,42 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000,
- data_ind->measParam.fLinkQuality * 10);
+ data_ind->measParam.fLinkQuality * 10,
+ data_ind->measParam.fRssi,
+ data_ind->measParam.i16BurstTiming * 64,
+ 0);
return 0;
err_payload_match:
- LOGPFN(DL1P, LOGL_ERROR, data_ind->u32Fn, "%s Rx Payload Type %s incompatible with lchan\n",
- gsm_lchan_name(lchan),
- get_value_string(femtobts_tch_pl_names, payload_type));
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_ERROR, "%s Rx Payload Type %s incompatible with lchan\n",
+ gsm_lchan_name(lchan), get_value_string(femtobts_tch_pl_names, payload_type));
return -EINVAL;
}
+/*! \brief provide an RTP empty payload "tick" to upper layers upon FACCH */
+int l1if_tch_rx_facch(struct gsm_bts_trx *trx, uint8_t chan_nr,
+ struct msgb *l1p_msg)
+{
+ GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
+ GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
+ struct msgb *rmsg = NULL;
+ struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
+
+ if (is_recv_only(lchan->abis_ip.speech_mode))
+ return -EAGAIN;
+
+ LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx FACCH\n", chan_nr);
+ /* Push empty payload to upper layers */
+ rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
+ return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
+ data_ind->measParam.fBer * 10000,
+ data_ind->measParam.fLinkQuality * 10,
+ 0, /* suppress RSSI like in osmo-bts-trx */
+ data_ind->measParam.i16BurstTiming * 64,
+ 0);
+}
+
struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn)
{
struct msgb *msg;
diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c
index 0e3ef273..735ebe0e 100644
--- a/src/osmo-bts-sysmo/utils.c
+++ b/src/osmo-bts-sysmo/utils.c
@@ -14,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am
index 19222405..63c00fec 100644
--- a/src/osmo-bts-trx/Makefile.am
+++ b/src/osmo-bts-trx/Makefile.am
@@ -1,10 +1,75 @@
-AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOCODING_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOCODING_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) -ldl
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ $(NULL)
-EXTRA_DIST = trx_if.h l1_if.h loops.h
+AM_CFLAGS = \
+ -Wall -fno-strict-aliasing \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOCODING_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOCODING_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ -ldl \
+ $(NULL)
+
+noinst_HEADERS = \
+ sched_utils.h \
+ trx_if.h \
+ l1_if.h \
+ amr_loop.h \
+ trx_provision_fsm.h \
+ $(NULL)
bin_PROGRAMS = osmo-bts-trx
-osmo_bts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler_trx.c trx_vty.c loops.c
-osmo_bts_trx_LDADD = $(top_builddir)/src/common/libl1sched.a $(top_builddir)/src/common/libbts.a $(LDADD)
+osmo_bts_trx_SOURCES = \
+ main.c \
+ trx_if.c \
+ l1_if.c \
+ scheduler_trx.c \
+ sched_lchan_fcch_sch.c \
+ sched_lchan_rach.c \
+ sched_lchan_xcch.c \
+ sched_lchan_pdtch.c \
+ sched_lchan_tchf.c \
+ sched_lchan_tchh.c \
+ trx_provision_fsm.c \
+ trx_vty.c \
+ amr_loop.c \
+ probes.d \
+ $(NULL)
+
+osmo_bts_trx_LDADD = \
+ $(top_builddir)/src/common/libl1sched.a \
+ $(top_builddir)/src/common/libbts.a \
+ $(LDADD) \
+ $(NULL)
+
+if ENABLE_SYSTEMTAP
+probes.h: probes.d
+ $(DTRACE) -C -h -s $< -o $@
+
+probes.lo: probes.d
+ $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -C -G -s $< -o $@
+
+BUILT_SOURCES = probes.h probes.lo
+osmo_bts_trx_LDADD += probes.lo
+endif
diff --git a/src/osmo-bts-trx/amr_loop.c b/src/osmo-bts-trx/amr_loop.c
new file mode 100644
index 00000000..cf75a8fc
--- /dev/null
+++ b/src/osmo-bts-trx/amr_loop.c
@@ -0,0 +1,107 @@
+/* AMR link adaptation loop (see 3GPP TS 45.009, section 3) */
+
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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 <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/logging.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include "amr_loop.h"
+
+void trx_loop_amr_input(struct l1sched_chan_state *chan_state,
+ const struct l1sched_meas_set *meas_set)
+{
+ const struct gsm_lchan *lchan = chan_state->lchan;
+ const struct amr_multirate_conf *cfg = &lchan->tch.amr_mr;
+ const uint8_t mi = chan_state->ul_ft; /* mode index 0..3 */
+ int lqual_cb = meas_set->ci_cb; /* cB (centibel) */
+
+ /* count per-block C/I samples for further averaging */
+ if (lchan->type == GSM_LCHAN_TCH_H) {
+ chan_state->lqual_cb_num += 2;
+ chan_state->lqual_cb_sum += (lqual_cb + lqual_cb);
+ } else {
+ chan_state->lqual_cb_num++;
+ chan_state->lqual_cb_sum += lqual_cb;
+ }
+
+ /* wait for MS to use the requested codec */
+ if (mi != chan_state->dl_cmr)
+ return;
+
+ /* count frames */
+ if (chan_state->lqual_cb_num < 48)
+ return;
+
+ /* calculate average (reuse lqual_cb variable) */
+ lqual_cb = chan_state->lqual_cb_sum / chan_state->lqual_cb_num;
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "AMR link quality (C/I) is %d cB, "
+ "codec mode[%u]=%u\n", lqual_cb, mi, cfg->mode[mi].mode);
+
+ /* reset the link quality measurements */
+ chan_state->lqual_cb_num = 0;
+ chan_state->lqual_cb_sum = 0;
+
+ /* If the current codec mode can be degraded */
+ if (mi > 0) {
+ /* The threshold/hysteresis is in 0.5 dB steps, convert to cB:
+ * 1dB is 10cB, so 0.5dB is 5cB - this is why we multiply by 5. */
+ const int thresh_lower_cb = cfg->mode[mi - 1].threshold * 5;
+
+ /* Degrade if the link quality is below THR_MX_Dn(i - 1) */
+ if (lqual_cb < thresh_lower_cb) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Degrading AMR codec mode: "
+ "[%u]=%u -> [%u]=%u due to link quality %d cB < THR_MX_Dn=%d cB\n",
+ mi, cfg->mode[mi].mode, mi - 1, cfg->mode[mi - 1].mode,
+ lqual_cb, thresh_lower_cb);
+ chan_state->dl_cmr--;
+ return;
+ }
+ }
+
+ /* If the current codec mode can be upgraded */
+ if (mi < chan_state->codecs - 1) {
+ /* The threshold/hysteresis is in 0.5 dB steps, convert to cB:
+ * 1dB is 10cB, so 0.5dB is 5cB - this is why we multiply by 5. */
+ const int thresh_upper_cb = cfg->mode[mi].threshold * 5 \
+ + cfg->mode[mi].hysteresis * 5;
+
+ /* Upgrade if the link quality is above THR_MX_Up(i) */
+ if (lqual_cb > thresh_upper_cb) {
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Upgrading AMR codec mode: "
+ "[%u]=%u -> [%u]=%u due to link quality %d cB > THR_MX_Up=%d cB\n",
+ mi, cfg->mode[mi].mode, mi + 1, cfg->mode[mi + 1].mode,
+ lqual_cb, thresh_upper_cb);
+ chan_state->dl_cmr++;
+ return;
+ }
+ }
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Keeping the current AMR codec "
+ "mode[%u]=%u\n", mi, cfg->mode[mi].mode);
+}
diff --git a/src/osmo-bts-trx/amr_loop.h b/src/osmo-bts-trx/amr_loop.h
new file mode 100644
index 00000000..efff76cf
--- /dev/null
+++ b/src/osmo-bts-trx/amr_loop.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <osmo-bts/scheduler.h>
+
+/*
+ * calibration of loops
+ */
+
+/*
+ * loops api
+ */
+
+void trx_loop_amr_input(struct l1sched_chan_state *chan_state,
+ const struct l1sched_meas_set *meas_set);
+
+void trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop);
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index db53d4c6..54f5bd24 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -29,8 +29,10 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/codec/ecu.h>
#include <osmocom/gsm/abis_nm.h>
+#include <osmocom/gsm/rsl.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
@@ -41,10 +43,15 @@
#include <osmo-bts/amr.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/scheduler.h>
+#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/handover.h>
#include "l1_if.h"
#include "trx_if.h"
+#include "trx_provision_fsm.h"
+#define RF_DISABLED_mdB to_mdB(-10)
static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_NONE] = 8,
@@ -60,7 +67,7 @@ static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_UNKNOWN] = 0,
};
-static enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type)
+enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type)
{
int i;
for (i = 0; i < _GSM_PCHAN_MAX; i++) {
@@ -75,221 +82,78 @@ struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst)
struct trx_l1h *l1h;
l1h = talloc_zero(tall_ctx, struct trx_l1h);
l1h->phy_inst = pinst;
+ l1h->provision_fi = osmo_fsm_inst_alloc(&trx_prov_fsm, l1h, l1h, LOGL_INFO, NULL);
+ OSMO_ASSERT(osmo_fsm_inst_update_id_f_sanitize(l1h->provision_fi, '-', phy_instance_name(pinst)) == 0);
trx_if_init(l1h);
return l1h;
}
-static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail)
-{
- 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
- * transceiver */
- if (avail) {
- /* signal availability */
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
- if (!pinst->u.osmotrx.sw_act_reported) {
- oml_mo_tx_sw_act_rep(&trx->mo);
- oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
- pinst->u.osmotrx.sw_act_reported = true;
- }
-
- for (tn = 0; tn < TRX_NR_TS; tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED,
- (l1h->config.slotmask & (1 << tn)) ?
- NM_AVSTATE_DEPENDENCY :
- NM_AVSTATE_NOT_INSTALLED);
- } else {
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_OFF_LINE);
- oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_OFF_LINE);
-
- for (tn = 0; tn < TRX_NR_TS; tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED,
- NM_AVSTATE_OFF_LINE);
- }
-}
-
-int check_transceiver_availability(struct gsm_bts *bts, int avail)
-{
- struct gsm_bts_trx *trx;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- struct phy_instance *pinst = trx_phy_instance(trx);
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- check_transceiver_availability_trx(l1h, avail);
- }
- return 0;
-}
-
int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
{
- struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ int rc;
+ /* set lchan inactive */
+ lchan_set_state(lchan, LCHAN_S_NONE);
+ /* Disable it on the scheduler: */
+ rc = trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, false);
+
+ /* Reactivate CCCH due to SI3 update in RSL */
if (lchan->rel_act_kind == LCHAN_REL_ACT_REACT) {
lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
- /* FIXME: perform whatever is needed (if any) to set proper PCH/AGCH allocation according to
- 3GPP TS 44.018 Table 10.5.2.11.1 using num_agch(lchan->ts->trx, "TRX L1"); function */
- return 0;
+ trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, true);
+ lchan_set_state(lchan, LCHAN_S_ACTIVE);
+ return rc;
}
- /* set lchan inactive */
- lchan_set_state(lchan, LCHAN_S_NONE);
-
- return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan),
- LID_DEDIC, 0);
+ return rc;
}
int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan)
{
- struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan),
- LID_SACCH, 0);
+ return trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_SACCH, false);
}
-static void l1if_setslot_cb(struct trx_l1h *l1h, uint8_t tn, uint8_t type, int rc)
+int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb)
{
- struct phy_instance *pinst = l1h->phy_inst;
- struct gsm_bts_trx *trx = pinst->trx;
- struct gsm_bts_trx_ts *ts;
- enum gsm_phys_chan_config pchan;
-
- if (tn >= TRX_NR_TS) {
- LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TN (%" PRIu8 ")\n",
- tn);
- return;
- }
-
- pchan = transceiver_chan_type_2_pchan(type);
- if (pchan == GSM_PCHAN_UNKNOWN) {
- LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TS_TYPE (%" PRIu8 ")\n",
- type);
- return;
- }
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- ts = &trx->ts[tn];
- LOGPPHI(pinst, DL1C, LOGL_DEBUG, "%s l1if_setslot_cb(as_pchan=%s),"
- " calling cb_ts_connected(rc=%d)\n",
- gsm_ts_name(ts), gsm_pchan_name(pchan), rc);
- cb_ts_connected(ts, rc);
+ if (l1h->config.forced_max_power_red == -1)
+ return power_ramp_start(trx, get_p_nominal_mdBm(trx), 0, ramp_compl_cb);
+ else
+ return power_ramp_start(trx, get_p_max_out_mdBm(trx) - to_mdB(l1h->config.forced_max_power_red), 1, ramp_compl_cb);
}
-
-/*
- * transceiver provisioning
- */
-int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
+/* Sets the nominal power, in dB */
+void l1if_trx_set_nominal_power(struct gsm_bts_trx *trx, int nominal_power)
{
- uint8_t tn;
- struct phy_link *plink = l1h->phy_inst->phy_link;
-
- if (!transceiver_available)
- return -EIO;
-
- if (l1h->config.poweron
- && l1h->config.tsc_valid
- && l1h->config.bsic_valid
- && l1h->config.arfcn_valid) {
- /* before power on */
- if (!l1h->config.arfcn_sent) {
- trx_if_cmd_rxtune(l1h, l1h->config.arfcn);
- trx_if_cmd_txtune(l1h, l1h->config.arfcn);
- l1h->config.arfcn_sent = 1;
- }
- if (!l1h->config.tsc_sent) {
- trx_if_cmd_settsc(l1h, l1h->config.tsc);
- l1h->config.tsc_sent = 1;
- }
- if (!l1h->config.bsic_sent) {
- trx_if_cmd_setbsic(l1h, l1h->config.bsic);
- l1h->config.bsic_sent = 1;
- }
-
- /* Ask transceiver to use the newest TRXD header version if not using it yet */
- if (!l1h->config.setformat_sent &&
- l1h->config.trxd_hdr_ver_use != plink->u.osmotrx.trxd_hdr_ver_max) {
- trx_if_cmd_setformat(l1h, plink->u.osmotrx.trxd_hdr_ver_max);
- l1h->config.trxd_hdr_ver_req = plink->u.osmotrx.trxd_hdr_ver_max;
- l1h->config.setformat_sent = 1;
- }
-
- if (!l1h->config.poweron_sent) {
- trx_if_cmd_poweron(l1h);
- l1h->config.poweron_sent = 1;
- }
-
- /* 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->config.maxdly_valid && !l1h->config.maxdly_sent) {
- trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly);
- l1h->config.maxdly_sent = 1;
- }
- if (l1h->config.maxdlynb_valid && !l1h->config.maxdlynb_sent) {
- trx_if_cmd_setmaxdlynb(l1h, l1h->config.maxdlynb);
- l1h->config.maxdlynb_sent = 1;
- }
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ bool nom_pwr_changed = trx->nominal_power != nominal_power;
- for (tn = 0; tn < TRX_NR_TS; tn++) {
- if (l1h->config.slottype_valid[tn]
- && !l1h->config.slottype_sent[tn]) {
- trx_if_cmd_setslot(l1h, tn,
- l1h->config.slottype[tn], l1if_setslot_cb);
- l1h->config.slottype_sent[tn] = 1;
- }
- }
- return 0;
- }
+ trx->nominal_power = nominal_power;
+ trx->power_params.trx_p_max_out_mdBm = to_mdB(nominal_power);
+ /* If we receive ultra-low nominal Tx power (<0dBm), make sure to update where we are */
+ trx->power_params.p_total_cur_mdBm = OSMO_MIN(trx->power_params.p_total_cur_mdBm,
+ trx->power_params.trx_p_max_out_mdBm);
- 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;
- l1h->config.maxdly_sent = 0;
- l1h->config.maxdlynb_sent = 0;
- for (tn = 0; tn < TRX_NR_TS; tn++)
- l1h->config.slottype_sent[tn] = 0;
- }
+ /* If TRX is not yet powered, delay ramping until it's ON */
+ if (!nom_pwr_changed || !pinst->phy_link->u.osmotrx.powered ||
+ trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
+ return;
- return 0;
+ /* We are already ON and we got new information about nominal power, so
+ * let's make sure we adapt the tx power to it
+ */
+ l1if_trx_start_power_ramp(trx, NULL);
}
-int l1if_provision_transceiver(struct gsm_bts *bts)
+static void l1if_setpower_att_cb(struct trx_l1h *l1h, int power_att_db, int rc)
{
- struct gsm_bts_trx *trx;
- uint8_t tn;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct gsm_bts_trx *trx = pinst->trx;
- llist_for_each_entry(trx, &bts->trx_list, list) {
- struct phy_instance *pinst = trx_phy_instance(trx);
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- l1h->config.trxd_hdr_ver_req = 0;
- l1h->config.trxd_hdr_ver_use = 0;
- l1h->config.setformat_sent = 0;
- 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;
- l1h->config.maxdly_sent = 0;
- l1h->config.maxdlynb_sent = 0;
- for (tn = 0; tn < TRX_NR_TS; tn++)
- l1h->config.slottype_sent[tn] = 0;
- l1if_provision_transceiver_trx(l1h);
- }
- return 0;
+ LOGPPHI(pinst, DL1C, LOGL_DEBUG, "l1if_setpower_att_cb(power_att_db=%d, rc=%d)\n", power_att_db, rc);
+
+ power_trx_change_compl(trx, get_p_max_out_mdBm(trx) - to_mdB(power_att_db));
}
/*
@@ -301,57 +165,43 @@ static int trx_init(struct gsm_bts_trx *trx)
{
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ int rc;
- /* power on transceiver, if not already */
- if (!l1h->config.poweron) {
- l1h->config.poweron = 1;
- l1h->config.poweron_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
-
- if (trx == trx->bts->c0)
- lchan_init_lapdm(&trx->ts[0].lchan[CCCH_LCHAN]);
-
- /* Set to Operational State: Enabled */
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
-
+ rc = osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ENABLE, (void*)(intptr_t)true);
+ if (rc != 0)
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,
+ (void*)(intptr_t)NM_NACK_CANT_PERFORM);
/* Send OPSTART ack */
- return oml_mo_opstart_ack(&trx->mo);
+ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);
}
-/* deactivate transceiver */
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+/* Deact RF on transceiver */
+int bts_model_trx_deact_rf(struct gsm_bts_trx *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 */
- trx_sched_reset(&l1h->l1s);
+ return trx_if_cmd_rfmute(l1h, true);
+}
- /* deactivate lchan for CCCH */
- if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4 ||
- pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) {
- lchan_set_state(&trx->ts[0].lchan[CCCH_LCHAN], LCHAN_S_INACTIVE);
- }
+/* deactivate transceiver */
+void bts_model_trx_close(struct gsm_bts_trx *trx)
+{
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- /* power off transceiver, if not already */
- if (l1h->config.poweron) {
- l1h->config.poweron = 0;
- l1h->config.poweron_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CLOSE, NULL);
/* Set to Operational State: Disabled */
- check_transceiver_availability_trx(l1h, 0);
-
- return 0;
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
-/* on RSL failure, deactivate transceiver */
void bts_model_abis_close(struct gsm_bts *bts)
{
- bts_shutdown(bts, "Abis close");
+ /* Go into shutdown state deactivating transceivers until Abis link
+ * becomes up again */
+ bts_shutdown_ext(bts, "Abis close", false, true);
}
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
@@ -362,23 +212,22 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
}
/* set bts attributes */
-static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr)
+static uint8_t trx_set_bts(struct gsm_bts *bts)
{
- struct gsm_bts_trx *trx;
+ struct phy_instance *pinst = trx_phy_instance(bts->c0);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
uint8_t bsic = bts->bsic;
+ struct gsm_bts_trx *trx;
+
+ /* ARFCN for C0 is assigned during Set BTS Attr, see oml.c */
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void *)(intptr_t)pinst->trx->arfcn);
llist_for_each_entry(trx, &bts->trx_list, list) {
- 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;
- l1h->config.bsic_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
- }
- check_transceiver_availability(bts, transceiver_available);
+ pinst = trx_phy_instance(trx);
+ l1h = pinst->u.osmotrx.hdl;
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_BSIC, (void*)(intptr_t)bsic);
+ }
return 0;
}
@@ -388,21 +237,19 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx)
{
struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ struct phy_link *plink = pinst->phy_link;
uint16_t arfcn = trx->arfcn;
- if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) {
- l1h->config.arfcn = arfcn;
- l1h->config.arfcn_valid = 1;
- l1h->config.arfcn_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
+ /* ARFCN for C0 is assigned during Set BTS Attr, see oml.c */
+ if (trx != trx->bts->c0)
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void *)(intptr_t)arfcn);
- if (l1h->config.power_oml) {
- l1h->config.power = trx->max_power_red;
- l1h->config.power_valid = 1;
- l1h->config.power_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
+ /* Begin to ramp up the power if power reduction is set by OML and TRX
+ is already running. Otherwise skip, power ramping will be started
+ after TRX is running */
+ if (plink->u.osmotrx.powered && l1h->config.forced_max_power_red == -1 &&
+ trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
+ power_ramp_start(pinst->trx, get_p_nominal_mdBm(pinst->trx), 0, NULL);
return 0;
}
@@ -414,20 +261,9 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts,
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;
uint8_t slottype;
int rc;
- /* all TSC of all timeslots must be equal, because transceiver only
- * supports one TSC per TRX */
-
- if (l1h->config.tsc != tsc || !l1h->config.tsc_valid) {
- l1h->config.tsc = tsc;
- l1h->config.tsc_valid = 1;
- l1h->config.tsc_sent = 0;
- l1if_provision_transceiver_trx(l1h);
- }
-
/* ignore disabled slots */
if (!(l1h->config.slotmask & (1 << tn)))
return NM_NACK_RES_NOTAVAIL;
@@ -435,28 +271,46 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts,
/* set physical channel. For dynamic timeslots, the caller should have
* decided on a more specific PCHAN type already. */
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
- rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
+ rc = trx_sched_set_pchan(ts, pchan);
if (rc)
return NM_NACK_RES_NOTAVAIL;
- /* activate lchan for CCCH */
- if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4 ||
- pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) {
+ /* activate lchans for [CBCH/]BCCH/CCCH */
+ switch (pchan) {
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ /* using RSL_CHAN_OSMO_CBCH4 is correct here, because the scheduler
+ * does not distinguish between SDCCH/4+CBCH abd SDCCH/8+CBCH. */
+ trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
+ RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
+ break;
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
+ RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
+ /* fall-through */
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH:
+ trx_sched_set_bcch_ccch(&ts->lchan[CCCH_LCHAN], true);
ts->lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML;
lchan_set_state(&ts->lchan[CCCH_LCHAN], LCHAN_S_ACTIVE);
+ break;
+ default:
+ break;
}
slottype = transceiver_chan_types[pchan];
- if (l1h->config.slottype[tn] != slottype
- || !l1h->config.slottype_valid[tn]) {
- l1h->config.slottype[tn] = slottype;
- l1h->config.slottype_valid[tn] = 1;
- l1h->config.slottype_sent[tn] = 0;
- l1if_provision_transceiver_trx(l1h);
+
+ struct trx_prov_ev_cfg_ts_data data = { .tn = tn, .slottype = slottype };
+ if (ts->tsc_set != 0) {
+ /* On TRXC we use 3GPP compliant numbering, so +1 */
+ data.tsc_set = ts->tsc_set + 1;
+ data.tsc_val = ts->tsc;
+ data.tsc_valid = true;
}
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_TS, &data);
+
return 0;
}
@@ -473,7 +327,7 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts)
pchan = (ts->flags & TS_F_PDCH_ACTIVE)? GSM_PCHAN_PDCH
: GSM_PCHAN_TCH_F;
break;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
OSMO_ASSERT(ts->dyn.pchan_is == ts->dyn.pchan_want);
pchan = ts->dyn.pchan_is;
break;
@@ -491,37 +345,30 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts)
*/
/* enable ciphering */
-static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan,
- uint8_t chan_nr, int downlink)
+static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink)
{
- /* ciphering already enabled in both directions */
- if (lchan->ciph_state == LCHAN_CIPH_RXTX_CONF)
+ /* ignore the request when the channel is not active */
+ if (lchan->state != LCHAN_S_ACTIVE)
return -EINVAL;
if (!downlink) {
/* set uplink */
- trx_sched_set_cipher(&l1h->l1s, chan_nr, 0, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ trx_sched_set_cipher(lchan, chan_nr, false);
lchan->ciph_state = LCHAN_CIPH_RX_CONF;
} else {
/* set downlink and also set uplink, if not already */
- if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) {
- trx_sched_set_cipher(&l1h->l1s, chan_nr, 0,
- lchan->encr.alg_id - 1, lchan->encr.key,
- lchan->encr.key_len);
- }
- trx_sched_set_cipher(&l1h->l1s, chan_nr, 1, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ if (lchan->ciph_state != LCHAN_CIPH_RX_CONF)
+ trx_sched_set_cipher(lchan, chan_nr, false);
+ trx_sched_set_cipher(lchan, chan_nr, true);
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
}
return 0;
}
-static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr,
- enum osmo_mph_info_type type, uint8_t cause)
+static int mph_info_chan_confirm(struct gsm_bts_trx *trx, 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));
@@ -531,7 +378,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(pinst->trx, &l1sap);
+ return l1sap_up(trx, &l1sap);
}
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
@@ -550,45 +397,9 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
return l1sap_up(bts->c0, &l1sap);
}
-
-static void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, int16_t toa256,
- float ber, float rssi, uint32_t fn)
-{
- memset(l1sap, 0, sizeof(*l1sap));
- osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
- l1sap->u.info.type = PRIM_INFO_MEAS;
- l1sap->u.info.u.meas_ind.chan_nr = chan_nr;
- l1sap->u.info.u.meas_ind.ta_offs_256bits = toa256;
- l1sap->u.info.u.meas_ind.ber10k = (unsigned int) (ber * 10000);
- l1sap->u.info.u.meas_ind.inv_rssi = (uint8_t) (rssi * -1);
- l1sap->u.info.u.meas_ind.fn = fn;
-}
-
-int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
- int n_errors, int n_bits_total, float rssi, int16_t toa256)
-{
- struct gsm_lchan *lchan = &trx->ts[tn].lchan[l1sap_chan2ss(chan_nr)];
- struct osmo_phsap_prim l1sap;
- /* 100% BER is n_bits_total is 0 */
- float ber = n_bits_total==0 ? 1.0 : (float)n_errors / (float)n_bits_total;
-
- LOGPFN(DMEAS, LOGL_DEBUG, fn, "RX UL measurement for %s fn=%u chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
- "ber=%.2f%% (%d/%d bits) L1_ta=%d rqd_ta=%d toa256=%d\n",
- gsm_lchan_name(lchan), fn, chan_nr, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power_ctrl.current),
- rssi, ber*100, n_errors, n_bits_total, lchan->meas.l1_info[1], lchan->rqd_ta, toa256);
-
- l1if_fill_meas_res(&l1sap, chan_nr, toa256, ber, rssi, fn);
-
- return l1sap_up(trx, &l1sap);
-}
-
-
/* primitive from common part */
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
- 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;
int rc = 0;
@@ -599,117 +410,115 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_ph_data_req(&l1h->l1s, l1sap);
+ return trx_sched_ph_data_req(trx, l1sap);
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_tch_req(&l1h->l1s, l1sap);
+ return trx_sched_tch_req(trx, l1sap);
case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST):
switch (l1sap->u.info.type) {
case PRIM_INFO_ACT_CIPH:
chan_nr = l1sap->u.info.u.ciph_req.chan_nr;
- lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ break;
+ case PRIM_INFO_ACT_UL_ACC:
+ case PRIM_INFO_DEACT_UL_ACC:
+ chan_nr = l1sap->u.info.u.ulacc_req.chan_nr;
+ break;
+ default:
+ /* u.act_req used by PRIM_INFO_{ACTIVATE,DEACTIVATE,MODIFY} */
+ chan_nr = l1sap->u.info.u.act_req.chan_nr;
+ }
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ if (OSMO_UNLIKELY(lchan == NULL)) {
+ LOGP(DL1C, LOGL_ERROR,
+ "Rx MPH-INFO.req (type=0x%02x) for non-existent lchan (%s)\n",
+ l1sap->u.info.type, rsl_chan_nr_str(chan_nr));
+ rc = -ENODEV;
+ break;
+ }
+
+ switch (l1sap->u.info.type) {
+ case PRIM_INFO_ACT_CIPH:
if (l1sap->u.info.u.ciph_req.uplink)
- l1if_set_ciphering(l1h, lchan, chan_nr, 0);
+ l1if_set_ciphering(lchan, chan_nr, 0);
if (l1sap->u.info.u.ciph_req.downlink)
- l1if_set_ciphering(l1h, lchan, chan_nr, 1);
+ l1if_set_ciphering(lchan, chan_nr, 1);
+ break;
+ case PRIM_INFO_ACT_UL_ACC:
+ trx_sched_set_ul_access(lchan, chan_nr, true);
+ break;
+ case PRIM_INFO_DEACT_UL_ACC:
+ trx_sched_set_ul_access(lchan, chan_nr, false);
break;
case PRIM_INFO_ACTIVATE:
- case PRIM_INFO_DEACTIVATE:
- case PRIM_INFO_MODIFY:
- chan_nr = l1sap->u.info.u.act_req.chan_nr;
- lchan = get_lchan_by_chan_nr(trx, chan_nr);
- if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) {
- if ((chan_nr & 0xE0) == 0x80) {
- LOGP(DL1C, LOGL_ERROR, "Cannot activate"
- " chan_nr 0x%02x\n", chan_nr);
- break;
- }
-
- /* attempt to allocate an Error Concealment Unit instance, if available */
- lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
-
- /* trx_chan_desc[] in scheduler.c uses the RSL_CHAN_OSMO_PDCH cbits
- * (0xc0) to indicate the need for PDTCH and PTCCH SAPI activation.
- * However, 0xc0 is a cbits pattern exclusively used for Osmocom style
- * dyn TS (a non-standard RSL Chan Activ mod); hence, for IPA style dyn
- * TS, the chan_nr will never reflect 0xc0 and we would omit the
- * PDTCH,PTTCH SAPIs. To properly de-/activate the PDTCH SAPIs in
- * scheduler.c, make sure the 0xc0 cbits are set for de-/activating PDTCH
- * lchans, i.e. both Osmocom and IPA style dyn TS. (For Osmocom style dyn
- * TS, the chan_nr typically already reflects 0xc0, while it doesn't for
- * IPA style.) */
- if (lchan->type == GSM_LCHAN_PDTCH)
- chan_nr = RSL_CHAN_OSMO_PDCH | (chan_nr & ~RSL_CHAN_NR_MASK);
-
- /* activate dedicated channel */
- trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_DEDIC, 1);
- /* activate associated channel */
- trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_SACCH, 1);
- /* set mode */
- trx_sched_set_mode(&l1h->l1s, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- (lchan->ho.active == 1));
- /* init lapdm */
- lchan_init_lapdm(lchan);
- /* set lchan active */
- lchan_set_state(lchan, LCHAN_S_ACTIVE);
- /* set initial ciphering */
- l1if_set_ciphering(l1h, lchan, chan_nr, 0);
- l1if_set_ciphering(l1h, lchan, chan_nr, 1);
- if (lchan->encr.alg_id)
- lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
- else
- lchan->ciph_state = LCHAN_CIPH_NONE;
-
- /* confirm */
- mph_info_chan_confirm(l1h, chan_nr,
- PRIM_INFO_ACTIVATE, 0);
- break;
- }
- if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
- /* ECU for possibly new codec */
- if (lchan->ecu_state)
- osmo_ecu_destroy(lchan->ecu_state);
- lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
- /* change mode */
- trx_sched_set_mode(&l1h->l1s, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- 0);
+ if ((chan_nr & 0xE0) == 0x80) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot activate"
+ " channel %s\n", rsl_chan_nr_str(chan_nr));
+ rc = -EPERM;
break;
}
- /* here, type == PRIM_INFO_DEACTIVATE */
+
+ /* activate dedicated channel */
+ trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true);
+ /* activate associated channel */
+ trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true);
+ /* set mode */
+ trx_sched_set_mode(lchan->ts, chan_nr,
+ lchan->rsl_cmode, lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.mode[0].mode,
+ lchan->tch.amr_mr.mode[1].mode,
+ lchan->tch.amr_mr.mode[2].mode,
+ lchan->tch.amr_mr.mode[3].mode,
+ amr_get_initial_mode(lchan),
+ (lchan->ho.active == HANDOVER_ENABLED));
+ /* set lchan active */
+ lchan_set_state(lchan, LCHAN_S_ACTIVE);
+ /* set initial ciphering */
+ l1if_set_ciphering(lchan, chan_nr, 0);
+ l1if_set_ciphering(lchan, chan_nr, 1);
+ if (lchan->encr.alg_id)
+ lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
+ else
+ lchan->ciph_state = LCHAN_CIPH_NONE;
+
+ /* confirm */
+ mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_ACTIVATE, 0);
+ break;
+ case PRIM_INFO_MODIFY:
+ /* change mode */
+ trx_sched_set_mode(lchan->ts, chan_nr,
+ lchan->rsl_cmode, lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.mode[0].mode,
+ lchan->tch.amr_mr.mode[1].mode,
+ lchan->tch.amr_mr.mode[2].mode,
+ lchan->tch.amr_mr.mode[3].mode,
+ amr_get_initial_mode(lchan),
+ 0);
+ /* update ciphering params */
+ l1if_set_ciphering(lchan, chan_nr, 0);
+ l1if_set_ciphering(lchan, chan_nr, 1);
+ if (lchan->encr.alg_id)
+ lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
+ else
+ lchan->ciph_state = LCHAN_CIPH_NONE;
+ break;
+ case PRIM_INFO_DEACTIVATE:
if ((chan_nr & 0xE0) == 0x80) {
- LOGP(DL1C, LOGL_ERROR, "Cannot deactivate "
- "chan_nr 0x%02x\n", chan_nr);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot deactivate"
+ " channel %s\n", rsl_chan_nr_str(chan_nr));
+ rc = -EPERM;
break;
}
- /* clear ECU state (if any) */
- if (lchan->ecu_state) {
- osmo_ecu_destroy(lchan->ecu_state);
- lchan->ecu_state = NULL;
- }
/* deactivate associated channel */
bts_model_lchan_deactivate_sacch(lchan);
if (!l1sap->u.info.u.act_req.sacch_only) {
/* deactivate dedicated channel */
lchan_deactivate(lchan);
/* confirm only on dedicated channel */
- mph_info_chan_confirm(l1h, chan_nr,
- PRIM_INFO_DEACTIVATE, 0);
+ mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0);
}
break;
default:
@@ -747,48 +556,51 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
}
/* callback from OML */
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- int cause = 0;
+ int rc;
switch (foh->msg_type) {
case NM_MT_SET_BTS_ATTR:
- cause = trx_set_bts(obj, new_attr);
+ rc = trx_set_bts(obj);
break;
case NM_MT_SET_RADIO_ATTR:
- cause = trx_set_trx(obj);
+ rc = trx_set_trx(obj);
break;
case NM_MT_SET_CHAN_ATTR:
- cause = trx_set_ts(obj);
+ rc = trx_set_ts(obj);
+ break;
+ default:
+ rc = 0;
break;
}
- return oml_fom_ack_nack(msg, cause);
+ return rc;
}
/* callback from OML */
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj)
{
+ struct gsm_bts_trx *trx;
int rc;
- LOGP(DOML, LOGL_DEBUG, "bts_model_opstart: %s received\n",
- get_value_string(abis_nm_obj_class_names, mo->obj_class));
+
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- /* activate transceiver */
- rc = trx_init(obj);
- break;
- case NM_OC_CHANNEL:
- case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
+ case NM_OC_BTS:
case NM_OC_BASEB_TRANSC:
+ case NM_OC_CHANNEL:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
- rc = oml_mo_opstart_ack(mo);
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
+ break;
+ case NM_OC_RADIO_CARRIER:
+ /* activate transceiver */
+ trx = (struct gsm_bts_trx *) obj;
+ rc = trx_init(trx);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -796,17 +608,91 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
return rc;
}
-int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
- void *obj, uint8_t adm_state)
+static void bts_model_chg_adm_state_ramp_compl_cb(struct gsm_bts_trx *trx)
{
- /* blindly accept all state changes */
- mo->nm_state.administrative = adm_state;
- return oml_mo_statechg_ack(mo);
+ LOGPTRX(trx, DL1C, LOGL_INFO, "power ramp due to ADM STATE change finished\n");
+ trx->mo.procedure_pending = 0;
+ if (trx->mo.nm_state.administrative == NM_STATE_LOCKED) {
+ bts_model_trx_deact_rf(trx);
+ pcu_tx_info_ind();
+ }
}
-int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
+int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
+ void *obj, uint8_t adm_state)
{
- return 0;
+ struct gsm_bts_trx *trx;
+ struct phy_instance *pinst;
+ struct trx_l1h *l1h;
+ int rc = 0;
+
+ switch (mo->obj_class) {
+ case NM_OC_RADIO_CARRIER:
+ trx = (struct gsm_bts_trx *) obj;
+ pinst = trx_phy_instance(trx);
+ l1h = pinst->u.osmotrx.hdl;
+
+ /* Begin to ramp the power if TRX is already running. Otherwise
+ * skip, power ramping will be started after TRX is running.
+ * We still want to make sure to update RFMUTE status on the
+ * other side. */
+ if (!pinst->phy_link->u.osmotrx.powered) {
+ trx_if_cmd_rfmute(l1h, adm_state != NM_STATE_UNLOCKED);
+ break;
+ }
+
+ if (mo->procedure_pending) {
+ LOGPTRX(trx, DL1C, LOGL_INFO,
+ "ADM change received while previous one still WIP\n");
+
+ if (mo->nm_state.administrative == NM_STATE_LOCKED &&
+ adm_state == NM_STATE_UNLOCKED) {
+ /* Previous change was UNLOCKED->LOCKED, so we
+ * were ramping down and we didn't mute RF
+ * yet, so now simply skip old ramp down compl
+ * cb, skip RF unmute and go for ramp up
+ * directly. */
+ goto ramp_up;
+ } else if (mo->nm_state.administrative == NM_STATE_UNLOCKED &&
+ adm_state == NM_STATE_LOCKED) {
+ /* Previous change was LOCKED->UNLOCKED, so we
+ * simply need to skip ramping up and start
+ * ramping down instead, muting RF at the
+ * end as usual. Fall through usual procedure
+ * below. */
+ } else if (mo->nm_state.administrative == adm_state) {
+ OSMO_ASSERT(0);
+ }
+ }
+ switch (adm_state) {
+ case NM_STATE_LOCKED:
+ mo->procedure_pending = 1;
+ rc = power_ramp_start(trx, RF_DISABLED_mdB, 1, bts_model_chg_adm_state_ramp_compl_cb);
+ break;
+ case NM_STATE_UNLOCKED:
+ mo->procedure_pending = 1;
+ trx_if_cmd_rfmute(l1h, false);
+ramp_up:
+ rc = l1if_trx_start_power_ramp(trx, bts_model_chg_adm_state_ramp_compl_cb);
+ if (rc == 0) {
+ mo->nm_state.administrative = adm_state;
+ pcu_tx_info_ind();
+ return oml_mo_statechg_ack(mo);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (rc == 0) {
+ mo->nm_state.administrative = adm_state;
+ return oml_mo_statechg_ack(mo);
+ } else
+ return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT);
}
int bts_model_oml_estab(struct gsm_bts *bts)
@@ -816,9 +702,10 @@ int bts_model_oml_estab(struct gsm_bts *bts)
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
{
-#warning "implement bts_model_change_power\n"
- LOGP(DL1C, LOGL_NOTICE, "Setting TRX output power not supported!\n");
- return 0;
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ int power_att = (get_p_max_out_mdBm(trx) - p_trxout_mdBm) / 1000;
+ return trx_if_cmd_setpower_att(l1h, power_att, l1if_setpower_att_cb);
}
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index 87df951b..84fd4b5b 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -1,58 +1,129 @@
#ifndef L1_IF_H_TRX
#define L1_IF_H_TRX
+#include <osmocom/core/rate_ctr.h>
+
#include <osmo-bts/scheduler.h>
#include <osmo-bts/phy_link.h>
#include "trx_if.h"
+/*
+ * TRX frame clock handling
+ *
+ * In a "normal" synchronous PHY layer, we would be polled every time
+ * the PHY needs data for a given frame number. However, the
+ * OpenBTS-inherited TRX protocol works differently: We (L1) must
+ * autonomously send burst data based on our own clock, and every so
+ * often (currently every ~ 216 frames), we get a clock indication from
+ * the TRX.
+ *
+ * We're using a MONOTONIC timerfd interval timer for the 4.615ms frame
+ * intervals, and then compute + send the 8 bursts for that frame.
+ *
+ * Upon receiving a clock indication from the TRX, we compensate
+ * accordingly: If we were transmitting too fast, we're delaying the
+ * next interval timer accordingly. If we were too slow, we immediately
+ * send burst data for the missing frame numbers.
+ */
+
+/* bts-trx specific rate counters */
+enum {
+ BTSTRX_CTR_SCHED_DL_MISS_FN,
+ BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER,
+ BTSTRX_CTR_SCHED_DL_FH_CACHE_MISS,
+ BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER,
+};
+
+/*! clock state of a given TRX */
+struct osmo_trx_clock_state {
+ /*! number of FN periods without TRX clock indication */
+ uint32_t fn_without_clock_ind;
+ struct {
+ /*! last FN we processed based on FN period timer */
+ uint32_t fn;
+ /*! time at which we last processed FN */
+ struct timespec tv;
+ } last_fn_timer;
+ struct {
+ /*! last FN we received a clock indication for */
+ uint32_t fn;
+ /*! time at which we received the last clock indication */
+ struct timespec tv;
+ } last_clk_ind;
+ /*! Osmocom FD wrapper for timerfd */
+ struct osmo_fd fn_timer_ofd;
+};
+
+/* gsm_bts->model_priv, specific to osmo-bts-trx */
+struct bts_trx_priv {
+ struct osmo_trx_clock_state clk_s;
+ struct rate_ctr_group *ctrs; /* bts-trx specific rate counters */
+};
+
struct trx_config {
- uint8_t trxd_hdr_ver_req; /* requested TRXD header version */
- uint8_t trxd_hdr_ver_use; /* actual TRXD header version in use */
- int setformat_sent;
+ uint8_t trxd_pdu_ver_req; /* requested TRXD PDU version */
+ uint8_t trxd_pdu_ver_use; /* actual TRXD PDU version in use */
+ bool setformat_sent;
+ bool setformat_acked;
+
+ bool enabled;
- uint8_t poweron; /* poweron(1) or poweroff(0) */
- int poweron_sent;
- int arfcn_valid;
+ bool arfcn_valid;
uint16_t arfcn;
- int arfcn_sent;
+ bool rxtune_sent;
+ bool rxtune_acked;
+ bool txtune_sent;
+ bool txtune_acked;
- int tsc_valid;
+ bool tsc_valid;
uint8_t tsc;
- int tsc_sent;
+ bool tsc_sent;
+ bool tsc_acked;
- int bsic_valid;
+ bool bsic_valid;
uint8_t bsic;
- int bsic_sent;
+ bool bsic_sent;
+ bool bsic_acked;
- int rxgain_valid;
+ bool rxgain_valid;
uint8_t rxgain;
- int rxgain_sent;
+ bool rxgain_sent;
- int power_valid;
- uint8_t power;
- int power_oml;
- int power_sent;
+ int forced_max_power_red; /* -1 if not forced by VTY config (default) */
- int maxdly_valid;
+ bool nominal_power_set_by_vty; /* whether nominal trx power was enforced/retreived from VTY config "nominal-tx-power" */
+ bool nomtxpower_sent;
+ bool nomtxpower_acked;
+
+ bool maxdly_valid;
int maxdly;
- int maxdly_sent;
+ bool maxdly_sent;
- int maxdlynb_valid;
+ bool maxdlynb_valid;
int maxdlynb;
- int maxdlynb_sent;
+ bool maxdlynb_sent;
uint8_t slotmask;
- int slottype_valid[TRX_NR_TS];
- uint8_t slottype[TRX_NR_TS];
- int slottype_sent[TRX_NR_TS];
+ bool setslot_valid[TRX_NR_TS];
+ struct {
+ uint8_t slottype;
+ uint8_t tsc_set;
+ uint8_t tsc_val;
+ bool tsc_valid;
+ } setslot[TRX_NR_TS];
+ bool setslot_sent[TRX_NR_TS];
};
struct trx_l1h {
struct llist_head trx_ctrl_list;
/* Latest RSPed cmd, used to catch duplicate RSPs from sent retransmissions */
struct trx_ctrl_msg *last_acked;
+ /* Whether the code path is in the middle of handling a received message. */
+ bool in_trx_ctrl_read_cb;
+ /* Whether the l1h->trx_ctrl_list was flushed by the callback handling a received message */
+ bool flushed_while_in_trx_ctrl_read_cb;
//struct gsm_bts_trx *trx;
struct phy_instance *phy_inst;
@@ -63,23 +134,14 @@ struct trx_l1h {
/* transceiver config */
struct trx_config config;
-
- struct l1sched_trx l1s;
+ struct osmo_fsm_inst *provision_fi;
};
struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst);
-int check_transceiver_availability(struct gsm_bts *bts, int avail);
int l1if_provision_transceiver_trx(struct trx_l1h *l1h);
-int l1if_provision_transceiver(struct gsm_bts *bts);
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn);
-int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
- int n_errors, int n_bits_total, float rssi, int16_t toa256);
-
-static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
-{
- struct phy_instance *pinst = trx->role_bts.l1h;
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- return &l1h->l1s;
-}
+void l1if_trx_set_nominal_power(struct gsm_bts_trx *trx, int nominal_power);
+int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb);
+enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type);
#endif /* L1_IF_H_TRX */
diff --git a/src/osmo-bts-trx/loops.c b/src/osmo-bts-trx/loops.c
deleted file mode 100644
index 3fa2b3b4..00000000
--- a/src/osmo-bts-trx/loops.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/* Loop control for OsmoBTS-TRX */
-
-/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * 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 <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <osmo-bts/gsm_data.h>
-#include <osmo-bts/logging.h>
-#include <osmo-bts/l1sap.h>
-#include <osmocom/core/bits.h>
-
-#include "trx_if.h"
-#include "l1_if.h"
-#include "loops.h"
-
-/*
- * MS Power loop
- */
-
-/*! compute the new MS POWER LEVEL communicated to the MS and store it in lchan.
- * \param lchan logical channel for which to compute (and in which to store) new power value.
- * \param[in] diff input delta value (in dB) */
-static void ms_power_diff(struct gsm_lchan *lchan, int8_t diff)
-{
- struct gsm_bts_trx *trx = lchan->ts->trx;
- enum gsm_band band = trx->bts->band;
- uint16_t arfcn = trx->arfcn;
- int8_t new_power;
-
- /* compute new target MS output power level based on current value subtracted by 'diff/2' */
- new_power = lchan->ms_power_ctrl.current - (diff >> 1);
-
- if (diff == 0)
- return;
-
- /* ms transmit power level cannot become negative */
- if (new_power < 0)
- new_power = 0;
-
- /* saturate at the maximum possible power level for the given band */
- // FIXME: to go above 1W, we need to know classmark of MS
- if (arfcn >= 512 && arfcn <= 885) {
- if (new_power > 15)
- new_power = 15;
- } else {
- if (new_power > 19)
- new_power = 19;
- }
-
- /* don't ever change more than MS_{LOWER,RAISE}_MAX during one loop iteration, i.e.
- * reduce the speed at which the MS transmit power can change */
- /* a higher value means a lower level (and vice versa) */
- if (new_power > lchan->ms_power_ctrl.current + MS_LOWER_MAX)
- new_power = lchan->ms_power_ctrl.current + MS_LOWER_MAX;
- else if (new_power < lchan->ms_power_ctrl.current - MS_RAISE_MAX)
- new_power = lchan->ms_power_ctrl.current - MS_RAISE_MAX;
-
- if (lchan->ms_power_ctrl.current == new_power) {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS new_power at control level %d (%d dBm)\n",
- new_power, ms_pwr_dbm(band, new_power));
- } else {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "%s MS new_power from control level %d (%d dBm) to %d (%d dBm)\n",
- (diff > 0) ? "Raising" : "Lowering",
- lchan->ms_power_ctrl.current, ms_pwr_dbm(band, lchan->ms_power_ctrl.current),
- new_power, ms_pwr_dbm(band, new_power));
-
- /* store the resulting new MS power level in the lchan */
- lchan->ms_power_ctrl.current = new_power;
- }
-}
-
-/*! Input a new RSSI value into the MS power control loop for the given logical channel.
- * \param lchan logical channel
- * \param chan_state L1 channel state of the logical channel.
- * \param rssi Received Signal Strength Indication (in dBm) */
-static void ms_power_val(struct gsm_lchan *lchan, struct l1sched_chan_state *chan_state, int8_t rssi)
-{
- /* ignore inserted dummy frames, treat as lost frames */
- if (rssi < -127)
- return;
-
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Got RSSI value of %d\n", rssi);
-
- chan_state->meas.rssi_count++;
-
- chan_state->meas.rssi_got_burst = 1;
-
- /* store and process RSSI */
- if (chan_state->meas.rssi_valid_count == ARRAY_SIZE(chan_state->meas.rssi))
- return;
- chan_state->meas.rssi[chan_state->meas.rssi_valid_count++] = rssi;
-}
-
-/*! Process a single clock tick of the MS power control loop.
- * \param lchan Logical channel to which the clock tick applies */
-static void ms_power_clock(struct gsm_lchan *lchan, struct l1sched_chan_state *chan_state)
-{
- struct gsm_bts_trx *trx = lchan->ts->trx;
- struct phy_instance *pinst = trx_phy_instance(trx);
- int rssi;
- int i;
-
- /* skip every second clock, to prevent oscillating due to roundtrip
- * delay */
- if (!(chan_state->meas.clock & 1))
- return;
-
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Got SACCH master clock at RSSI count %d\n",
- chan_state->meas.rssi_count);
-
- /* wait for initial burst */
- if (!chan_state->meas.rssi_got_burst)
- return;
-
- /* if no burst was received from MS at clock */
- if (chan_state->meas.rssi_count == 0) {
- LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE, "LOST SACCH frame, so we raise MS power\n");
- ms_power_diff(lchan, MS_RAISE_MAX);
- return;
- }
-
- /* reset total counter */
- chan_state->meas.rssi_count = 0;
-
- /* check the minimum level received after MS acknowledged the ordered
- * power level */
- if (chan_state->meas.rssi_valid_count == 0)
- return;
- for (rssi = 999, i = 0; i < chan_state->meas.rssi_valid_count; i++) {
- if (rssi > chan_state->meas.rssi[i])
- rssi = chan_state->meas.rssi[i];
- }
-
- /* reset valid counter */
- chan_state->meas.rssi_valid_count = 0;
-
- /* change RSSI */
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Lowest RSSI: %d Target RSSI: %d Current "
- "MS power: %d (%d dBm)\n", rssi,
- pinst->phy_link->u.osmotrx.trx_target_rssi, lchan->ms_power_ctrl.current,
- ms_pwr_dbm(trx->bts->band, lchan->ms_power_ctrl.current));
- ms_power_diff(lchan, pinst->phy_link->u.osmotrx.trx_target_rssi - rssi);
-}
-
-
-/* 90% of one bit duration in 1/256 symbols: 256*0.9 */
-#define TOA256_9OPERCENT 230
-
-/*
- * Timing Advance loop
- */
-
-void ta_val(struct gsm_lchan *lchan, struct l1sched_chan_state *chan_state, int16_t toa256)
-{
- /* check if the current L1 header acks to the current ordered TA */
- if (lchan->meas.l1_info[1] != lchan->rqd_ta)
- return;
-
- /* sum measurement */
- chan_state->meas.toa256_sum += toa256;
- if (++(chan_state->meas.toa_num) < 16)
- return;
-
- /* complete set */
- toa256 = chan_state->meas.toa256_sum / chan_state->meas.toa_num;
-
- /* check for change of TOA */
- if (toa256 < -TOA256_9OPERCENT && lchan->rqd_ta > 0) {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "TOA is too early (%d), now lowering TA from %d to %d\n",
- toa256, lchan->rqd_ta, lchan->rqd_ta - 1);
- lchan->rqd_ta--;
- } else if (toa256 > TOA256_9OPERCENT && lchan->rqd_ta < 63) {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "TOA is too late (%d), now raising TA from %d to %d\n",
- toa256, lchan->rqd_ta, lchan->rqd_ta + 1);
- lchan->rqd_ta++;
- } else
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "TOA is correct (%d), keeping current TA of %d\n",
- toa256, lchan->rqd_ta);
-
- chan_state->meas.toa_num = 0;
- chan_state->meas.toa256_sum = 0;
-}
-
-/*! Process a SACCH event as input to the MS power control and TA loop. Function
- * is called once every uplink SACCH block is received.
- * \param l1t L1 TRX instance on which we operate
- * \param chan_nr RSL channel number on which we operate
- * \param chan_state L1 scheduler channel state of the channel on which we operate
- * \param[in] rssi Receive Signal Strength Indication
- * \param[in] toa256 Time of Arrival in 1/256 symbol periods */
-void trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state, int8_t rssi, int16_t toa256)
-{
- struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)]
- .lchan[l1sap_chan2ss(chan_nr)];
- struct phy_instance *pinst = trx_phy_instance(l1t->trx);
-
- /* if MS power control loop is enabled, handle it */
- if (pinst->phy_link->u.osmotrx.trx_ms_power_loop)
- ms_power_val(lchan, chan_state, rssi);
-
- /* if TA loop is enabled, handle it */
- if (pinst->phy_link->u.osmotrx.trx_ta_loop)
- ta_val(lchan, chan_state, toa256);
-}
-
-/*! Called once every downlink SACCH block needs to be sent. */
-void trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state)
-{
- struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)]
- .lchan[l1sap_chan2ss(chan_nr)];
- struct phy_instance *pinst = trx_phy_instance(l1t->trx);
-
- if (lchan->ms_power_ctrl.fixed)
- return;
-
- if (pinst->phy_link->u.osmotrx.trx_ms_power_loop)
- ms_power_clock(lchan, chan_state);
-
- /* count the number of SACCH clocks */
- chan_state->meas.clock++;
-}
-
-void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state, float ber)
-{
- struct gsm_bts_trx *trx = l1t->trx;
- struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)]
- .lchan[l1sap_chan2ss(chan_nr)];
-
- /* check if loop is enabled */
- if (!chan_state->amr_loop)
- return;
-
- /* wait for MS to use the requested codec */
- if (chan_state->ul_ft != chan_state->dl_cmr)
- return;
-
- /* count bit errors */
- if (L1SAP_IS_CHAN_TCHH(chan_nr)) {
- chan_state->ber_num += 2;
- chan_state->ber_sum += (ber + ber);
- } else {
- chan_state->ber_num++;
- chan_state->ber_sum += ber;
- }
-
- /* count frames */
- if (chan_state->ber_num < 48)
- return;
-
- /* calculate average (reuse ber variable) */
- ber = chan_state->ber_sum / chan_state->ber_num;
-
- /* reset bit errors */
- chan_state->ber_num = 0;
- chan_state->ber_sum = 0;
-
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Current bit error rate (BER) %.6f "
- "codec id %d\n", ber, chan_state->ul_ft);
-
- /* degrade */
- if (chan_state->dl_cmr > 0) {
- /* degrade, if ber is above threshold FIXME: C/I */
- if (ber >
- lchan->tch.amr_mr.bts_mode[chan_state->dl_cmr-1].threshold) {
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Degrading due to BER %.6f "
- "from codec id %d to %d\n", ber, chan_state->dl_cmr,
- chan_state->dl_cmr - 1);
- chan_state->dl_cmr--;
- }
- } else if (chan_state->dl_cmr < chan_state->codecs - 1) {
- /* degrade, if ber is above threshold FIXME: C/I*/
- if (ber <
- lchan->tch.amr_mr.bts_mode[chan_state->dl_cmr].threshold
- - lchan->tch.amr_mr.bts_mode[chan_state->dl_cmr].hysteresis) {
- LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Upgrading due to BER %.6f "
- "from codec id %d to %d\n", ber, chan_state->dl_cmr,
- chan_state->dl_cmr + 1);
- chan_state->dl_cmr++;
- }
- }
-}
-
-void trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop)
-{
- if (chan_state->amr_loop && !loop) {
- chan_state->amr_loop = 0;
- return;
- }
-
- if (!chan_state->amr_loop && loop) {
- chan_state->amr_loop = 1;
-
- /* reset bit errors */
- chan_state->ber_num = 0;
- chan_state->ber_sum = 0;
-
- return;
- }
-}
diff --git a/src/osmo-bts-trx/loops.h b/src/osmo-bts-trx/loops.h
deleted file mode 100644
index 50a658d0..00000000
--- a/src/osmo-bts-trx/loops.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _TRX_LOOPS_H
-#define _TRX_LOOPS_H
-
-/*
- * calibration of loops
- */
-
-/* how much power levels do we raise/lower as maximum (1 level = 2 dB) */
-#define MS_RAISE_MAX 4
-#define MS_LOWER_MAX 2
-
-/*
- * loops api
- */
-
-void trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state, int8_t rssi, int16_t toa);
-
-void trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state);
-
-void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
- struct l1sched_chan_state *chan_state, float ber);
-
-void trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop);
-
-#endif /* _TRX_LOOPS_H */
diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c
index b1fa2079..ddc44285 100644
--- a/src/osmo-bts-trx/main.c
+++ b/src/osmo-bts-trx/main.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -43,6 +43,8 @@
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stats.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
@@ -59,8 +61,34 @@
#include "l1_if.h"
#include "trx_if.h"
+static const struct rate_ctr_desc btstrx_ctr_desc[] = {
+ [BTSTRX_CTR_SCHED_DL_MISS_FN] = {
+ "trx_clk:sched_dl_miss_fn",
+ "Downlink frames scheduled later than expected due to missed timerfd event (due to high system load)"
+ },
+ [BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER] = {
+ "trx_sched:dl_fh_no_carrier",
+ "Frequency hopping: no carrier found for a Downlink burst (check hopping parameters)"
+ },
+ [BTSTRX_CTR_SCHED_DL_FH_CACHE_MISS] = {
+ "trx_sched:dl_fh_cache_miss",
+ "Frequency hopping: no Downlink carrier found in cache (lookup performed)"
+ },
+ [BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER] = {
+ "trx_sched:ul_fh_no_carrier",
+ "Frequency hopping: no carrier found for an Uplink burst (check hopping parameters)"
+ },
+};
+static const struct rate_ctr_group_desc btstrx_ctrg_desc = {
+ "bts-trx",
+ "osmo-bts-trx specific counters",
+ OSMO_STATS_CLASS_GLOBAL,
+ ARRAY_SIZE(btstrx_ctr_desc),
+ btstrx_ctr_desc
+};
+
/* dummy, since no direct dsp support */
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
return 0;
}
@@ -97,29 +125,85 @@ int bts_model_handle_options(int argc, char **argv)
int bts_model_init(struct gsm_bts *bts)
{
+ struct bts_trx_priv *bts_trx = talloc_zero(bts, struct bts_trx_priv);
+ bts_trx->clk_s.fn_timer_ofd.fd = -1;
+ bts_trx->ctrs = rate_ctr_group_alloc(bts_trx, &btstrx_ctrg_desc, 0);
+
+ bts->model_priv = bts_trx;
bts->variant = BTS_OSMO_TRX;
- bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
+ bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3) | CIPHER_A5(4);
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
+ | NM_IPAC_MASK_GPRS_CODING_MCS;
- /* FIXME: this needs to be overridden with the real hardrware
- * value */
+ /* The nominal value for each TRX is later overwritten through VTY cmd
+ * 'nominal-tx-power' if present, otherwise through TRXC cmd NOMTXPOWER.
+ */
bts->c0->nominal_power = 23;
- gsm_bts_set_feature(bts, BTS_FEAT_GPRS);
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_EFR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_CBCH);
-
- bts_model_vty_init(bts);
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_ACCH_REP);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_ACCH_TEMP_OVP);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_BCCH_POWER_RED);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_HOPPING);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_MULTI_TSC);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_EFR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VAMOS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VGCS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_VBS);
+
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB);
+ bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_INTERF_MEAS);
+
+ /* The default HR codec output format in the absence of saved
+ * vty config needs to match what was implemented previously,
+ * for the sake of existing deployments, i.e., to avoid
+ * a surprise functional change upon software update. */
+ bts->emit_hr_rfc5993 = true;
+
+ /* For the same reason as the above, rtp internal-uplink-ecu
+ * needs to be enabled by default on osmo-bts-trx model only. */
+ bts->use_ul_ecu = true;
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = NM_IPAC_F_FREQ_BAND_PGSM
+ | NM_IPAC_F_FREQ_BAND_EGSM
+ | NM_IPAC_F_FREQ_BAND_RGSM
+ | NM_IPAC_F_FREQ_BAND_DCS
+ | NM_IPAC_F_FREQ_BAND_PCS
+ | NM_IPAC_F_FREQ_BAND_850
+ | NM_IPAC_F_FREQ_BAND_480
+ | NM_IPAC_F_FREQ_BAND_450;
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH
+ | NM_IPAC_MASK_CHANM_CSD_NT
+ | NM_IPAC_MASK_CHANM_CSD_T;
+ /* TODO: missing rate adaptation for TCH/F14.4 (see OS#6167) */
+ trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_T_14k4;
+ trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_NT_14k4;
+
+ /* The nominal value for each TRX is later overwritten through VTY cmd
+ * 'nominal-tx-power' if present, otherwise through TRXC cmd NOMTXPOWER.
+ */
+ l1if_trx_set_nominal_power(trx, trx->bts->c0->nominal_power);
return 0;
}
@@ -129,13 +213,10 @@ void bts_model_phy_link_set_defaults(struct phy_link *plink)
plink->u.osmotrx.remote_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.trx_ta_loop = true;
- plink->u.osmotrx.trx_ms_power_loop = false;
- plink->u.osmotrx.trx_target_rssi = -10;
+ plink->u.osmotrx.clock_advance = 2;
+ plink->u.osmotrx.rts_advance = 3;
/* attempt use newest TRXD version by default: */
- plink->u.osmotrx.trxd_hdr_ver_max = TRX_DATA_FORMAT_VER;
+ plink->u.osmotrx.trxd_pdu_ver_max = TRX_DATA_PDU_VER;
}
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
@@ -144,7 +225,7 @@ void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
l1h = trx_l1h_alloc(tall_bts_ctx, pinst);
pinst->u.osmotrx.hdl = l1h;
- l1h->config.power_oml = 1;
+ l1h->config.forced_max_power_red = -1;
}
int main(int argc, char **argv)
diff --git a/src/osmo-bts-trx/probes.d b/src/osmo-bts-trx/probes.d
new file mode 100644
index 00000000..2f905bd1
--- /dev/null
+++ b/src/osmo-bts-trx/probes.d
@@ -0,0 +1,7 @@
+provider osmo_bts_trx {
+ probe ul_data_start(int, int, int); /* trx_nr, ts_nr, fn */
+ probe ul_data_done(int, int, int); /* trx_nr, ts_nr, fn */
+
+ probe dl_rts_start(int, int, int); /* trx_nr, ts_nr, fn */
+ probe dl_rts_done(int, int, int); /* trx_nr, ts_nr, fn */
+};
diff --git a/src/osmo-bts-trx/sched_lchan_fcch_sch.c b/src/osmo-bts-trx/sched_lchan_fcch_sch.c
new file mode 100644
index 00000000..5722b288
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_fcch_sch.c
@@ -0,0 +1,89 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * Contributions by sysmocom - s.f.m.c. GmbH
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/coding/gsm0503_coding.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+
+#include <sched_utils.h>
+
+/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
+int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting FCCH\n");
+
+ /* A frequency correction burst is basically a sequence of zeros */
+ memset(br->burst, 0x00, GSM_BURST_LEN);
+ br->burst_len = GSM_BURST_LEN;
+
+ return 0;
+}
+
+/* obtain a to-be-transmitted SCH (synchronization channel) burst */
+int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ ubit_t burst[78];
+ uint8_t sb_info[4];
+ struct gsm_time t;
+ uint8_t t3p, bsic;
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting SCH\n");
+
+ /* BURST BYPASS */
+
+ /* create SB info from GSM time and BSIC */
+ gsm_fn2gsmtime(&t, br->fn);
+ t3p = t.t3 / 10;
+ bsic = l1ts->ts->trx->bts->bsic;
+ sb_info[0] =
+ ((bsic & 0x3f) << 2) |
+ ((t.t1 & 0x600) >> 9);
+ sb_info[1] =
+ ((t.t1 & 0x1fe) >> 1);
+ sb_info[2] =
+ ((t.t1 & 0x001) << 7) |
+ ((t.t2 & 0x1f) << 2) |
+ ((t3p & 0x6) >> 1);
+ sb_info[3] =
+ (t3p & 0x1);
+
+ /* encode bursts */
+ gsm0503_sch_encode(burst, sb_info);
+
+ /* compose burst */
+ memcpy(br->burst + 3, burst, 39);
+ memcpy(br->burst + 42, _sched_train_seq_gmsk_sb, 64);
+ memcpy(br->burst + 106, burst + 39, 39);
+
+ br->burst_len = GSM_BURST_LEN;
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_lchan_pdtch.c b/src/osmo-bts-trx/sched_lchan_pdtch.c
new file mode 100644
index 00000000..466a4144
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_pdtch.c
@@ -0,0 +1,221 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * Contributions by sysmocom - s.f.m.c. GmbH
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/coding/gsm0503_coding.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+
+#include <sched_utils.h>
+
+/* Maximum size of a EGPRS message in bytes */
+#define EGPRS_0503_MAX_BYTES 155
+
+/*! \brief a single PDTCH burst was received by the PHY, process it */
+int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ sbit_t *burst, *bursts_p = chan_state->ul_bursts;
+ uint32_t first_fn;
+ uint32_t *mask = &chan_state->ul_mask;
+ struct l1sched_meas_set meas_avg;
+ uint8_t l2[EGPRS_0503_MAX_BYTES];
+ int n_errors = 0;
+ int n_bursts_bits = 0;
+ int n_bits_total = 0;
+ uint16_t ber10k;
+ int rc;
+ enum osmo_ph_pres_info_type presence_info;
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received PDTCH bid=%u\n", bi->bid);
+
+ /* An MS may be polled to send an ACK in form of four Access Bursts */
+ if (bi->flags & TRX_BI_F_ACCESS_BURST)
+ return rx_rach_fn(l1ts, bi);
+
+ /* clear burst */
+ if (bi->bid == 0) {
+ memset(bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS);
+ *mask = 0x0;
+ }
+
+ /* update mask */
+ *mask |= (1 << bi->bid);
+
+ /* store measurements */
+ trx_sched_meas_push(chan_state, bi);
+
+ /* copy burst to buffer of 4 bursts */
+ switch (bi->burst_len) {
+ case EGPRS_BURST_LEN:
+ burst = bursts_p + bi->bid * 348;
+ memcpy(burst, bi->burst + 9, 174);
+ memcpy(burst + 174, bi->burst + 261, 174);
+ n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS;
+ break;
+ case GSM_BURST_LEN:
+ burst = bursts_p + bi->bid * 116;
+ memcpy(burst, bi->burst + 3, 58);
+ memcpy(burst + 58, bi->burst + 87, 58);
+ n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;
+ break;
+ case 0:
+ /* NOPE.ind, assume GPRS? */
+ n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;
+ }
+
+ /* wait until complete set of bursts */
+ if (bi->bid != 3)
+ return 0;
+
+ /* average measurements of the last 4 bursts */
+ trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_S4N4);
+
+ /* check for complete set of bursts */
+ if ((*mask & 0xf) != 0xf) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received incomplete frame (%u/%u)\n",
+ bi->fn % l1ts->mf_period, l1ts->mf_period);
+ }
+ *mask = 0x0;
+
+ /*
+ * Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we
+ * do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS,
+ * then we incur decoding overhead of 31 bits on the Type 3 EGPRS
+ * header, which is tolerable.
+ */
+ rc = gsm0503_pdtch_egprs_decode(l2, bursts_p, n_bursts_bits,
+ NULL, &n_errors, &n_bits_total);
+
+ if ((bi->burst_len == GSM_BURST_LEN) && (rc < 0)) {
+ rc = gsm0503_pdtch_decode(l2, bursts_p, NULL,
+ &n_errors, &n_bits_total);
+ }
+
+ if (rc > 0) {
+ presence_info = PRES_INFO_BOTH;
+ } else {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ BAD_DATA_MSG_FMT "\n", BAD_DATA_MSG_ARGS);
+ rc = 0;
+ presence_info = PRES_INFO_INVALID;
+ }
+
+ ber10k = compute_ber10k(n_bits_total, n_errors);
+
+ first_fn = GSM_TDMA_FN_SUB(bi->fn, 3);
+ return _sched_compose_ph_data_ind(l1ts, first_fn, bi->chan,
+ &l2[0], rc,
+ ber10k,
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ presence_info);
+}
+
+/* obtain a to-be-transmitted PDTCH (packet data) burst */
+int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ struct msgb *msg = NULL; /* make GCC happy */
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
+ ubit_t *burst, *bursts_p = chan_state->dl_bursts;
+ enum trx_mod_type *mod = &chan_state->dl_mod_type;
+ uint8_t *mask = &chan_state->dl_mask;
+ int rc = 0;
+
+ /* send burst, if we already got a frame */
+ if (br->bid > 0) {
+ if ((*mask & 0x01) != 0x01)
+ return -ENOMSG;
+ goto send_burst;
+ }
+
+ *mask = *mask << 4;
+
+ /* get mac block from queue */
+ msg = _sched_dequeue_prim(l1ts, br);
+ if (!msg) {
+ /* It's totally fine to get no block here, since PCU may submit
+ * empty blocks when there's no MS listening. The scheduler will
+ * take care of filling C0 with dummy bursts to keep expected
+ * power transmit levels
+ */
+ return -ENODEV;
+ }
+
+ /* BURST BYPASS */
+
+ /* encode bursts */
+ rc = gsm0503_pdtch_egprs_encode(bursts_p, msg->l2h, msgb_l2len(msg));
+ if (rc < 0)
+ rc = gsm0503_pdtch_encode(bursts_p, msg->l2h, msgb_l2len(msg));
+
+ /* check validity of message */
+ if (rc < 0) {
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim invalid length, please FIX! "
+ "(len=%u)\n", msgb_l2len(msg));
+ /* free message */
+ msgb_free(msg);
+ return -EINVAL;
+ } else if (rc == GSM0503_EGPRS_BURSTS_NBITS) {
+ *mod = TRX_MOD_T_8PSK;
+ } else {
+ *mod = TRX_MOD_T_GMSK;
+ }
+
+ /* free message */
+ msgb_free(msg);
+
+send_burst:
+ /* compose burst */
+ if (*mod == TRX_MOD_T_8PSK) {
+ burst = bursts_p + br->bid * 348;
+ memset(br->burst, 1, 9);
+ memcpy(br->burst + 9, burst, 174);
+ memcpy(br->burst + 183, TRX_8PSK_NB_TSC(br), 78);
+ memcpy(br->burst + 261, burst + 174, 174);
+ memset(br->burst + 435, 1, 9);
+
+ br->burst_len = EGPRS_BURST_LEN;
+ } else {
+ burst = bursts_p + br->bid * 116;
+ memcpy(br->burst + 3, burst, 58);
+ memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
+ memcpy(br->burst + 87, burst + 58, 58);
+
+ br->burst_len = GSM_BURST_LEN;
+ }
+
+ *mask |= (1 << br->bid);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_lchan_rach.c b/src/osmo-bts-trx/sched_lchan_rach.c
new file mode 100644
index 00000000..c92dfe24
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_rach.c
@@ -0,0 +1,214 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com>
+ * Contributions by sysmocom - s.f.m.c. GmbH
+ *
+ * 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 Affero 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 <limits.h>
+#include <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/coding/gsm0503_coding.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+
+#include <sched_utils.h>
+
+/* 3GPP TS 05.02, section 5.2.7 */
+#define RACH_EXT_TAIL_LEN 8
+#define RACH_SYNCH_SEQ_LEN 41
+
+enum rach_synch_seq_t {
+ RACH_SYNCH_SEQ_UNKNOWN = -1,
+ RACH_SYNCH_SEQ_TS0, /* GSM, GMSK (default) */
+ RACH_SYNCH_SEQ_TS1, /* EGPRS, 8-PSK */
+ RACH_SYNCH_SEQ_TS2, /* EGPRS, GMSK */
+ RACH_SYNCH_SEQ_NUM
+};
+
+static struct value_string rach_synch_seq_names[] = {
+ { RACH_SYNCH_SEQ_UNKNOWN, "UNKNOWN" },
+ { RACH_SYNCH_SEQ_TS0, "TS0: GSM, GMSK" },
+ { RACH_SYNCH_SEQ_TS1, "TS1: EGPRS, 8-PSK" },
+ { RACH_SYNCH_SEQ_TS2, "TS2: EGPRS, GMSK" },
+ { 0, NULL },
+};
+
+static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)
+{
+ sbit_t *synch_seq_burst = bits + RACH_EXT_TAIL_LEN;
+ enum rach_synch_seq_t seq = RACH_SYNCH_SEQ_TS0;
+ int score[RACH_SYNCH_SEQ_NUM] = { 0 };
+ int max_score = INT_MIN;
+ int i, j;
+
+ /* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
+ static const char synch_seq_ref[RACH_SYNCH_SEQ_NUM][RACH_SYNCH_SEQ_LEN] = {
+ [RACH_SYNCH_SEQ_TS0] = "01001011011111111001100110101010001111000",
+ [RACH_SYNCH_SEQ_TS1] = "01010100111110001000011000101111001001101",
+ [RACH_SYNCH_SEQ_TS2] = "11101111001001110101011000001101101110111",
+ };
+
+ /* Get a multiplier for j-th bit of i-th synch. sequence */
+#define RACH_SYNCH_SEQ_MULT \
+ (synch_seq_ref[i][j] == '1' ? -1 : 1)
+
+ /* For each synch. sequence, count the bit match score. Since we deal with
+ * soft-bits (-127...127), we sum the absolute values of matching ones,
+ * and subtract the absolute values of different ones, so the resulting
+ * score is more accurate than it could be with hard-bits. */
+ for (i = 0; i < RACH_SYNCH_SEQ_NUM; i++) {
+ for (j = 0; j < RACH_SYNCH_SEQ_LEN; j++)
+ score[i] += RACH_SYNCH_SEQ_MULT * synch_seq_burst[j];
+
+ /* Keep the maximum value updated */
+ if (score[i] > max_score) {
+ max_score = score[i];
+ seq = i;
+ }
+ }
+
+ /* Calculate an approximate level of our confidence */
+ if (best_score != NULL)
+ *best_score = max_score;
+
+ /* At least 1/3 of a synch. sequence shall match */
+ if (max_score < (127 * RACH_SYNCH_SEQ_LEN / 3))
+ return RACH_SYNCH_SEQ_UNKNOWN;
+
+ return seq;
+}
+
+int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
+{
+ struct gsm_bts_trx *trx = l1ts->ts->trx;
+ struct osmo_phsap_prim l1sap;
+ int n_errors = 0;
+ int n_bits_total = 0;
+ uint16_t ra11;
+ uint8_t ra;
+ int rc;
+
+ /* Ignore NOPE indications, they're of no use here */
+ if (bi->flags & TRX_BI_F_NOPE_IND)
+ return 0;
+
+ /* TSC (Training Sequence Code) is an optional parameter of the UL burst
+ * indication. We need this information in order to decide whether an
+ * Access Burst is 11-bit encoded or not (see OS#1854). If this information
+ * is absent, we try to correlate the received synch. sequence with the
+ * known ones (3GPP TS 05.02, section 5.2.7), and fall-back to the default
+ * TS0 if it fails. */
+ enum rach_synch_seq_t synch_seq = RACH_SYNCH_SEQ_TS0;
+ int best_score = 127 * RACH_SYNCH_SEQ_LEN;
+
+ /* If logical channel is not either of RACH, PDTCH or PTCCH, this is a
+ * handover Access Burst, which is always encoded as 8-bit and shall
+ * contain the generic training sequence (TS0). */
+ if (bi->chan == TRXC_RACH || bi->chan == TRXC_PDTCH || bi->chan == TRXC_PTCCH) {
+ if (bi->flags & TRX_BI_F_TS_INFO)
+ synch_seq = (enum rach_synch_seq_t) bi->tsc;
+ else
+ synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);
+ }
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "Received%s RACH (%s): rssi=%d toa256=%d",
+ TRX_CHAN_IS_DEDIC(bi->chan) ? " handover" : "",
+ get_value_string(rach_synch_seq_names, synch_seq),
+ bi->rssi, bi->toa256);
+ if (bi->flags & TRX_BI_F_CI_CB)
+ LOGPC(DL1P, LOGL_DEBUG, " C/I=%d cB", bi->ci_cb);
+ else
+ LOGPC(DL1P, LOGL_DEBUG, " match=%.1f%%",
+ best_score * 100.0 / (127 * RACH_SYNCH_SEQ_LEN));
+ LOGPC(DL1P, LOGL_DEBUG, "\n");
+
+ /* Compose a new L1SAP primitive */
+ memset(&l1sap, 0x00, sizeof(l1sap));
+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, NULL);
+ l1sap.u.rach_ind.chan_nr = trx_chan_desc[bi->chan].chan_nr | bi->tn;
+ l1sap.u.rach_ind.acc_delay = (bi->toa256 >= 0) ? bi->toa256 / 256 : 0;
+ l1sap.u.rach_ind.acc_delay_256bits = bi->toa256;
+ l1sap.u.rach_ind.rssi = bi->rssi;
+ l1sap.u.rach_ind.fn = bi->fn;
+
+ /* Link quality is defined by C/I (Carrier-to-Interference ratio),
+ * which has optional presence. If it's absent, report the
+ * minimum acceptable value to pass L1SAP checks. */
+ if (bi->flags & TRX_BI_F_CI_CB)
+ l1sap.u.rach_ind.lqual_cb = bi->ci_cb;
+ else
+ l1sap.u.rach_ind.lqual_cb = trx->bts->min_qual_rach;
+
+ /* Decode RACH depending on its synch. sequence */
+ switch (synch_seq) {
+ case RACH_SYNCH_SEQ_TS1:
+ case RACH_SYNCH_SEQ_TS2:
+ rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
+ trx->bts->bsic, &n_errors, &n_bits_total);
+ if (rc) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
+ return 0;
+ }
+
+ if (synch_seq == RACH_SYNCH_SEQ_TS1)
+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_1;
+ else
+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_2;
+
+ l1sap.u.rach_ind.is_11bit = 1;
+ l1sap.u.rach_ind.ra = ra11;
+ break;
+
+ case RACH_SYNCH_SEQ_TS0:
+ default:
+ /* Fall-back to the default TS0 if needed */
+ if (synch_seq != RACH_SYNCH_SEQ_TS0) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Falling-back to the default TS0\n");
+ synch_seq = RACH_SYNCH_SEQ_TS0;
+ }
+
+ rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
+ trx->bts->bsic, &n_errors, &n_bits_total);
+ if (rc) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
+ return 0;
+ }
+
+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;
+ l1sap.u.rach_ind.is_11bit = 0;
+ l1sap.u.rach_ind.ra = ra;
+ break;
+ }
+
+ l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);
+
+ /* forward primitive */
+ l1sap_up(trx, &l1sap);
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c
new file mode 100644
index 00000000..5a3e80ac
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_tchf.c
@@ -0,0 +1,677 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/gsm/gsm0502.h>
+
+#include <osmocom/codec/codec.h>
+
+#include <osmocom/coding/gsm0503_coding.h>
+#include <osmocom/coding/gsm0503_amr_dtx.h>
+
+#include <osmocom/netif/amr.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+#include <osmo-bts/msg_utils.h>
+
+#include <sched_utils.h>
+#include <amr_loop.h>
+
+/* 3GPP TS 45.009, table 3.2.1.3-{1,3}: AMR on Uplink TCH/F.
+ *
+ * +---+---+---+---+---+---+---+---+
+ * | a | b | c | d | e | f | g | h | Burst 'a' received first
+ * +---+---+---+---+---+---+---+---+
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Speech/FACCH frame (bursts 'a' .. 'h')
+ *
+ * TDMA frame number of burst 'h' is always used as the table index. */
+static const uint8_t sched_tchf_ul_amr_cmi_map[26] = {
+ [7] = 1, /* TCH/F: a=0 / h=7 */
+ [16] = 1, /* TCH/F: a=8 / h=16 */
+ [24] = 1, /* TCH/F: a=17 / h=24 */
+};
+
+/* TDMA frame number of burst 'a' should be used as the table index. */
+static const uint8_t sched_tchf_dl_amr_cmi_map[26] = {
+ [4] = 1, /* TCH/F: a=4 */
+ [13] = 1, /* TCH/F: a=13 */
+ [21] = 1, /* TCH/F: a=21 */
+};
+
+extern const uint8_t sched_tchh_dl_amr_cmi_map[26];
+
+static int decode_fr_facch(struct l1sched_ts *l1ts,
+ const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ const sbit_t *bursts_p = chan_state->ul_bursts;
+ struct l1sched_meas_set meas_avg;
+ uint8_t data[GSM_MACBLOCK_LEN];
+ int n_errors, n_bits_total;
+ int rc;
+
+ rc = gsm0503_tch_fr_facch_decode(&data[0], BUFTAIL8(bursts_p),
+ &n_errors, &n_bits_total);
+ if (rc != GSM_MACBLOCK_LEN)
+ return rc;
+
+ /* average measurements of the last 8 bursts, obtain TDMA Fn of the first burst */
+ trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_S8N8);
+
+ _sched_compose_ph_data_ind(l1ts, meas_avg.fn, bi->chan,
+ &data[0], GSM_MACBLOCK_LEN,
+ compute_ber10k(n_bits_total, n_errors),
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ PRES_INFO_UNKNOWN);
+ return GSM_MACBLOCK_LEN;
+}
+
+/* Process a single Uplink TCH/F burst received by the PHY.
+ * This function is visualized in file 'doc/trx_sched_tch.txt'. */
+int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ struct gsm_lchan *lchan = chan_state->lchan;
+ sbit_t *burst, *bursts_p = chan_state->ul_bursts;
+ uint32_t *mask = &chan_state->ul_mask;
+ uint8_t rsl_cmode = chan_state->rsl_cmode;
+ uint8_t tch_mode = chan_state->tch_mode;
+ uint8_t tch_data[290]; /* large enough to hold 290 unpacked bits for CSD */
+ enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
+ struct l1sched_meas_set meas_avg;
+ int rc, amr = 0;
+ int n_errors = 0;
+ int n_bits_total = 0;
+ unsigned int fn_begin;
+ uint16_t ber10k;
+ uint8_t is_sub = 0;
+ uint8_t ft;
+ bool amr_is_cmr;
+
+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.
+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
+ return rx_rach_fn(l1ts, bi);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received TCH/F, bid=%u\n", bi->bid);
+
+ /* shift the buffer by 4 bursts leftwards */
+ if (bi->bid == 0) {
+ memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
+ memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);
+ *mask = *mask << 4;
+ }
+
+ /* update mask */
+ *mask |= (1 << bi->bid);
+
+ /* store measurements */
+ trx_sched_meas_push(chan_state, bi);
+
+ /* copy burst to end of buffer of 24 bursts */
+ burst = BUFPOS(bursts_p, 20 + bi->bid);
+ if (bi->burst_len > 0) {
+ memcpy(burst, bi->burst + 3, 58);
+ memcpy(burst + 58, bi->burst + 87, 58);
+ }
+
+ /* wait until complete set of bursts */
+ if (bi->bid != 3)
+ return 0;
+
+ /* fill up the burst buffer so that we have 8 bursts in there */
+ if (OSMO_UNLIKELY((*mask & 0xff) != 0xff)) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "UL burst buffer is not filled up: mask=0x%02x != 0xff\n",
+ *mask);
+ return 0; /* TODO: send BFI */
+ }
+
+ /* TCH/F: speech and signalling frames are interleaved over 8 bursts, while
+ * CSD frames are interleaved over 22 bursts. Unless we're in CSD mode,
+ * decode only the last 8 bursts to avoid introducing additional delays. */
+ switch (tch_mode) {
+ case GSM48_CMODE_SIGN:
+ case GSM48_CMODE_SPEECH_V1: /* FR */
+ rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
+ 1, 0, &n_errors, &n_bits_total);
+ if (rc == GSM_FR_BYTES) /* only for valid *speech* frames */
+ lchan_set_marker(osmo_fr_is_any_sid(tch_data), lchan); /* DTXu */
+ break;
+ case GSM48_CMODE_SPEECH_EFR: /* EFR */
+ rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
+ 1, 1, &n_errors, &n_bits_total);
+ if (rc == GSM_EFR_BYTES) /* only for valid *speech* frames */
+ lchan_set_marker(osmo_efr_is_any_sid(tch_data), lchan); /* DTXu */
+ break;
+ case GSM48_CMODE_SPEECH_AMR: /* AMR */
+ /* the first FN 0,8,17 defines that CMI is included in frame,
+ * the first FN 4,13,21 defines that CMR is included in frame.
+ * NOTE: A frame ends 7 FN after start.
+ */
+ amr_is_cmr = !sched_tchf_ul_amr_cmi_map[bi->fn % 26];
+
+ /* The AFS_ONSET frame itself does not result into an RTP frame
+ * since it only contains a recognition pattern that marks the
+ * end of the DTX interval. To mark the end of the DTX interval
+ * in the RTP stream as well, the voice frame after the
+ * AFS_ONSET frame is used. */
+ if (chan_state->amr_last_dtx == AFS_ONSET)
+ lchan_set_marker(false, lchan);
+
+ /* Store AMR payload in tch-data with an offset of 2 bytes, so
+ * that we can easily prepend/fill the RTP AMR header (struct
+ * amr_hdr) with osmo_amr_rtp_enc() later on. The amr variable
+ * is used far below to account for the decoded offset in case
+ * we receive an FACCH frame instead of a voice frame (we
+ * do not know this before we actually decode the frame) */
+ amr = sizeof(struct amr_hdr);
+ rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, BUFTAIL8(bursts_p),
+ amr_is_cmr, chan_state->codec, chan_state->codecs, &chan_state->ul_ft,
+ &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
+
+ /* Tag all frames that are not regular AMR voice frames as
+ * SUB-Frames */
+ if (chan_state->amr_last_dtx != AMR_OTHER) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "Received AMR DTX frame (rc=%d, BER %d/%d): %s\n",
+ rc, n_errors, n_bits_total,
+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
+ is_sub = 1;
+ }
+
+ /* The occurrence of the following frames indicates that we
+ * are either at the beginning or in the middle of a talk
+ * spurt. We update the SID status accordingly, but we do
+ * not want the marker to be set, since this must only
+ * happen when the talk spurt is over (see above) */
+ switch (chan_state->amr_last_dtx) {
+ case AFS_SID_FIRST:
+ case AFS_SID_UPDATE:
+ case AFS_SID_UPDATE_CN:
+ lchan_set_marker(true, lchan);
+ lchan->rtp_tx_marker = false;
+ break;
+ }
+
+ switch (chan_state->amr_last_dtx) {
+ case AFS_SID_FIRST:
+ case AFS_SID_UPDATE_CN:
+ meas_avg_mode = SCHED_MEAS_AVG_M_S8N4;
+ break;
+ case AFS_SID_UPDATE:
+ case AFS_ONSET:
+ meas_avg_mode = SCHED_MEAS_AVG_M_S4N4;
+ break;
+ }
+
+ /* only good speech frames get rtp header */
+ if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
+ if (chan_state->amr_last_dtx == AMR_OTHER) {
+ ft = chan_state->codec[chan_state->ul_ft];
+ } else {
+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */
+ ft = AMR_SID;
+ }
+ rc = osmo_amr_rtp_enc(tch_data,
+ chan_state->codec[chan_state->ul_cmr],
+ ft, AMR_GOOD);
+ }
+
+ break;
+ /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_12k0:
+ /* FACCH/F does not steal TCH/F9.6 frames, but only disturbs some bits */
+ decode_fr_facch(l1ts, bi);
+ rc = gsm0503_tch_fr96_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+ break;
+ /* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ /* FACCH/F does not steal TCH/F4.8 frames, but only disturbs some bits */
+ decode_fr_facch(l1ts, bi);
+ rc = gsm0503_tch_fr48_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+ break;
+ /* CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ /* TCH/F2.4 employs the same interleaving as TCH/FS (8 bursts),
+ * so FACCH/F *does* steal TCH/F2.4 frames completely. */
+ if (decode_fr_facch(l1ts, bi) == GSM_MACBLOCK_LEN)
+ return 0; /* TODO: emit BFI */
+ rc = gsm0503_tch_fr24_decode(&tch_data[0], BUFTAIL8(bursts_p),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
+ break;
+ /* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_14k5:
+ /* FACCH/F does not steal TCH/F14.4 frames, but only disturbs some bits */
+ decode_fr_facch(l1ts, bi);
+ rc = gsm0503_tch_fr144_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+ break;
+ default:
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
+ "TCH mode %u invalid, please fix!\n",
+ tch_mode);
+ return -EINVAL;
+ }
+
+ ber10k = compute_ber10k(n_bits_total, n_errors);
+
+ /* average measurements of the last N (depends on mode) bursts */
+ trx_sched_meas_avg(chan_state, &meas_avg, meas_avg_mode);
+ /* meas_avg.fn now contains TDMA frame number of the first burst */
+ fn_begin = meas_avg.fn;
+
+ if (tch_mode == GSM48_CMODE_SPEECH_AMR)
+ trx_loop_amr_input(chan_state, &meas_avg);
+
+ /* Check if the frame is bad */
+ if (rc < 4) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
+ BAD_DATA_MSG_FMT "\n", BAD_DATA_MSG_ARGS);
+ rc = 0; /* this is how we signal BFI to l1sap */
+ } else if (rc == GSM_MACBLOCK_LEN) { /* FACCH/F */
+ _sched_compose_ph_data_ind(l1ts, fn_begin, bi->chan,
+ &tch_data[amr], GSM_MACBLOCK_LEN,
+ ber10k,
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ PRES_INFO_UNKNOWN);
+
+ /* If we are in SPEECH mode we will generate a fake (BFI) TCH
+ * indication as well. This indication is needed by the higher
+ * layers, however we already have reported the measurement
+ * result for the current block together with the FACCH.
+ * To avoid reporting the same measurement result again with
+ * the fake (BFI) TCH indication we set meas_avg.rssi to zero.
+ * Doing so tells l1sap.c to ignore the measurement result. */
+ meas_avg.rssi = 0;
+ rc = 0;
+ }
+
+ if (rsl_cmode == RSL_CMOD_SPD_SIGN)
+ return 0;
+
+ /* TCH or BFI */
+ return _sched_compose_tch_ind(l1ts, fn_begin, bi->chan,
+ &tch_data[0], rc,
+ ber10k,
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ is_sub);
+}
+
+/* common section for generation of TCH bursts (TCH/H and TCH/F).
+ * FIXME: this function is over-complicated, refactor / get rid of it. */
+void tch_dl_dequeue(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br,
+ struct msgb **msg_tch, struct msgb **msg_facch)
+{
+ struct msgb *msg1, *msg2;
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
+ uint8_t rsl_cmode = chan_state->rsl_cmode;
+ uint8_t tch_mode = chan_state->tch_mode;
+ struct osmo_phsap_prim *l1sap;
+
+ /* get frame and unlink from queue */
+ msg1 = _sched_dequeue_prim(l1ts, br);
+ msg2 = _sched_dequeue_prim(l1ts, br);
+ if (msg1) {
+ l1sap = msgb_l1sap_prim(msg1);
+ if (l1sap->oph.primitive == PRIM_TCH) {
+ *msg_tch = msg1;
+ if (msg2) {
+ l1sap = msgb_l1sap_prim(msg2);
+ if (l1sap->oph.primitive == PRIM_TCH) {
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "TCH twice, please FIX!\n");
+ msgb_free(msg2);
+ } else
+ *msg_facch = msg2;
+ }
+ } else {
+ *msg_facch = msg1;
+ if (msg2) {
+ l1sap = msgb_l1sap_prim(msg2);
+ if (l1sap->oph.primitive != PRIM_TCH) {
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "FACCH twice, please FIX!\n");
+ msgb_free(msg2);
+ } else
+ *msg_tch = msg2;
+ }
+ }
+ }
+
+ /* check validity of message */
+ if (*msg_facch != NULL && msgb_l2len(*msg_facch) != GSM_MACBLOCK_LEN) {
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
+ msgb_l2len(*msg_facch), GSM_MACBLOCK_LEN);
+ /* free message */
+ msgb_free(*msg_facch);
+ *msg_facch = NULL;
+ }
+
+ /* check validity of message, get AMR ft and cmr */
+ if (*msg_tch != NULL) {
+ int len;
+ uint8_t cmr_codec;
+ int ft, i;
+ enum osmo_amr_type ft_codec;
+ enum osmo_amr_quality bfi;
+ int8_t sti, cmi;
+ bool amr_is_cmr;
+
+ if (OSMO_UNLIKELY(rsl_cmode == RSL_CMOD_SPD_SIGN)) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping a TCH frame, "
+ "because we are not in speech mode\n");
+ goto free_bad_msg;
+ }
+
+ switch (tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */
+ if (br->chan != TRXC_TCHF) /* HR */
+ len = GSM_HR_BYTES;
+ else
+ len = GSM_FR_BYTES;
+ break;
+ case GSM48_CMODE_SPEECH_EFR: /* EFR */
+ if (br->chan != TRXC_TCHF)
+ goto inval_mode2;
+ len = GSM_EFR_BYTES;
+ break;
+ case GSM48_CMODE_SPEECH_AMR: /* AMR */
+ len = osmo_amr_rtp_dec(msgb_l2((*msg_tch)), msgb_l2len(*msg_tch),
+ &cmr_codec, &cmi, &ft_codec,
+ &bfi, &sti);
+ if (len < 0) {
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n");
+ goto free_bad_msg;
+ }
+ ft = -1;
+ for (i = 0; i < chan_state->codecs; i++) {
+ if (chan_state->codec[i] == ft_codec)
+ ft = i;
+ }
+ if (ft < 0) {
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
+ "Codec (FT = %d) of RTP frame not in list\n", ft_codec);
+ goto free_bad_msg;
+ }
+ if (br->chan == TRXC_TCHF)
+ amr_is_cmr = !sched_tchf_dl_amr_cmi_map[br->fn % 26];
+ else /* TRXC_TCHH_0 or TRXC_TCHH_1 */
+ amr_is_cmr = !sched_tchh_dl_amr_cmi_map[br->fn % 26];
+ if (amr_is_cmr && chan_state->dl_ft != ft) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Codec (FT = %d) "
+ " of RTP cannot be changed now, but in next frame\n", ft_codec);
+ goto free_bad_msg;
+ }
+ chan_state->dl_ft = ft;
+ if (bfi == AMR_BAD) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad AMR frame'\n");
+ goto free_bad_msg;
+ }
+ /* pull the AMR header, it's not being sent over Um */
+ (*msg_tch)->l2h += sizeof(struct amr_hdr);
+ len -= sizeof(struct amr_hdr);
+ break;
+ case GSM48_CMODE_DATA_14k5: /* TCH/F14.4 */
+ if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
+ goto inval_mode2;
+ len = 290;
+ break;
+ case GSM48_CMODE_DATA_12k0: /* TCH/F9.6 */
+ if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
+ goto inval_mode2;
+ len = 4 * 60;
+ break;
+ case GSM48_CMODE_DATA_6k0: /* TCH/[FH]4.8 */
+ if (br->chan == TRXC_TCHF)
+ len = 2 * 60;
+ else
+ len = 4 * 60;
+ break;
+ case GSM48_CMODE_DATA_3k6: /* TCH/[FH]2.4 */
+ if (br->chan == TRXC_TCHF)
+ len = 2 * 36;
+ else
+ len = 4 * 36;
+ break;
+ default:
+inval_mode2:
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
+ goto free_bad_msg;
+ }
+ if (msgb_l2len(*msg_tch) != len) {
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with "
+ "invalid length! (expecting %d, received %d)\n",
+ len, msgb_l2len(*msg_tch));
+free_bad_msg:
+ /* free message */
+ msgb_free(*msg_tch);
+ *msg_tch = NULL;
+ }
+ }
+}
+
+struct msgb *tch_dummy_msgb(size_t size, uint8_t pad)
+{
+ struct msgb *msg;
+
+ msg = msgb_alloc(size, __func__);
+ OSMO_ASSERT(msg != NULL);
+
+ msg->l2h = msgb_put(msg, size);
+ memset(msg->l2h, pad, size);
+
+ return msg;
+}
+
+/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
+int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
+ uint8_t tch_mode = chan_state->tch_mode;
+ ubit_t *burst, *bursts_p = chan_state->dl_bursts;
+ uint8_t *mask = &chan_state->dl_mask;
+ struct msgb *msg_facch = NULL;
+ struct msgb *msg_tch = NULL;
+ struct msgb *msg = NULL;
+
+ /* send burst, if we already got a frame */
+ if (br->bid > 0) {
+ if ((*mask & 0x01) != 0x01)
+ return -ENOMSG;
+ goto send_burst;
+ }
+
+ *mask = *mask << 4;
+
+ /* BURST BYPASS */
+
+ /* shift buffer by 4 bursts for interleaving */
+ memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
+ memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);
+
+ /* dequeue a TCH and/or a FACCH message to be transmitted */
+ tch_dl_dequeue(l1ts, br, &msg_tch, &msg_facch);
+ if (msg_tch == NULL && msg_facch == NULL) {
+ int rc;
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "No TCH or FACCH prim for transmit.\n");
+ /* - If the channel mode is TCH/FS or TCH/EFS, transmit a dummy
+ * speech block with inverted CRC3, designed to induce a BFI
+ * condition in the MS receiver.
+ * - If the channel mode is TCH/AFS, transmit a dummy speech
+ * block with inverted CRC6, designed to induce a BFI
+ * condition in the MS receiver.
+ * - If the channel mode is one of the CSD modes, transmit an
+ * idle frame as described in 3GPP TS 44.021, sections 8.1.6
+ * and 10.2.3 (all data, status and E-bits set to binary '1').
+ * - In all other channel modes, transmit dummy FACCH
+ * like we always did before.
+ */
+ switch (tch_mode) {
+ case GSM48_CMODE_DATA_12k0:
+ case GSM48_CMODE_DATA_6k0:
+ case GSM48_CMODE_DATA_3k6:
+ case GSM48_CMODE_DATA_14k5:
+ break; /* see below */
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ rc = gsm0503_tch_fr_encode(BUFPOS(bursts_p, 0), NULL, 0, 1);
+ if (rc == 0)
+ goto send_burst;
+ /* fall-through */
+ case GSM48_CMODE_SIGN:
+ default:
+ if (tch_mode == GSM48_CMODE_SPEECH_AMR) {
+ /* the first FN 4,13,21 defines that CMI is included in frame,
+ * the first FN 0,8,17 defines that CMR is included in frame.
+ */
+ rc = gsm0503_tch_afs_encode(BUFPOS(bursts_p, 0),
+ NULL, 0,
+ !sched_tchf_dl_amr_cmi_map[br->fn % 26],
+ chan_state->codec,
+ chan_state->codecs,
+ chan_state->dl_ft,
+ chan_state->dl_cmr);
+ if (rc == 0)
+ goto send_burst;
+ }
+
+ /* TODO: use randomized padding */
+ msg_facch = tch_dummy_msgb(GSM_MACBLOCK_LEN, GSM_MACBLOCK_PADDING);
+ /* dummy LAPDm func=UI frame */
+ msg_facch->l2h[0] = 0x03;
+ msg_facch->l2h[1] = 0x03;
+ msg_facch->l2h[2] = 0x01;
+ break;
+ }
+ }
+
+ /* Unlike SACCH, FACCH has no dedicated slots on the multiframe layout.
+ * It's multiplexed together with TCH (speech or data) frames basically
+ * by replacing (stealing) their bits, either completely or partly. */
+ msg = (msg_facch != NULL) ? msg_facch : msg_tch;
+ if (msg == msg_facch)
+ chan_state->dl_facch_bursts = 8;
+
+ /* populate the buffer with bursts */
+ switch (tch_mode) {
+ case GSM48_CMODE_SIGN:
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ gsm0503_tch_fr_encode(BUFPOS(bursts_p, 0), msg->l2h, msgb_l2len(msg), 1);
+ break;
+ case GSM48_CMODE_SPEECH_AMR:
+ /* the first FN 4,13,21 defines that CMI is included in frame,
+ * the first FN 0,8,17 defines that CMR is included in frame.
+ */
+ gsm0503_tch_afs_encode(BUFPOS(bursts_p, 0),
+ msgb_l2(msg), msgb_l2len(msg),
+ !sched_tchf_dl_amr_cmi_map[br->fn % 26],
+ chan_state->codec,
+ chan_state->codecs,
+ chan_state->dl_ft,
+ chan_state->dl_cmr);
+ break;
+ /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_12k0:
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(4 * 60, 0x01);
+ gsm0503_tch_fr96_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ if (msg_facch != NULL)
+ gsm0503_tch_fr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ break;
+ /* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(2 * 60, 0x01);
+ gsm0503_tch_fr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ if (msg_facch != NULL)
+ gsm0503_tch_fr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ break;
+ /* CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ /* FACCH/F does steal a TCH/F2.4 frame completely */
+ if (msg_facch != NULL) {
+ gsm0503_tch_fr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ } else {
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(2 * 36, 0x01);
+ gsm0503_tch_fr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ }
+ break;
+ /* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_14k5:
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(290, 0x01);
+ gsm0503_tch_fr144_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ if (msg_facch != NULL)
+ gsm0503_tch_fr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ /* free messages */
+ msgb_free(msg_tch);
+ msgb_free(msg_facch);
+
+send_burst:
+ /* compose burst */
+ burst = BUFPOS(bursts_p, br->bid);
+ memcpy(br->burst + 3, burst, 58);
+ memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
+ memcpy(br->burst + 87, burst + 58, 58);
+
+ br->burst_len = GSM_BURST_LEN;
+
+ if (chan_state->dl_facch_bursts > 0) {
+ chan_state->dl_facch_bursts--;
+ br->flags |= TRX_BR_F_FACCH;
+ }
+
+ *mask |= (1 << br->bid);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c
new file mode 100644
index 00000000..66244cb0
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_tchh.c
@@ -0,0 +1,580 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/gsm/gsm0502.h>
+
+#include <osmocom/codec/codec.h>
+
+#include <osmocom/coding/gsm0503_coding.h>
+#include <osmocom/coding/gsm0503_amr_dtx.h>
+
+#include <osmocom/netif/amr.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+#include <osmo-bts/msg_utils.h>
+
+#include <sched_utils.h>
+#include <amr_loop.h>
+
+/* 3GPP TS 45.009, table 3.2.1.3-{2,4}: AMR on Uplink TCH/H.
+ *
+ * +---+---+---+---+---+---+
+ * | a | b | c | d | e | f | Burst 'a' received first
+ * +---+---+---+---+---+---+
+ * ^^^^^^^^^^^^^^^^^^^^^^^ FACCH frame (bursts 'a' .. 'f')
+ * ^^^^^^^^^^^^^^^ Speech frame (bursts 'a' .. 'd')
+ *
+ * TDMA frame number of burst 'f' is always used as the table index. */
+static const uint8_t sched_tchh_ul_amr_cmi_map[26] = {
+ [10] = 1, /* TCH/H(0): a=0 / d=6 / f=10 */
+ [19] = 1, /* TCH/H(0): a=8 / d=15 / f=19 */
+ [2] = 1, /* TCH/H(0): a=17 / d=23 / f=2 */
+
+ [11] = 1, /* TCH/H(1): a=1 / d=7 / f=11 */
+ [20] = 1, /* TCH/H(1): a=9 / d=16 / f=20 */
+ [3] = 1, /* TCH/H(1): a=18 / d=24 / f=3 */
+};
+
+/* TDMA frame number of burst 'a' should be used as the table index.
+ * This mapping is valid for both FACCH/H(0) and FACCH/H(1). */
+const uint8_t sched_tchh_dl_amr_cmi_map[26] = {
+ [4] = 1, /* TCH/H(0): a=4 */
+ [13] = 1, /* TCH/H(0): a=13 */
+ [21] = 1, /* TCH/H(0): a=21 */
+
+ [5] = 1, /* TCH/H(1): a=5 */
+ [14] = 1, /* TCH/H(1): a=14 */
+ [22] = 1, /* TCH/H(1): a=22 */
+};
+
+/* 3GPP TS 45.002, table 1 in clause 7: Mapping tables.
+ * TDMA frame number of burst 'f' is always used as the table index. */
+static const uint8_t sched_tchh_ul_facch_map[26] = {
+ [10] = 1, /* FACCH/H(0): B0(0,2,4,6,8,10) */
+ [11] = 1, /* FACCH/H(1): B0(1,3,5,7,9,11) */
+ [19] = 1, /* FACCH/H(0): B1(8,10,13,15,17,19) */
+ [20] = 1, /* FACCH/H(1): B1(9,11,14,16,18,20) */
+ [2] = 1, /* FACCH/H(0): B2(17,19,21,23,0,2) */
+ [3] = 1, /* FACCH/H(1): B2(18,20,22,24,1,3) */
+};
+
+/* TDMA frame number of burst 'a' is used as the table index. */
+extern const uint8_t sched_tchh_dl_facch_map[26];
+
+/* 3GPP TS 45.002, table 2 in clause 7: Mapping tables for TCH/H2.4 and TCH/H4.8.
+ *
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * TCH/H(0): B0(0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19)
+ * TCH/H(1): B0(1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20)
+ * TCH/H(0): B1(8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2)
+ * TCH/H(1): B1(9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3)
+ * TCH/H(0): B2(17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10)
+ * TCH/H(1): B2(18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11)
+ *
+ * TDMA frame number of burst 'v' % 26 is the table index.
+ * This mapping is valid for both TCH/H(0) and TCH/H(1). */
+static const uint8_t sched_tchh_ul_csd_map[26] = {
+ [19] = 1, /* TCH/H(0): B0(0 ... 19) */
+ [20] = 1, /* TCH/H(1): B0(1 ... 20) */
+ [2] = 1, /* TCH/H(0): B1(8 ... 2) */
+ [3] = 1, /* TCH/H(1): B1(9 ... 3) */
+ [10] = 1, /* TCH/H(0): B2(17 ... 10) */
+ [11] = 1, /* TCH/H(1): B2(18 ... 11) */
+};
+
+/* TDMA frame number of burst 'a' % 26 is the table index.
+ * This mapping is valid for both TCH/H(0) and TCH/H(1). */
+static const uint8_t sched_tchh_dl_csd_map[26] = {
+ [0] = 1, /* TCH/H(0): B0(0 ... 19) */
+ [1] = 1, /* TCH/H(1): B0(1 ... 20) */
+ [8] = 1, /* TCH/H(0): B1(8 ... 2) */
+ [9] = 1, /* TCH/H(1): B1(9 ... 3) */
+ [17] = 1, /* TCH/H(0): B2(17 ... 10) */
+ [18] = 1, /* TCH/H(1): B2(18 ... 11) */
+};
+
+static int decode_hr_facch(struct l1sched_ts *l1ts,
+ const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ const sbit_t *bursts_p = chan_state->ul_bursts;
+ struct l1sched_meas_set meas_avg;
+ uint8_t data[GSM_MACBLOCK_LEN];
+ int n_errors, n_bits_total;
+ int rc;
+
+ rc = gsm0503_tch_hr_facch_decode(&data[0], BUFTAIL8(bursts_p),
+ &n_errors, &n_bits_total);
+ if (rc != GSM_MACBLOCK_LEN)
+ return rc;
+
+ /* average measurements of the last 6 bursts, obtain TDMA Fn of the first burst */
+ trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_S6N6);
+
+ _sched_compose_ph_data_ind(l1ts, meas_avg.fn, bi->chan,
+ &data[0], GSM_MACBLOCK_LEN,
+ compute_ber10k(n_bits_total, n_errors),
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ PRES_INFO_UNKNOWN);
+ return GSM_MACBLOCK_LEN;
+}
+
+/* Process a single Uplink TCH/H burst received by the PHY.
+ * This function is visualized in file 'doc/trx_sched_tch.txt'. */
+int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ struct gsm_lchan *lchan = chan_state->lchan;
+ sbit_t *burst, *bursts_p = chan_state->ul_bursts;
+ uint32_t *mask = &chan_state->ul_mask;
+ uint8_t rsl_cmode = chan_state->rsl_cmode;
+ uint8_t tch_mode = chan_state->tch_mode;
+ uint8_t tch_data[240]; /* large enough to hold 240 unpacked bits for CSD */
+ int rc = 0; /* initialize to make gcc happy */
+ int amr = 0;
+ int n_errors = 0;
+ int n_bits_total = 0;
+ enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_S6N4;
+ struct l1sched_meas_set meas_avg;
+ unsigned int fn_begin;
+ uint16_t ber10k = 0;
+ uint8_t is_sub = 0;
+ uint8_t ft;
+ bool fn_is_cmi;
+
+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.
+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
+ return rx_rach_fn(l1ts, bi);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received TCH/H, bid=%u\n", bi->bid);
+
+ /* shift the buffer by 2 bursts leftwards */
+ if (bi->bid == 0) {
+ memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
+ memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
+ *mask = *mask << 2;
+ }
+
+ /* update mask */
+ *mask |= (1 << bi->bid);
+
+ /* store measurements */
+ trx_sched_meas_push(chan_state, bi);
+
+ /* copy burst to end of buffer of 24 bursts */
+ burst = BUFPOS(bursts_p, 20 + bi->bid);
+ if (bi->burst_len > 0) {
+ memcpy(burst, bi->burst + 3, 58);
+ memcpy(burst + 58, bi->burst + 87, 58);
+ }
+
+ /* wait until complete set of bursts */
+ if (bi->bid != 1)
+ return 0;
+
+ /* fill up the burst buffer so that we have 6 bursts in there */
+ if (OSMO_UNLIKELY((*mask & 0x3f) != 0x3f)) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "UL burst buffer is not filled up: mask=0x%02x != 0x3f\n",
+ *mask);
+ return 0; /* TODO: send BFI */
+ }
+
+ /* skip decoding of the last 4 bursts of FACCH/H */
+ if (chan_state->ul_ongoing_facch) {
+ chan_state->ul_ongoing_facch = 0;
+ /* we have already sent the first BFI when a FACCH/H frame
+ * was decoded (see below), now send the second one. */
+ trx_sched_meas_avg(chan_state, &meas_avg, meas_avg_mode);
+ /* meas_avg.fn now contains TDMA frame number of the first burst */
+ fn_begin = meas_avg.fn;
+ goto bfi;
+ }
+
+ /* TCH/H: speech and signalling frames are interleaved over 4 and 6 bursts,
+ * respectively, while CSD frames are interleaved over 22 bursts. Unless
+ * we're in CSD mode, decode only the last 6 bursts to avoid introducing
+ * additional delays. */
+ switch (tch_mode) {
+ case GSM48_CMODE_SIGN:
+ meas_avg_mode = SCHED_MEAS_AVG_M_S6N6;
+ /* fall-through */
+ case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
+ rc = gsm0503_tch_hr_decode2(tch_data, BUFTAIL8(bursts_p),
+ !sched_tchh_ul_facch_map[bi->fn % 26],
+ &n_errors, &n_bits_total);
+ if (rc == GSM_HR_BYTES) { /* only for valid *speech* frames */
+ bool is_sid = osmo_hr_check_sid(tch_data, GSM_HR_BYTES);
+ lchan_set_marker(is_sid, lchan); /* DTXu */
+ }
+ break;
+ case GSM48_CMODE_SPEECH_AMR: /* AMR */
+ /* the first FN 0,8,17 or 1,9,18 defines that CMI is included
+ * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR
+ * is included in frame.
+ */
+
+ /* See comment in function rx_tchf_fn() */
+ switch (chan_state->amr_last_dtx) {
+ case AHS_ONSET:
+ case AHS_SID_FIRST_INH:
+ case AHS_SID_UPDATE_INH:
+ lchan_set_marker(false, lchan);
+ break;
+ }
+
+ fn_is_cmi = sched_tchh_ul_amr_cmi_map[bi->fn % 26];
+
+ /* See comment in function rx_tchf_fn() */
+ amr = sizeof(struct amr_hdr);
+ rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, BUFTAIL8(bursts_p),
+ !sched_tchh_ul_facch_map[bi->fn % 26],
+ !fn_is_cmi, chan_state->codec,
+ chan_state->codecs, &chan_state->ul_ft,
+ &chan_state->ul_cmr, &n_errors, &n_bits_total,
+ &chan_state->amr_last_dtx);
+
+ /* Tag all frames that are not regular AMR voice frames
+ as SUB-Frames */
+ if (chan_state->amr_last_dtx != AMR_OTHER) {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "Received AMR DTX frame (rc=%d, BER %d/%d): %s\n",
+ rc, n_errors, n_bits_total,
+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
+ is_sub = 1;
+ }
+
+ /* See comment in function rx_tchf_fn() */
+ switch (chan_state->amr_last_dtx) {
+ case AHS_SID_FIRST_P1:
+ case AHS_SID_FIRST_P2:
+ case AHS_SID_UPDATE:
+ case AHS_SID_UPDATE_CN:
+ lchan_set_marker(true, lchan);
+ lchan->rtp_tx_marker = false;
+ break;
+ }
+
+ switch (chan_state->amr_last_dtx) {
+ case AHS_SID_FIRST_P1:
+ case AHS_SID_FIRST_P2:
+ case AHS_SID_UPDATE:
+ case AHS_SID_UPDATE_CN:
+ case AHS_SID_FIRST_INH:
+ case AHS_SID_UPDATE_INH:
+ meas_avg_mode = SCHED_MEAS_AVG_M_S6N2;
+ break;
+ case AHS_ONSET:
+ meas_avg_mode = SCHED_MEAS_AVG_M_S4N2;
+ break;
+ }
+
+ /* only good speech frames get rtp header */
+ if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
+ if (chan_state->amr_last_dtx == AMR_OTHER) {
+ ft = chan_state->codec[chan_state->ul_ft];
+ } else {
+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */
+ ft = AMR_SID;
+ }
+ rc = osmo_amr_rtp_enc(tch_data,
+ chan_state->codec[chan_state->ul_cmr],
+ ft, AMR_GOOD);
+ }
+
+ break;
+ /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ if (!sched_tchh_ul_csd_map[bi->fn % 26])
+ return 0; /* CSD: skip decoding attempt, need 2 more bursts */
+ /* FACCH/H does not steal TCH/H4.8 frames, but only disturbs some bits */
+ decode_hr_facch(l1ts, bi);
+ rc = gsm0503_tch_hr48_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
+ break;
+ /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ if (!sched_tchh_ul_csd_map[bi->fn % 26])
+ return 0; /* CSD: skip decoding attempt, need 2 more bursts */
+ /* FACCH/H does not steal TCH/H2.4 frames, but only disturbs some bits */
+ decode_hr_facch(l1ts, bi);
+ rc = gsm0503_tch_hr24_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+ &n_errors, &n_bits_total);
+ meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
+ break;
+ default:
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
+ "TCH mode %u invalid, please fix!\n",
+ tch_mode);
+ return -EINVAL;
+ }
+
+ ber10k = compute_ber10k(n_bits_total, n_errors);
+
+ /* average measurements of the last N (depends on mode) bursts */
+ trx_sched_meas_avg(chan_state, &meas_avg, meas_avg_mode);
+ /* meas_avg.fn now contains TDMA frame number of the first burst */
+ fn_begin = meas_avg.fn;
+
+ if (tch_mode == GSM48_CMODE_SPEECH_AMR)
+ trx_loop_amr_input(chan_state, &meas_avg);
+
+ /* Check if the frame is bad */
+ if (rc < 4) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
+ BAD_DATA_MSG_FMT "\n", BAD_DATA_MSG_ARGS);
+ rc = 0; /* this is how we signal BFI to l1sap */
+ } else if (rc == GSM_MACBLOCK_LEN) { /* FACCH */
+ chan_state->ul_ongoing_facch = 1;
+ /* In order to provide an even stream of measurement reports in *speech*
+ * mode, here we intentionally invalidate RSSI for FACCH, so that this
+ * report gets dropped in process_l1sap_meas_data(). The averaged results
+ * will be sent with the first (see below) and second (see above) BFIs. */
+ _sched_compose_ph_data_ind(l1ts, fn_begin, bi->chan,
+ &tch_data[amr], GSM_MACBLOCK_LEN,
+ ber10k,
+ tch_mode == GSM48_CMODE_SIGN ? meas_avg.rssi : 0,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ PRES_INFO_UNKNOWN);
+ ber10k = 0;
+bfi:
+ /* A FACCH/H frame replaces two speech frames, so we need to send two BFIs.
+ * One is sent here, another will be sent two bursts later (see above). */
+ rc = 0;
+ }
+
+ if (rsl_cmode == RSL_CMOD_SPD_SIGN)
+ return 0;
+
+ /* TCH or BFI */
+ return _sched_compose_tch_ind(l1ts, fn_begin, bi->chan,
+ &tch_data[0], rc,
+ ber10k,
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ is_sub);
+}
+
+/* common section for generation of TCH bursts (TCH/H and TCH/F).
+ * FIXME: this function is over-complicated, refactor / get rid of it. */
+extern void tch_dl_dequeue(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br,
+ struct msgb **msg_tch, struct msgb **msg_facch);
+
+struct msgb *tch_dummy_msgb(size_t size, uint8_t pad);
+
+/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
+int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
+ uint8_t tch_mode = chan_state->tch_mode;
+ ubit_t *burst, *bursts_p = chan_state->dl_bursts;
+ uint8_t *mask = &chan_state->dl_mask;
+ struct msgb *msg_facch = NULL;
+ struct msgb *msg_tch = NULL;
+ struct msgb *msg = NULL;
+
+ /* send burst, if we already got a frame */
+ if (br->bid > 0) {
+ if ((*mask & 0x01) != 0x01)
+ return -ENOMSG;
+ goto send_burst;
+ }
+
+ *mask = *mask << 2;
+
+ /* BURST BYPASS */
+
+ /* shift buffer by 2 bursts for interleaving */
+ memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
+ memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
+
+ /* for half-rate CSD we dequeue every 4th burst */
+ if (chan_state->rsl_cmode == RSL_CMOD_SPD_DATA) {
+ if (!sched_tchh_dl_csd_map[br->fn % 26])
+ goto send_burst;
+ }
+
+ /* dequeue a TCH and/or a FACCH message to be transmitted */
+ tch_dl_dequeue(l1ts, br, &msg_tch, &msg_facch);
+
+ /* if we're sending 2 middle bursts of FACCH/H */
+ if (chan_state->dl_ongoing_facch) {
+ /* FACCH/H shall not be scheduled at wrong FNs */
+ OSMO_ASSERT(msg_facch == NULL);
+ msgb_free(msg_tch); /* drop 2nd speech frame */
+ chan_state->dl_ongoing_facch = 0;
+ goto send_burst;
+ }
+
+ /* no message at all, send a dummy L2 frame on FACCH */
+ if (msg_tch == NULL && msg_facch == NULL) {
+ int rc;
+
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No TCH or FACCH prim for transmit.\n");
+ /* - If the channel mode is TCH/HS, transmit a dummy speech block
+ * with inverted CRC3, designed to induce a BFI condition in
+ * the MS receiver.
+ * - If the channel mode is TCH/AHS, transmit a dummy speech
+ * block with inverted CRC6, designed to induce a BFI
+ * condition in the MS receiver.
+ * - If the channel mode is one of the CSD modes, transmit an
+ * idle frame as described in 3GPP TS 44.021, sections 8.1.6
+ * and 10.2.3 (all data, status and E-bits set to binary '1').
+ * - In all other channel modes, transmit dummy FACCH
+ * like we always did before.
+ */
+ switch (tch_mode) {
+ case GSM48_CMODE_DATA_6k0:
+ case GSM48_CMODE_DATA_3k6:
+ break; /* see below */
+ case GSM48_CMODE_SPEECH_V1:
+ rc = gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), NULL, 0);
+ if (rc == 0)
+ goto send_burst;
+ /* fall-through */
+ case GSM48_CMODE_SIGN:
+ default:
+ if (tch_mode == GSM48_CMODE_SPEECH_AMR) {
+ /* the first FN 4,13,21 or 5,14,22 defines that CMI is included
+ * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
+ * included in frame. */
+ rc = gsm0503_tch_ahs_encode(BUFPOS(bursts_p, 0),
+ NULL, 0,
+ !sched_tchh_dl_amr_cmi_map[br->fn % 26],
+ chan_state->codec,
+ chan_state->codecs,
+ chan_state->dl_ft,
+ chan_state->dl_cmr);
+ if (rc == 0)
+ goto send_burst;
+ }
+
+ /* FACCH/H can only be scheduled at specific TDMA offset */
+ if (!sched_tchh_dl_facch_map[br->fn % 26]) {
+ /* FACCH/H is not allowed, send half-filled bursts with even numbered
+ * bits contaning 232 encoded bits of the previous L2 frame, and 232
+ * odd numbered bits all set to 0. */
+ goto send_burst;
+ }
+
+ /* TODO: use randomized padding */
+ msg_facch = tch_dummy_msgb(GSM_MACBLOCK_LEN, GSM_MACBLOCK_PADDING);
+ /* dummy LAPDm func=UI frame */
+ msg_facch->l2h[0] = 0x03;
+ msg_facch->l2h[1] = 0x03;
+ msg_facch->l2h[2] = 0x01;
+ break;
+ }
+ }
+
+ /* Unlike SACCH, FACCH has no dedicated slots on the multiframe layout.
+ * It's multiplexed together with TCH (speech or data) frames basically
+ * by replacing (stealing) their bits, either completely or partly. */
+ msg = (msg_facch != NULL) ? msg_facch : msg_tch;
+ if (msg == msg_facch) {
+ if (chan_state->rsl_cmode != RSL_CMOD_SPD_DATA)
+ chan_state->dl_ongoing_facch = 1;
+ chan_state->dl_facch_bursts = 6;
+ }
+
+ /* populate the buffer with bursts */
+ switch (tch_mode) {
+ case GSM48_CMODE_SIGN:
+ case GSM48_CMODE_SPEECH_V1:
+ gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), msg->l2h, msgb_l2len(msg));
+ break;
+ case GSM48_CMODE_SPEECH_AMR:
+ /* the first FN 4,13,21 or 5,14,22 defines that CMI is included
+ * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
+ * included in frame. */
+ gsm0503_tch_ahs_encode(BUFPOS(bursts_p, 0),
+ msgb_l2(msg), msgb_l2len(msg),
+ !sched_tchh_dl_amr_cmi_map[br->fn % 26],
+ chan_state->codec,
+ chan_state->codecs,
+ chan_state->dl_ft,
+ chan_state->dl_cmr);
+ break;
+ /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(4 * 60, 0x01);
+ gsm0503_tch_hr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ if (msg_facch != NULL)
+ gsm0503_tch_hr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ break;
+ /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ if (msg_tch == NULL)
+ msg_tch = tch_dummy_msgb(4 * 36, 0x01);
+ gsm0503_tch_hr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_tch));
+ if (msg_facch != NULL)
+ gsm0503_tch_hr_facch_encode(BUFPOS(bursts_p, 0), msgb_l2(msg_facch));
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ /* free messages */
+ msgb_free(msg_tch);
+ msgb_free(msg_facch);
+
+send_burst:
+ /* compose burst */
+ burst = BUFPOS(bursts_p, br->bid);
+ memcpy(br->burst + 3, burst, 58);
+ memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
+ memcpy(br->burst + 87, burst + 58, 58);
+
+ br->burst_len = GSM_BURST_LEN;
+
+ if (chan_state->dl_facch_bursts > 0) {
+ chan_state->dl_facch_bursts--;
+ br->flags |= TRX_BR_F_FACCH;
+ }
+
+ *mask |= (1 << br->bid);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c b/src/osmo-bts-trx/sched_lchan_xcch.c
new file mode 100644
index 00000000..0580d33b
--- /dev/null
+++ b/src/osmo-bts-trx/sched_lchan_xcch.c
@@ -0,0 +1,205 @@
+/*
+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * Contributions by sysmocom - s.f.m.c. GmbH
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/coding/gsm0503_coding.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/scheduler.h>
+#include <osmo-bts/scheduler_backend.h>
+
+#include <sched_utils.h>
+
+/* Add two arrays of sbits */
+static void add_sbits(sbit_t *current, const sbit_t *previous)
+{
+ for (unsigned int i = 0; i < BPLEN * 4; i++)
+ current[i] = current[i] / 2 + previous[i] / 2;
+}
+
+/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */
+int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
+{
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
+ sbit_t *burst, *bursts_p = chan_state->ul_bursts;
+ uint32_t *first_fn = &chan_state->ul_first_fn;
+ uint32_t *mask = &chan_state->ul_mask;
+ uint8_t l2[GSM_MACBLOCK_LEN], l2_len;
+ struct l1sched_meas_set meas_avg;
+ int n_errors = 0;
+ int n_bits_total = 0;
+ uint16_t ber10k;
+ int rc;
+ struct gsm_lchan *lchan = chan_state->lchan;
+ bool rep_sacch = L1SAP_IS_LINK_SACCH(trx_chan_desc[bi->chan].link_id) && lchan->rep_acch.ul_sacch_active;
+
+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.
+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
+ return rx_rach_fn(l1ts, bi);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received Data, bid=%u\n", bi->bid);
+
+ /* clear burst & store frame number of first burst */
+ if (bi->bid == 0) {
+ if (rep_sacch) /* Keep a copy to ease decoding in the next repetition pass */
+ memcpy(BUFPOS(bursts_p, 4), BUFPOS(bursts_p, 0), BPLEN * 4);
+ memset(BUFPOS(bursts_p, 0), 0, BPLEN * 4);
+ *mask = 0x0;
+ *first_fn = bi->fn;
+ }
+
+ /* update mask */
+ *mask |= (1 << bi->bid);
+
+ /* store measurements */
+ trx_sched_meas_push(chan_state, bi);
+
+ /* Copy burst to buffer of 4 bursts. If the burst indication contains
+ * no data, ensure that the buffer does not stay uninitialized */
+ burst = bursts_p + bi->bid * 116;
+ if (bi->burst_len > 0) {
+ memcpy(burst, bi->burst + 3, 58);
+ memcpy(burst + 58, bi->burst + 87, 58);
+ }
+
+ /* wait until complete set of bursts */
+ if (bi->bid != 3)
+ return 0;
+
+ /* average measurements of the last 4 bursts */
+ trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_S4N4);
+
+ /* check for complete set of bursts */
+ if ((*mask & 0xf) != 0xf) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi, "Received incomplete data (%u/%u)\n",
+ bi->fn % l1ts->mf_period, l1ts->mf_period);
+
+ /* we require first burst to have correct FN */
+ if (!(*mask & 0x1)) {
+ *mask = 0x0;
+ return 0;
+ }
+ }
+ *mask = 0x0;
+
+ /* decode */
+ rc = gsm0503_xcch_decode(l2, BUFPOS(bursts_p, 0), &n_errors, &n_bits_total);
+ if (rc) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
+ BAD_DATA_MSG_FMT "\n", BAD_DATA_MSG_ARGS);
+ l2_len = 0;
+
+ /* When SACCH Repetition is active, we may try to decode the
+ * current SACCH block by including the information from the
+ * information from the previous SACCH block. See also:
+ * 3GPP TS 44.006, section 11.2 */
+ if (rep_sacch) {
+ add_sbits(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4));
+ rc = gsm0503_xcch_decode(l2, BUFPOS(bursts_p, 0), &n_errors, &n_bits_total);
+ if (rc) {
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
+ "Combining current SACCH block with previous SACCH block also yields bad data (%u/%u)\n",
+ bi->fn % l1ts->mf_period, l1ts->mf_period);
+ } else {
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
+ "Combining current SACCH block with previous SACCH block yields good data (%u/%u)\n",
+ bi->fn % l1ts->mf_period, l1ts->mf_period);
+ l2_len = GSM_MACBLOCK_LEN;
+ }
+ }
+ } else
+ l2_len = GSM_MACBLOCK_LEN;
+
+ ber10k = compute_ber10k(n_bits_total, n_errors);
+
+ return _sched_compose_ph_data_ind(l1ts, *first_fn, bi->chan,
+ &l2[0], l2_len,
+ ber10k,
+ meas_avg.rssi,
+ meas_avg.toa256,
+ meas_avg.ci_cb,
+ PRES_INFO_UNKNOWN);
+}
+
+/* obtain a to-be-transmitted xCCH (e.g SACCH or SDCCH) burst */
+int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ struct msgb *msg = NULL; /* make GCC happy */
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
+ ubit_t *burst, *bursts_p = chan_state->dl_bursts;
+ uint8_t *mask = &chan_state->dl_mask;
+
+ /* send burst, if we already got a frame */
+ if (br->bid > 0) {
+ if ((*mask & 0x01) != 0x01)
+ return -ENOMSG;
+ goto send_burst;
+ }
+
+ *mask = *mask << 4;
+
+ /* get mac block from queue */
+ msg = _sched_dequeue_prim(l1ts, br);
+ if (msg == NULL) {
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No prim for transmit.\n");
+ return -ENODEV;
+ }
+
+ /* check validity of message */
+ if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
+ msgb_l2len(msg), GSM_MACBLOCK_LEN);
+ /* free message */
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ /* BURST BYPASS */
+
+ /* encode bursts */
+ gsm0503_xcch_encode(bursts_p, msg->l2h);
+
+ /* free message */
+ msgb_free(msg);
+
+send_burst:
+ /* compose burst */
+ burst = bursts_p + br->bid * 116;
+ memcpy(br->burst + 3, burst, 58);
+ memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
+ memcpy(br->burst + 87, burst + 58, 58);
+
+ br->burst_len = GSM_BURST_LEN;
+
+ *mask |= (1 << br->bid);
+
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
+
+ return 0;
+}
diff --git a/src/osmo-bts-trx/sched_utils.h b/src/osmo-bts-trx/sched_utils.h
new file mode 100644
index 00000000..a88e06ee
--- /dev/null
+++ b/src/osmo-bts-trx/sched_utils.h
@@ -0,0 +1,51 @@
+/* Auxiliary scheduler utilities.
+ *
+ * (C) 2017 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 Affero 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/>.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/* Burst Payload LENgth (short alias) */
+#define BPLEN GSM_NBITS_NB_GMSK_PAYLOAD
+
+/* Burst BUFfer capacity (in BPLEN units). Why 24? Because CSD frames
+ * are interleaved over 22 bursts, but on TCH/F we decode every 4th burst,
+ * so it must be a multiple of 4. See also 'doc/trx_sched_tch.txt'. */
+#define BUFMAX 24
+
+/* Burst BUFfer position macros */
+#define BUFPOS(buf, n) &buf[(n) * BPLEN]
+#define BUFTAIL8(buf) BUFPOS(buf, (BUFMAX - 8))
+
+extern void *tall_bts_ctx;
+
+#define BAD_DATA_MSG_FMT "Received bad data (rc=%d, BER %d/%d) ending at fn=%u/%u"
+#define BAD_DATA_MSG_ARGS \
+ rc, n_errors, n_bits_total, bi->fn % l1ts->mf_period, l1ts->mf_period
+
+/* Compute the bit error rate in 1/10000 units */
+static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)
+{
+ if (n_bits_total == 0)
+ return 10000;
+ else
+ return 10000 * n_errors / n_bits_total;
+}
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index 45fc7012..00143abe 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -3,6 +3,7 @@
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -14,7 +15,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -32,1598 +33,345 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer_compat.h>
-#include <osmocom/codec/codec.h>
-#include <osmocom/codec/ecu.h>
#include <osmocom/core/bits.h>
#include <osmocom/gsm/a5.h>
-#include <osmocom/coding/gsm0503_coding.h>
+#include <osmocom/gsm/gsm0502.h>
+
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/l1sap.h>
-#include <osmo-bts/msg_utils.h>
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>
+#include <osmo-bts/pcu_if.h>
#include "l1_if.h"
#include "trx_if.h"
-#include "loops.h"
-
-extern void *tall_bts_ctx;
-
-/* Maximum size of a EGPRS message in bytes */
-#define EGPRS_0503_MAX_BYTES 155
-
-
-/* Compute the bit error rate in 1/10000 units */
-static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)
-{
- if (n_bits_total == 0)
- return 10000;
- else
- return 10000 * n_errors / n_bits_total;
-}
-
-/*
- * TX on downlink
- */
-/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
-ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
-{
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting IDLE\n");
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
-
- return NULL;
-}
+#include "btsconfig.h"
-/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
-ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
-{
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting FCCH\n");
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
+#ifdef HAVE_SYSTEMTAP
+/* include the generated probes header and put markers in code */
+#include "probes.h"
+#define TRACE(probe) probe
+#define TRACE_ENABLED(probe) probe ## _ENABLED()
+#else
+/* Wrap the probe to allow it to be removed when no systemtap available */
+#define TRACE(probe)
+#define TRACE_ENABLED(probe) (0)
+#endif /* HAVE_SYSTEMTAP */
- /* BURST BYPASS */
+#define SCHED_FH_PARAMS_FMT "hsn=%u, maio=%u, ma_len=%u"
+#define SCHED_FH_PARAMS_VALS(ts) \
+ (ts)->hopping.hsn, (ts)->hopping.maio, (ts)->hopping.arfcn_num
- return (ubit_t *) _sched_fcch_burst;
-}
-
-/* obtain a to-be-transmitted SCH (synchronization channel) burst */
-ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+static void lchan_report_interf_meas(const struct gsm_lchan *lchan)
{
- static ubit_t bits[GSM_BURST_LEN], burst[78];
- uint8_t sb_info[4];
- struct gsm_time t;
- uint8_t t3p, bsic;
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting SCH\n");
-
- /* BURST BYPASS */
-
- /* create SB info from GSM time and BSIC */
- gsm_fn2gsmtime(&t, fn);
- t3p = t.t3 / 10;
- bsic = l1t->trx->bts->bsic;
- sb_info[0] =
- ((bsic & 0x3f) << 2) |
- ((t.t1 & 0x600) >> 9);
- sb_info[1] =
- ((t.t1 & 0x1fe) >> 1);
- sb_info[2] =
- ((t.t1 & 0x001) << 7) |
- ((t.t2 & 0x1f) << 2) |
- ((t3p & 0x6) >> 1);
- sb_info[3] =
- (t3p & 0x1);
-
- /* encode bursts */
- gsm0503_sch_encode(burst, sb_info);
-
- /* compose burst */
- memset(bits, 0, 3);
- memcpy(bits + 3, burst, 39);
- memcpy(bits + 42, _sched_sch_train, 64);
- memcpy(bits + 106, burst + 39, 39);
- memset(bits + 145, 0, 3);
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
-
- return bits;
-}
-
-/* obtain a to-be-transmitted data (SACCH/SDCCH) burst */
-ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
-{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
- uint8_t link_id = trx_chan_desc[chan].link_id;
- uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
- struct msgb *msg = NULL; /* make GCC happy */
- ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
- static ubit_t bits[GSM_BURST_LEN];
-
- /* send burst, if we already got a frame */
- if (bid > 0) {
- if (!*bursts_p)
- return NULL;
- goto send_burst;
- }
-
- /* send clock information to loops process */
- if (L1SAP_IS_LINK_SACCH(link_id))
- trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]);
-
- /* get mac block from queue */
- msg = _sched_dequeue_prim(l1t, tn, fn, chan);
- if (msg)
- goto got_msg;
-
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
-
-no_msg:
- /* free burst memory */
- if (*bursts_p) {
- talloc_free(*bursts_p);
- *bursts_p = NULL;
- }
- return NULL;
-
-got_msg:
- /* check validity of message */
- if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "
- "(len=%d)\n", msgb_l2len(msg));
- /* free message */
- msgb_free(msg);
- goto no_msg;
- }
-
- /* BURST BYPASS */
-
- /* handle loss detection of SACCH */
- if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
- /* count and send BFI */
- if (++(l1ts->chan_state[chan].lost_frames) > 1) {
- /* TODO: Should we pass old TOA here? Otherwise we risk
- * unnecessary decreasing TA */
-
- /* Send uplink measurement information to L2 */
- l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
- 456, 456, -110, 0);
- /* FIXME: use actual values for BER etc */
- _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,
- -110, 0, 0, 10000,
- PRES_INFO_INVALID);
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+ const struct l1sched_ts *l1ts = ts->priv;
+ enum trx_chan_type dcch, acch;
+ int interf_avg;
+
+ /* We're not interested in active CS channels */
+ if (lchan->state == LCHAN_S_ACTIVE) {
+ if (lchan->type != GSM_LCHAN_PDTCH)
+ return;
+ }
+
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4 ||
+ ts->pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) {
+ dcch = TRXC_SDCCH4_0 + lchan->nr;
+ acch = TRXC_SACCH4_0 + lchan->nr;
+ } else { /* SDCCH/8 otherwise */
+ dcch = TRXC_SDCCH8_0 + lchan->nr;
+ acch = TRXC_SACCH8_0 + lchan->nr;
}
+ break;
+ case GSM_LCHAN_TCH_F:
+ dcch = TRXC_TCHF;
+ acch = TRXC_SACCHTF;
+ break;
+ case GSM_LCHAN_TCH_H:
+ dcch = TRXC_TCHH_0 + lchan->nr;
+ acch = TRXC_SACCHTH_0 + lchan->nr;
+ break;
+ case GSM_LCHAN_PDTCH:
+ /* We use idle TDMA frames on PDCH */
+ dcch = TRXC_IDLE;
+ acch = TRXC_IDLE;
+ break;
+ default:
+ /* Skip other lchan types */
+ return;
}
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 464);
- if (!*bursts_p)
- return NULL;
- }
-
- /* encode bursts */
- gsm0503_xcch_encode(*bursts_p, msg->l2h);
-
- /* free message */
- msgb_free(msg);
-
-send_burst:
- /* compose burst */
- burst = *bursts_p + bid * 116;
- memset(bits, 0, 3);
- memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
- memcpy(bits + 87, burst + 58, 58);
- memset(bits + 145, 0, 3);
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
-
- return bits;
-}
-
-/* obtain a to-be-transmitted PDTCH (packet data) burst */
-ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
-{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
- struct msgb *msg = NULL; /* make GCC happy */
- ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
- enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;
- static ubit_t bits[EGPRS_BURST_LEN];
- int rc = 0;
-
- /* send burst, if we already got a frame */
- if (bid > 0) {
- if (!*bursts_p)
- return NULL;
- goto send_burst;
- }
-
- /* get mac block from queue */
- msg = _sched_dequeue_prim(l1t, tn, fn, chan);
- if (msg)
- goto got_msg;
-
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
-
-no_msg:
- /* free burst memory */
- if (*bursts_p) {
- talloc_free(*bursts_p);
- *bursts_p = NULL;
- }
- return NULL;
-
-got_msg:
- /* BURST BYPASS */
-
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx,
- GSM0503_EGPRS_BURSTS_NBITS);
- if (!*bursts_p)
- return NULL;
- }
-
- /* encode bursts */
- rc = gsm0503_pdtch_egprs_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);
- if (rc < 0)
- rc = gsm0503_pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);
-
- /* check validity of message */
- if (rc < 0) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim invalid length, please FIX! "
- "(len=%ld)\n", msg->tail - msg->l2h);
- /* free message */
- msgb_free(msg);
- goto no_msg;
- } else if (rc == GSM0503_EGPRS_BURSTS_NBITS) {
- *burst_type = TRX_BURST_8PSK;
- } else {
- *burst_type = TRX_BURST_GMSK;
- }
-
- /* free message */
- msgb_free(msg);
-
-send_burst:
- /* compose burst */
- if (*burst_type == TRX_BURST_8PSK) {
- burst = *bursts_p + bid * 348;
- memset(bits, 1, 9);
- memcpy(bits + 9, burst, 174);
- memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
- memcpy(bits + 261, burst + 174, 174);
- memset(bits + 435, 1, 9);
-
- if (nbits)
- *nbits = EGPRS_BURST_LEN;
- } else {
- burst = *bursts_p + bid * 116;
- memset(bits, 0, 3);
- memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
- memcpy(bits + 87, burst + 58, 58);
- memset(bits + 145, 0, 3);
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
- }
+ OSMO_ASSERT(dcch < ARRAY_SIZE(l1ts->chan_state));
+ OSMO_ASSERT(acch < ARRAY_SIZE(l1ts->chan_state));
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
+ interf_avg = (l1ts->chan_state[dcch].meas.interf_avg +
+ l1ts->chan_state[acch].meas.interf_avg) / 2;
- return bits;
+ gsm_lchan_interf_meas_push((struct gsm_lchan *) lchan, interf_avg);
}
-/* determine if the FN is transmitting a CMR (1) or not (0) */
-static inline int fn_is_codec_mode_request(uint32_t fn)
+static void bts_report_interf_meas(const struct gsm_bts *bts)
{
- return (((fn + 4) % 26) >> 2) & 1;
-}
+ const struct gsm_bts_trx *trx;
+ unsigned int tn, ln;
-/* common section for generation of TCH bursts (TCH/H and TCH/F) */
-static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,
- struct msgb **_msg_facch)
-{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- uint8_t rsl_cmode = chan_state->rsl_cmode;
- uint8_t tch_mode = chan_state->tch_mode;
- struct osmo_phsap_prim *l1sap;
-
- /* handle loss detection of received TCH frames */
- if (rsl_cmode == RSL_CMOD_SPD_SPEECH
- && ++(chan_state->lost_frames) > 5) {
- uint8_t tch_data[GSM_FR_BYTES];
- int len;
-
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
- "Missing TCH bursts detected, sending BFI\n");
-
- /* indicate bad frame */
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR / HR */
- if (chan != TRXC_TCHF) { /* HR */
- tch_data[0] = 0x70; /* F = 0, FT = 111 */
- memset(tch_data + 1, 0, 14);
- len = 15;
- break;
- }
- memset(tch_data, 0, GSM_FR_BYTES);
- len = GSM_FR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
- if (chan != TRXC_TCHF)
- goto inval_mode1;
- memset(tch_data, 0, GSM_EFR_BYTES);
- len = GSM_EFR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- len = osmo_amr_rtp_enc(tch_data,
- chan_state->codec[chan_state->dl_cmr],
- chan_state->codec[chan_state->dl_ft], AMR_BAD);
- if (len < 2) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
- "Failed to encode AMR_BAD frame (rc=%d), "
- "not sending BFI\n", len);
- return;
- }
- memset(tch_data + 2, 0, len - 2);
- break;
- default:
-inval_mode1:
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
- len = 0;
- }
- if (len)
- _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len);
- }
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ /* Skip pushing interf_meas for disabled TRX */
+ if (trx->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
+ trx->bb_transc.mo.nm_state.operational != NM_OPSTATE_ENABLED)
+ continue;
- /* get frame and unlink from queue */
- msg1 = _sched_dequeue_prim(l1t, tn, fn, chan);
- msg2 = _sched_dequeue_prim(l1t, tn, fn, chan);
- if (msg1) {
- l1sap = msgb_l1sap_prim(msg1);
- if (l1sap->oph.primitive == PRIM_TCH) {
- msg_tch = msg1;
- if (msg2) {
- l1sap = msgb_l1sap_prim(msg2);
- if (l1sap->oph.primitive == PRIM_TCH) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "TCH twice, please FIX!\n");
- msgb_free(msg2);
- } else
- msg_facch = msg2;
- }
- } else {
- msg_facch = msg1;
- if (msg2) {
- l1sap = msgb_l1sap_prim(msg2);
- if (l1sap->oph.primitive != PRIM_TCH) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "FACCH twice, please FIX!\n");
- msgb_free(msg2);
- } else
- msg_tch = msg2;
- }
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++)
+ lchan_report_interf_meas(&ts->lchan[ln]);
}
- } else if (msg2) {
- l1sap = msgb_l1sap_prim(msg2);
- if (l1sap->oph.primitive == PRIM_TCH)
- msg_tch = msg2;
- else
- msg_facch = msg2;
}
-
- /* check validity of message */
- if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "
- "(len=%d)\n", msgb_l2len(msg_facch));
- /* free message */
- msgb_free(msg_facch);
- msg_facch = NULL;
- }
-
- /* check validity of message, get AMR ft and cmr */
- if (!msg_facch && msg_tch) {
- int len;
- uint8_t cmr_codec;
- int cmr, ft, i;
- enum osmo_amr_type ft_codec;
- enum osmo_amr_quality bfi;
- int8_t sti, cmi;
-
- if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, "
- "because we are not in speech mode\n");
- goto free_bad_msg;
- }
-
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR / HR */
- if (chan != TRXC_TCHF) /* HR */
- len = 15;
- else
- len = GSM_FR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
- if (chan != TRXC_TCHF)
- goto inval_mode2;
- len = GSM_EFR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch),
- &cmr_codec, &cmi, &ft_codec,
- &bfi, &sti);
- cmr = -1;
- ft = -1;
- for (i = 0; i < chan_state->codecs; i++) {
- if (chan_state->codec[i] == cmr_codec)
- cmr = i;
- if (chan_state->codec[i] == ft_codec)
- ft = i;
- }
- if (cmr >= 0) { /* new request */
- chan_state->dl_cmr = cmr;
- /* disable AMR loop */
- trx_loop_amr_set(chan_state, 0);
- } else {
- /* enable AMR loop */
- trx_loop_amr_set(chan_state, 1);
- }
- if (ft < 0) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
- "Codec (FT = %d) of RTP frame not in list\n", ft_codec);
- goto free_bad_msg;
- }
- if (fn_is_codec_mode_request(fn) && chan_state->dl_ft != ft) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Codec (FT = %d) "
- " of RTP cannot be changed now, but in next frame\n", ft_codec);
- goto free_bad_msg;
- }
- chan_state->dl_ft = ft;
- if (bfi == AMR_BAD) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
- "Transmitting 'bad AMR frame'\n");
- goto free_bad_msg;
- }
- break;
- default:
-inval_mode2:
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
- goto free_bad_msg;
- }
- if (len < 0) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send invalid AMR payload\n");
- goto free_bad_msg;
- }
- if (msgb_l2len(msg_tch) != len) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send payload with "
- "invalid length! (expecting %d, received %d)\n",
- len, msgb_l2len(msg_tch));
-free_bad_msg:
- /* free message */
- msgb_free(msg_tch);
- msg_tch = NULL;
- goto send_frame;
- }
- }
-
-send_frame:
- *_msg_tch = msg_tch;
- *_msg_facch = msg_facch;
}
-/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
-ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+/* Find a route (PHY instance) for a given Downlink burst request */
+static struct phy_instance *dlfh_route_br(const struct trx_dl_burst_req *br,
+ struct gsm_bts_trx_ts *ts)
{
- struct msgb *msg_tch = NULL, *msg_facch = NULL;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- uint8_t tch_mode = chan_state->tch_mode;
- ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
- static ubit_t bits[GSM_BURST_LEN];
-
- /* send burst, if we already got a frame */
- if (bid > 0) {
- if (!*bursts_p)
- return NULL;
- goto send_burst;
- }
-
- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
-
- /* BURST BYPASS */
-
- /* allocate burst memory, if not already,
- * otherwise shift buffer by 4 bursts for interleaving */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 928);
- if (!*bursts_p)
- return NULL;
- } else {
- memcpy(*bursts_p, *bursts_p + 464, 464);
- memset(*bursts_p + 464, 0, 464);
- }
-
- /* no message at all */
- if (!msg_tch && !msg_facch) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
- goto send_burst;
- }
-
- /* encode bursts (prioritize FACCH) */
- if (msg_facch)
- gsm0503_tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),
- 1);
- else if (tch_mode == GSM48_CMODE_SPEECH_AMR)
- /* the first FN 4,13,21 defines that CMI is included in frame,
- * the first FN 0,8,17 defines that CMR is included in frame.
- */
- gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,
- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
- chan_state->codec, chan_state->codecs,
- chan_state->dl_ft,
- chan_state->dl_cmr);
- else
- gsm0503_tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1);
-
- /* free message */
- if (msg_tch)
- msgb_free(msg_tch);
- if (msg_facch)
- msgb_free(msg_facch);
-
-send_burst:
- /* compose burst */
- burst = *bursts_p + bid * 116;
- memset(bits, 0, 3);
- memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
- memcpy(bits + 87, burst + 58, 58);
- memset(bits + 145, 0, 3);
+ const struct gsm_bts_trx *trx;
+ struct gsm_time time;
+ uint16_t idx;
- if (nbits)
- *nbits = GSM_BURST_LEN;
+ gsm_fn2gsmtime(&time, br->fn);
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
+ /* Check the "cache" first, so we eliminate frequent lookups */
+ idx = gsm0502_hop_seq_gen(&time, SCHED_FH_PARAMS_VALS(ts), NULL);
+ if (ts->fh_trx_list[idx] != NULL)
+ return ts->fh_trx_list[idx]->pinst;
- return bits;
-}
-
-/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
-ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
-{
- struct msgb *msg_tch = NULL, *msg_facch = NULL;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- uint8_t tch_mode = chan_state->tch_mode;
- ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
- static ubit_t bits[GSM_BURST_LEN];
-
- /* send burst, if we already got a frame */
- if (bid > 0) {
- if (!*bursts_p)
- return NULL;
- goto send_burst;
- }
-
- /* get TCH and/or FACCH */
- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
+ struct bts_trx_priv *priv = (struct bts_trx_priv *) ts->trx->bts->model_priv;
- /* check for FACCH alignment */
- if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
- "even frames, please fix RTS!\n");
- msgb_free(msg_facch);
- msg_facch = NULL;
- }
-
- /* BURST BYPASS */
-
- /* allocate burst memory, if not already,
- * otherwise shift buffer by 2 bursts for interleaving */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 696);
- if (!*bursts_p)
- return NULL;
- } else {
- memcpy(*bursts_p, *bursts_p + 232, 232);
- if (chan_state->dl_ongoing_facch) {
- memcpy(*bursts_p + 232, *bursts_p + 464, 232);
- memset(*bursts_p + 464, 0, 232);
- } else {
- memset(*bursts_p + 232, 0, 232);
+ /* The "cache" may not be filled yet, lookup the transceiver */
+ llist_for_each_entry(trx, &ts->trx->bts->trx_list, list) {
+ if (trx->arfcn == ts->hopping.arfcn_list[idx]) {
+ rate_ctr_inc2(priv->ctrs, BTSTRX_CTR_SCHED_DL_FH_CACHE_MISS);
+ ts->fh_trx_list[idx] = trx;
+ return trx->pinst;
}
}
- /* no message at all */
- if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
- goto send_burst;
- }
-
- /* encode bursts (prioritize FACCH) */
- if (msg_facch) {
- gsm0503_tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch));
- chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */
- } else if (chan_state->dl_ongoing_facch) /* second of two TCH frames */
- chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */
- else if (tch_mode == GSM48_CMODE_SPEECH_AMR)
- /* the first FN 4,13,21 or 5,14,22 defines that CMI is included
- * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
- * included in frame. */
- gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
- chan_state->codec, chan_state->codecs,
- chan_state->dl_ft,
- chan_state->dl_cmr);
- else
- gsm0503_tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch));
+ LOGPTRX(ts->trx, DL1C, LOGL_FATAL, "Failed to find the transceiver (RF carrier) "
+ "for a Downlink burst (fn=%u, tn=%u, " SCHED_FH_PARAMS_FMT ")\n",
+ br->fn, br->tn, SCHED_FH_PARAMS_VALS(ts));
- /* free message */
- if (msg_tch)
- msgb_free(msg_tch);
- if (msg_facch)
- msgb_free(msg_facch);
+ rate_ctr_inc2(priv->ctrs, BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER);
-send_burst:
- /* compose burst */
- burst = *bursts_p + bid * 116;
- memset(bits, 0, 3);
- memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
- memcpy(bits + 87, burst + 58, 58);
- memset(bits + 145, 0, 3);
-
- if (nbits)
- *nbits = GSM_BURST_LEN;
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
-
- return bits;
+ return NULL;
}
+static void bts_sched_init_buffers(struct gsm_bts *bts, const uint32_t fn)
+{
+ struct gsm_bts_trx *trx;
+ uint8_t tn;
-/*
- * RX on uplink (indication to upper layer)
- */
-
-/* 3GPP TS 05.02, section 5.2.7 */
-#define RACH_EXT_TAIL_LEN 8
-#define RACH_SYNCH_SEQ_LEN 41
-
-enum rach_synch_seq_t {
- RACH_SYNCH_SEQ_UNKNOWN = -1,
- RACH_SYNCH_SEQ_TS0, /* GSM, GMSK (default) */
- RACH_SYNCH_SEQ_TS1, /* EGPRS, 8-PSK */
- RACH_SYNCH_SEQ_TS2, /* EGPRS, GMSK */
- RACH_SYNCH_SEQ_NUM
-};
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ struct phy_instance *pinst = trx->pinst;
+ const struct phy_link *plink = pinst->phy_link;
-static struct value_string rach_synch_seq_names[] = {
- { RACH_SYNCH_SEQ_UNKNOWN, "UNKNOWN" },
- { RACH_SYNCH_SEQ_TS0, "TS0: GSM, GMSK" },
- { RACH_SYNCH_SEQ_TS1, "TS1: EGPRS, 8-PSK" },
- { RACH_SYNCH_SEQ_TS2, "TS2: EGPRS, GMSK" },
- { 0, NULL },
-};
+ /* Advance frame number, so the PHY has more time to process bursts */
+ const uint32_t sched_fn = GSM_TDMA_FN_SUM(fn, plink->u.osmotrx.clock_advance);
-static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)
-{
- sbit_t *synch_seq_burst = bits + RACH_EXT_TAIL_LEN;
- enum rach_synch_seq_t seq = RACH_SYNCH_SEQ_TS0;
- int score[RACH_SYNCH_SEQ_NUM] = { 0 };
- int max_score = INT_MIN;
- int i, j;
-
- /* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
- static const char synch_seq_ref[RACH_SYNCH_SEQ_NUM][RACH_SYNCH_SEQ_LEN] = {
- [RACH_SYNCH_SEQ_TS0] = "01001011011111111001100110101010001111000",
- [RACH_SYNCH_SEQ_TS1] = "01010100111110001000011000101111001001101",
- [RACH_SYNCH_SEQ_TS2] = "11101111001001110101011000001101101110111",
- };
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct trx_dl_burst_req *br = &pinst->u.osmotrx.br[tn];
- /* Get a multiplier for j-th bit of i-th synch. sequence */
-#define RACH_SYNCH_SEQ_MULT \
- (synch_seq_ref[i][j] == '1' ? -1 : 1)
-
- /* For each synch. sequence, count the bit match score. Since we deal with
- * soft-bits (-127...127), we sum the absolute values of matching ones,
- * and subtract the absolute values of different ones, so the resulting
- * score is more accurate than it could be with hard-bits. */
- for (i = 0; i < RACH_SYNCH_SEQ_NUM; i++) {
- for (j = 0; j < RACH_SYNCH_SEQ_LEN; j++)
- score[i] += RACH_SYNCH_SEQ_MULT * synch_seq_burst[j];
-
- /* Keep the maximum value updated */
- if (score[i] > max_score) {
- max_score = score[i];
- seq = i;
+ *br = (struct trx_dl_burst_req) {
+ .trx_num = trx->nr,
+ .fn = sched_fn,
+ .tn = tn,
+ };
}
}
- /* Calculate an approximate level of our confidence */
- if (best_score != NULL)
- *best_score = max_score;
+ /* Initialize all timeslots on C0/TRX0 with dummy burst */
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct phy_instance *pinst = bts->c0->pinst;
+ struct trx_dl_burst_req *br = &pinst->u.osmotrx.br[tn];
+ const struct gsm_bts_trx_ts *ts = &bts->c0->ts[tn];
- /* At least 1/3 of a synch. sequence shall match */
- if (max_score < (127 * RACH_SYNCH_SEQ_LEN / 3))
- return RACH_SYNCH_SEQ_UNKNOWN;
+ memcpy(br->burst, _sched_dummy_burst, GSM_BURST_LEN);
+ br->burst_len = GSM_BURST_LEN;
- return seq;
+ /* BCCH carrier power reduction for this timeslot */
+ br->att = ts->c0_power_red_db;
+ }
}
-int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+static void bts_sched_flush_buffers(struct gsm_bts *bts)
{
- struct osmo_phsap_prim l1sap;
- int n_errors, n_bits_total;
- uint16_t ra11;
- uint8_t ra;
- int rc;
-
- /* TSC (Training Sequence Code) is an optional parameter of the UL burst
- * indication. We need this information in order to decide whether an
- * Access Burst is 11-bit encoded or not (see OS#1854). If this information
- * is absent, we try to correlate the received synch. sequence with the
- * known ones (3GPP TS 05.02, section 5.2.7), and fall-back to the default
- * TS0 if it fails. */
- enum rach_synch_seq_t synch_seq = RACH_SYNCH_SEQ_TS0;
- int best_score = 127 * RACH_SYNCH_SEQ_LEN;
-
- /* If chan != TRXC_RACH, this is a handover RACH, which is always encoded
- * as 8-bit and should contain the generic training sequence (TS0). */
- if (chan == TRXC_RACH) {
- if (bi->flags & TRX_BI_F_TS_INFO)
- synch_seq = (enum rach_synch_seq_t) bi->tsc;
- else
- synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);
- }
+ const struct gsm_bts_trx *trx;
+ unsigned int tn;
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received%s RACH (%s): rssi=%d toa256=%d",
- (chan != TRXC_RACH) ? " handover" : "",
- get_value_string(rach_synch_seq_names, synch_seq),
- bi->rssi, bi->toa256);
- if (bi->flags & TRX_BI_F_CI_CB)
- LOGPC(DL1P, LOGL_DEBUG, " C/I=%d cB", bi->ci_cb);
- else
- LOGPC(DL1P, LOGL_DEBUG, " match=%.1f%%",
- best_score * 100.0 / (127 * RACH_SYNCH_SEQ_LEN));
- LOGPC(DL1P, LOGL_DEBUG, "\n");
-
- /* Compose a new L1SAP primitive */
- memset(&l1sap, 0x00, sizeof(l1sap));
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, NULL);
- l1sap.u.rach_ind.chan_nr = trx_chan_desc[chan].chan_nr | bi->tn;
- l1sap.u.rach_ind.acc_delay = (bi->toa256 >= 0) ? bi->toa256 / 256 : 0;
- l1sap.u.rach_ind.acc_delay_256bits = bi->toa256;
- l1sap.u.rach_ind.rssi = bi->rssi;
- l1sap.u.rach_ind.fn = bi->fn;
-
- /* Link quality is defined by C/I (Carrier-to-Interference ratio),
- * which has optional presence. If it's absent, report the
- * minimum acceptable value to pass L1SAP checks. */
- if (bi->flags & TRX_BI_F_CI_CB)
- l1sap.u.rach_ind.lqual_cb = bi->ci_cb;
- else
- l1sap.u.rach_ind.lqual_cb = l1t->trx->bts->min_qual_rach;
-
- /* Decode RACH depending on its synch. sequence */
- switch (synch_seq) {
- case RACH_SYNCH_SEQ_TS1:
- case RACH_SYNCH_SEQ_TS2:
- rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
- l1t->trx->bts->bsic, &n_errors, &n_bits_total);
- if (rc) {
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received bad Access Burst\n");
- return 0;
- }
-
- if (synch_seq == RACH_SYNCH_SEQ_TS1)
- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_1;
- else
- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_2;
-
- l1sap.u.rach_ind.is_11bit = 1;
- l1sap.u.rach_ind.ra = ra11;
- break;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ const struct phy_instance *pinst = trx->pinst;
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- case RACH_SYNCH_SEQ_TS0:
- default:
- /* Fall-back to the default TS0 if needed */
- if (synch_seq != RACH_SYNCH_SEQ_TS0) {
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Falling-back to the default TS0\n");
- synch_seq = RACH_SYNCH_SEQ_TS0;
- }
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ const struct trx_dl_burst_req *br;
- rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
- l1t->trx->bts->bsic, &n_errors, &n_bits_total);
- if (rc) {
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received bad Access Burst\n");
- return 0;
+ br = &pinst->u.osmotrx.br[tn];
+ if (!br->burst_len)
+ continue;
+ trx_if_send_burst(l1h, br);
}
- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;
- l1sap.u.rach_ind.is_11bit = 0;
- l1sap.u.rach_ind.ra = ra;
- break;
+ /* Batch all timeslots into a single TRXD PDU */
+ trx_if_send_burst(l1h, NULL);
}
-
- l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);
-
- /* forward primitive */
- l1sap_up(l1t->trx, &l1sap);
-
- return 0;
}
-/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */
-int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+/* schedule one frame for a shadow timeslot, merge bursts */
+static void _sched_dl_shadow_burst(const struct gsm_bts_trx_ts *ts,
+ struct trx_dl_burst_req *br)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
- uint32_t *first_fn = &chan_state->ul_first_fn;
- uint8_t *mask = &chan_state->ul_mask;
- float *rssi_sum = &chan_state->rssi_sum;
- uint8_t *rssi_num = &chan_state->rssi_num;
- int32_t *toa256_sum = &chan_state->toa256_sum;
- uint8_t *toa_num = &chan_state->toa_num;
- int32_t *ci_cb_sum = &chan_state->ci_cb_sum;
- uint8_t *ci_cb_num = &chan_state->ci_cb_num;
- uint8_t l2[GSM_MACBLOCK_LEN], l2_len;
- int n_errors, n_bits_total;
- int16_t lqual_cb;
- uint16_t ber10k;
- int rc;
-
- /* handle RACH, if handover RACH detection is turned on */
- if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1t, chan, bid, bi);
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received Data, bid=%u\n", bid);
-
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 464);
- if (!*bursts_p)
- return -ENOMEM;
- }
-
- /* clear burst & store frame number of first burst */
- if (bid == 0) {
- memset(*bursts_p, 0, 464);
- *mask = 0x0;
- *first_fn = bi->fn;
- *rssi_sum = 0;
- *rssi_num = 0;
- *toa256_sum = 0;
- *toa_num = 0;
- *ci_cb_sum = 0;
- *ci_cb_num = 0;
- }
-
- /* update mask + RSSI */
- *mask |= (1 << bid);
- *rssi_sum += bi->rssi;
- (*rssi_num)++;
- *toa256_sum += bi->toa256;
- (*toa_num)++;
-
- /* C/I: Carrier-to-Interference ratio (in centiBels) */
- if (bi->flags & TRX_BI_F_CI_CB) {
- *ci_cb_sum += bi->ci_cb;
- (*ci_cb_num)++;
- }
-
- /* copy burst to buffer of 4 bursts */
- burst = *bursts_p + bid * 116;
- memcpy(burst, bi->burst + 3, 58);
- memcpy(burst + 58, bi->burst + 87, 58);
-
- /* send burst information to loops process */
- if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
- trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | bi->tn,
- chan_state, bi->rssi, bi->toa256);
- }
-
- /* wait until complete set of bursts */
- if (bid != 3)
- return 0;
+ struct l1sched_ts *l1ts = ts->priv;
+
+ /* For the shadow timeslots, physical channel type can be either
+ * GSM_PCHAN_TCH_{F,H} or GSM_PCHAN_NONE. Even if the primary
+ * timeslot is a dynamic timeslot, it's always a concrete value. */
+ if (ts->pchan == GSM_PCHAN_NONE)
+ return;
+
+ struct trx_dl_burst_req sbr = {
+ .trx_num = br->trx_num,
+ .fn = br->fn,
+ .tn = br->tn,
+ };
- /* check for complete set of bursts */
- if ((*mask & 0xf) != 0xf) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received incomplete data (%u/%u)\n",
- *first_fn, (*first_fn) % l1ts->mf_period);
+ _sched_dl_burst(l1ts, &sbr);
- /* we require first burst to have correct FN */
- if (!(*mask & 0x1)) {
- *mask = 0x0;
- return 0;
- }
+ if (br->burst_len != 0 && sbr.burst_len != 0) { /* Both present */
+ memcpy(br->burst + GSM_BURST_LEN, sbr.burst, GSM_BURST_LEN);
+ br->burst_len = 2 * GSM_BURST_LEN;
+ br->mod = TRX_MOD_T_AQPSK;
+ /* FIXME: SCPIR is hard-coded to 0 */
+ } else if (br->burst_len == 0) {
+ /* No primary burst, send shadow burst alone */
+ memcpy(br, &sbr, sizeof(sbr));
+ } else if (sbr.burst_len == 0) {
+ /* No shadow burst, send primary burst alone */
+ return;
}
- *mask = 0x0;
-
- /* decode */
- rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);
- if (rc) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received bad data (%u/%u)\n",
- *first_fn, (*first_fn) % l1ts->mf_period);
- l2_len = 0;
- } else
- l2_len = GSM_MACBLOCK_LEN;
-
- /* Send uplink measurement information to L2 */
- l1if_process_meas_res(l1t->trx, bi->tn, *first_fn,
- trx_chan_desc[chan].chan_nr | bi->tn,
- n_errors, n_bits_total,
- *rssi_sum / *rssi_num,
- *toa256_sum / *toa_num);
- lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;
- ber10k = compute_ber10k(n_bits_total, n_errors);
- return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn,
- chan, l2, l2_len,
- *rssi_sum / *rssi_num,
- *toa256_sum / *toa_num,
- lqual_cb, ber10k,
- PRES_INFO_UNKNOWN);
}
-/*! \brief a single PDTCH burst was received by the PHY, process it */
-int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+/* schedule all frames of all TRX for given FN */
+static void bts_sched_fn(struct gsm_bts *bts, const uint32_t fn)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
- uint32_t *first_fn = &chan_state->ul_first_fn;
- uint8_t *mask = &chan_state->ul_mask;
- float *rssi_sum = &chan_state->rssi_sum;
- uint8_t *rssi_num = &chan_state->rssi_num;
- int32_t *toa256_sum = &chan_state->toa256_sum;
- uint8_t *toa_num = &chan_state->toa_num;
- int32_t *ci_cb_sum = &chan_state->ci_cb_sum;
- uint8_t *ci_cb_num = &chan_state->ci_cb_num;
- uint8_t l2[EGPRS_0503_MAX_BYTES];
- int n_errors, n_bursts_bits, n_bits_total;
- int16_t lqual_cb;
- uint16_t ber10k;
- int rc;
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received PDTCH bid=%u\n", bid);
-
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx,
- GSM0503_EGPRS_BURSTS_NBITS);
- if (!*bursts_p)
- return -ENOMEM;
- }
-
- /* clear burst */
- if (bid == 0) {
- memset(*bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS);
- *mask = 0x0;
- *first_fn = bi->fn;
- *rssi_sum = 0;
- *rssi_num = 0;
- *toa256_sum = 0;
- *toa_num = 0;
- *ci_cb_sum = 0;
- *ci_cb_num = 0;
- }
-
- /* update mask + rssi */
- *mask |= (1 << bid);
- *rssi_sum += bi->rssi;
- (*rssi_num)++;
- *toa256_sum += bi->toa256;
- (*toa_num)++;
-
- /* C/I: Carrier-to-Interference ratio (in centiBels) */
- if (bi->flags & TRX_BI_F_CI_CB) {
- *ci_cb_sum += bi->ci_cb;
- (*ci_cb_num)++;
- }
-
- /* copy burst to buffer of 4 bursts */
- if (bi->burst_len == EGPRS_BURST_LEN) {
- burst = *bursts_p + bid * 348;
- memcpy(burst, bi->burst + 9, 174);
- memcpy(burst + 174, bi->burst + 261, 174);
- n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS;
- } else {
- burst = *bursts_p + bid * 116;
- memcpy(burst, bi->burst + 3, 58);
- memcpy(burst + 58, bi->burst + 87, 58);
- n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;
- }
-
- /* wait until complete set of bursts */
- if (bid != 3)
- return 0;
-
- /* check for complete set of bursts */
- if ((*mask & 0xf) != 0xf) {
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received incomplete frame (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- }
- *mask = 0x0;
-
- /*
- * Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we
- * do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS,
- * then we incur decoding overhead of 31 bits on the Type 3 EGPRS
- * header, which is tolerable.
- */
- rc = gsm0503_pdtch_egprs_decode(l2, *bursts_p, n_bursts_bits,
- NULL, &n_errors, &n_bits_total);
-
- if ((bi->burst_len == GSM_BURST_LEN) && (rc < 0)) {
- rc = gsm0503_pdtch_decode(l2, *bursts_p, NULL,
- &n_errors, &n_bits_total);
- }
-
-
- /* Send uplink measurement information to L2 */
- l1if_process_meas_res(l1t->trx, bi->tn, *first_fn,
- trx_chan_desc[chan].chan_nr | bi->tn,
- n_errors, n_bits_total,
- *rssi_sum / *rssi_num,
- *toa256_sum / *toa_num);
-
- if (rc <= 0) {
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received bad PDTCH (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- return 0;
- }
-
- lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;
- ber10k = compute_ber10k(n_bits_total, n_errors);
- return _sched_compose_ph_data_ind(l1t, bi->tn,
- *first_fn, chan, l2, rc,
- *rssi_sum / *rssi_num,
- *toa256_sum / *toa_num,
- lqual_cb, ber10k,
- PRES_INFO_BOTH);
-}
+ struct gsm_bts_trx *trx;
+ unsigned int tn;
-/*! \brief a single TCH/F burst was received by the PHY, process it */
-int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
-{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
- uint32_t *first_fn = &chan_state->ul_first_fn;
- uint8_t *mask = &chan_state->ul_mask;
- uint8_t rsl_cmode = chan_state->rsl_cmode;
- uint8_t tch_mode = chan_state->tch_mode;
- uint8_t tch_data[128]; /* just to be safe */
- int rc, amr = 0;
- int n_errors, n_bits_total;
- bool bfi_flag = false;
- struct gsm_lchan *lchan =
- get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);
-
- /* handle rach, if handover rach detection is turned on */
- if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1t, chan, bid, bi);
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received TCH/F, bid=%u\n", bid);
-
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 928);
- if (!*bursts_p)
- return -ENOMEM;
- }
+ /* Report interference measurements */
+ if (fn % 104 == 0) /* SACCH period */
+ bts_report_interf_meas(bts);
- /* clear burst */
- if (bid == 0) {
- memset(*bursts_p + 464, 0, 464);
- *mask = 0x0;
- *first_fn = bi->fn;
- }
+ /* send time indication */
+ l1if_mph_time_ind(bts, fn);
- /* update mask */
- *mask |= (1 << bid);
+ /* Initialize Downlink burst buffers */
+ bts_sched_init_buffers(bts, fn);
- /* copy burst to end of buffer of 8 bursts */
- burst = *bursts_p + bid * 116 + 464;
- memcpy(burst, bi->burst + 3, 58);
- memcpy(burst + 58, bi->burst + 87, 58);
+ /* Populate Downlink burst buffers for each TRX/TS */
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ const struct phy_link *plink = trx->pinst->phy_link;
+ struct trx_l1h *l1h = trx->pinst->u.osmotrx.hdl;
- /* wait until complete set of bursts */
- if (bid != 3)
- return 0;
+ /* we don't schedule, if power is off */
+ if (!trx_if_powered(l1h))
+ continue;
- /* check for complete set of bursts */
- if ((*mask & 0xf) != 0xf) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received incomplete frame (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- }
- *mask = 0x0;
-
- /* decode
- * also shift buffer by 4 bursts for interleaving */
- switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
- : tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR */
- rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total);
- if (rc >= 0)
- lchan_set_marker(osmo_fr_check_sid(tch_data, rc), lchan); /* DTXu */
- break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
- rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total);
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- /* the first FN 0,8,17 defines that CMI is included in frame,
- * the first FN 4,13,21 defines that CMR is included in frame.
- * NOTE: A frame ends 7 FN after start.
- */
- rc = gsm0503_tch_afs_decode(tch_data + 2, *bursts_p,
- (((bi->fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,
- chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &n_errors, &n_bits_total);
- if (rc)
- trx_loop_amr_input(l1t,
- trx_chan_desc[chan].chan_nr | bi->tn, chan_state,
- (float)n_errors/(float)n_bits_total);
- amr = 2; /* we store tch_data + 2 header bytes */
- /* only good speech frames get rtp header */
- if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
- rc = osmo_amr_rtp_enc(tch_data,
- chan_state->codec[chan_state->ul_cmr],
- chan_state->codec[chan_state->ul_ft], AMR_GOOD);
- }
- break;
- default:
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "TCH mode %u invalid, please fix!\n",
- tch_mode);
- return -EINVAL;
- }
- memcpy(*bursts_p, *bursts_p + 464, 464);
-
- /* Send uplink measurement information to L2 */
- l1if_process_meas_res(l1t->trx, bi->tn, *first_fn,
- trx_chan_desc[chan].chan_nr | bi->tn,
- n_errors, n_bits_total,
- bi->rssi, bi->toa256);
-
- /* Check if the frame is bad */
- if (rc < 0) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received bad data (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- bfi_flag = true;
- } else if (rc < 4) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received bad data (%u/%u) with invalid codec mode %d\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
- bfi_flag = true;
- }
+ /* process every TS of TRX */
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct phy_instance *pinst = trx->pinst;
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ struct l1sched_ts *l1ts = ts->priv;
+ struct trx_dl_burst_req *br;
- if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)
- osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);
-
- if (bfi_flag)
- goto bfi;
-
- /* FACCH */
- if (rc == GSM_MACBLOCK_LEN) {
- uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
- _sched_compose_ph_data_ind(l1t, bi->tn,
- /* FIXME: this calculation is wrong */
- (bi->fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
- tch_data + amr, GSM_MACBLOCK_LEN,
- /* FIXME: AVG RSSI and ToA256 */
- bi->rssi, bi->toa256,
- 0 /* FIXME: AVG C/I */,
- ber10k, PRES_INFO_UNKNOWN);
-bfi:
- if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
- /* indicate bad frame */
- if (lchan->tch.dtx.ul_sid) {
- /* DTXu: pause in progress. Push empty payload to upper layers */
- rc = 0;
- goto compose_l1sap;
+ /* ready-to-send */
+ TRACE(OSMO_BTS_TRX_DL_RTS_START(trx->nr, tn, fn));
+ _sched_rts(l1ts, GSM_TDMA_FN_SUM(fn, plink->u.osmotrx.clock_advance
+ + plink->u.osmotrx.rts_advance));
+ TRACE(OSMO_BTS_TRX_DL_RTS_DONE(trx->nr, tn, fn));
+
+ /* pre-initialized buffer for the Downlink burst */
+ br = &pinst->u.osmotrx.br[tn];
+
+ /* resolve PHY instance if freq. hopping is enabled */
+ if (ts->hopping.enabled) {
+ pinst = dlfh_route_br(br, ts);
+ if (pinst == NULL)
+ continue;
+ /* simply use a different buffer */
+ br = &pinst->u.osmotrx.br[tn];
}
- /* If there is an ECU active on this channel, use its output */
- if (lchan->ecu_state) {
- rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);
- goto compose_l1sap;
- }
+ /* get burst for the primary timeslot */
+ _sched_dl_burst(l1ts, br);
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR */
- memset(tch_data, 0, GSM_FR_BYTES);
- tch_data[0] = 0xd0;
- rc = GSM_FR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
- memset(tch_data, 0, GSM_EFR_BYTES);
- tch_data[0] = 0xc0;
- rc = GSM_EFR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- rc = osmo_amr_rtp_enc(tch_data,
- chan_state->codec[chan_state->dl_cmr],
- chan_state->codec[chan_state->dl_ft],
- AMR_BAD);
- if (rc < 2) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "Failed to encode AMR_BAD frame (rc=%d), "
- "not sending BFI\n", rc);
- return -EINVAL;
- }
- memset(tch_data + 2, 0, rc - 2);
- break;
- default:
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "TCH mode %u invalid, please fix!\n", tch_mode);
- return -EINVAL;
- }
+ /* get burst for the shadow timeslot */
+ _sched_dl_shadow_burst(ts->vamos.peer, br);
}
}
- if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
- return 0;
-
- /* TCH or BFI */
-compose_l1sap:
- return _sched_compose_tch_ind(l1t, bi->tn,
- /* FIXME: this calculation is wrong */
- (bi->fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
- tch_data, rc);
+ /* Send everything to the PHY */
+ bts_sched_flush_buffers(bts);
}
-/*! \brief a single TCH/H burst was received by the PHY, process it */
-int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+/* Find a route (TRX instance) for a given Uplink burst indication */
+static struct gsm_bts_trx *ulfh_route_bi(const struct trx_ul_burst_ind *bi,
+ const struct gsm_bts_trx *src_trx)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
- uint32_t *first_fn = &chan_state->ul_first_fn;
- uint8_t *mask = &chan_state->ul_mask;
- uint8_t rsl_cmode = chan_state->rsl_cmode;
- uint8_t tch_mode = chan_state->tch_mode;
- uint8_t tch_data[128]; /* just to be safe */
- int rc, amr = 0;
- int n_errors, n_bits_total;
- bool bfi_flag = false;
- struct gsm_lchan *lchan =
- get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);
- /* Note on FN-10: If we are at FN 10, we decoded an even aligned
- * TCH/FACCH frame, because our burst buffer carries 6 bursts.
- * Even FN ending at: 10,11,19,20,2,3
- */
- int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1;
-
- /* handle RACH, if handover RACH detection is turned on */
- if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1t, chan, bid, bi);
-
- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
- "Received TCH/H, bid=%u\n", bid);
-
- /* allocate burst memory, if not already */
- if (!*bursts_p) {
- *bursts_p = talloc_zero_size(tall_bts_ctx, 696);
- if (!*bursts_p)
- return -ENOMEM;
- }
-
- /* clear burst */
- if (bid == 0) {
- memset(*bursts_p + 464, 0, 232);
- *mask = 0x0;
- *first_fn = bi->fn;
- }
-
- /* update mask */
- *mask |= (1 << bid);
-
- /* copy burst to end of buffer of 6 bursts */
- burst = *bursts_p + bid * 116 + 464;
- memcpy(burst, bi->burst + 3, 58);
- memcpy(burst + 58, bi->burst + 87, 58);
+ struct gsm_bts_trx *trx;
+ struct gsm_time time;
+ uint16_t arfcn;
- /* wait until complete set of bursts */
- if (bid != 1)
- return 0;
+ gsm_fn2gsmtime(&time, bi->fn);
- /* check for complete set of bursts */
- if ((*mask & 0x3) != 0x3) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received incomplete frame (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- }
- *mask = 0x0;
-
- /* skip second of two TCH frames of FACCH was received */
- if (chan_state->ul_ongoing_facch) {
- chan_state->ul_ongoing_facch = 0;
- memcpy(*bursts_p, *bursts_p + 232, 232);
- memcpy(*bursts_p + 232, *bursts_p + 464, 232);
- goto bfi;
- }
+ llist_for_each_entry(trx, &src_trx->bts->trx_list, list) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[bi->tn];
+ if (!ts->hopping.enabled)
+ continue;
- /* decode
- * also shift buffer by 4 bursts for interleaving */
- switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
- : tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
- /* Note on FN-10: If we are at FN 10, we decoded an even aligned
- * TCH/FACCH frame, because our burst buffer carries 6 bursts.
- * Even FN ending at: 10,11,19,20,2,3
- */
- rc = gsm0503_tch_hr_decode(tch_data, *bursts_p,
- fn_is_odd, &n_errors, &n_bits_total);
- if (rc >= 0) /* DTXu */
- lchan_set_marker(osmo_hr_check_sid(tch_data, rc), lchan);
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- /* the first FN 0,8,17 or 1,9,18 defines that CMI is included
- * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR
- * is included in frame.
- */
- rc = gsm0503_tch_ahs_decode(tch_data + 2, *bursts_p,
- fn_is_odd, fn_is_odd, chan_state->codec,
- chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &n_errors, &n_bits_total);
- if (rc)
- trx_loop_amr_input(l1t,
- trx_chan_desc[chan].chan_nr | bi->tn, chan_state,
- (float)n_errors/(float)n_bits_total);
- amr = 2; /* we store tch_data + 2 two */
- /* only good speech frames get rtp header */
- if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
- rc = osmo_amr_rtp_enc(tch_data,
- chan_state->codec[chan_state->ul_cmr],
- chan_state->codec[chan_state->ul_ft], AMR_GOOD);
- }
- break;
- default:
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "TCH mode %u invalid, please fix!\n",
- tch_mode);
- return -EINVAL;
- }
- memcpy(*bursts_p, *bursts_p + 232, 232);
- memcpy(*bursts_p + 232, *bursts_p + 464, 232);
-
- /* Send uplink measurement information to L2 */
- l1if_process_meas_res(l1t->trx, bi->tn,
- *first_fn /* FIXME: this is wrong */,
- trx_chan_desc[chan].chan_nr | bi->tn,
- n_errors, n_bits_total, bi->rssi, bi->toa256);
-
- /* Check if the frame is bad */
- if (rc < 0) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received bad data (%u/%u)\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period);
- bfi_flag = true;
- } else if (rc < 4) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
- "Received bad data (%u/%u) with invalid codec mode %d\n",
- bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
- bfi_flag = true;
+ arfcn = gsm0502_hop_seq_gen(&time, SCHED_FH_PARAMS_VALS(ts), ts->hopping.arfcn_list);
+ if (src_trx->arfcn == arfcn)
+ return trx;
}
- if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)
- osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);
-
- if (bfi_flag)
- goto bfi;
-
- /* FACCH */
- if (rc == GSM_MACBLOCK_LEN) {
- chan_state->ul_ongoing_facch = 1;
- uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
- _sched_compose_ph_data_ind(l1t, bi->tn,
- /* FIXME: what the hell is this?!? */
- (bi->fn + GSM_HYPERFRAME - 10 - ((bi->fn % 26) >= 19)) % GSM_HYPERFRAME, chan,
- tch_data + amr, GSM_MACBLOCK_LEN,
- /* FIXME: AVG both RSSI and ToA */
- bi->rssi, bi->toa256,
- 0 /* FIXME: AVG C/I */,
- ber10k, PRES_INFO_UNKNOWN);
-bfi:
- /* FIXME: a FACCH/H frame replaces two speech frames,
- * so we actually need to send two bad frame indications! */
- if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
- /* indicate bad frame */
- if (lchan->tch.dtx.ul_sid) {
- /* DTXu: pause in progress. Push empty payload to upper layers */
- rc = 0;
- goto compose_l1sap;
- }
+ LOGPTRX(src_trx, DL1C, LOGL_DEBUG, "Failed to find the transceiver (RF carrier) "
+ "for an Uplink burst (fn=%u, tn=%u, " SCHED_FH_PARAMS_FMT ")\n",
+ bi->fn, bi->tn, SCHED_FH_PARAMS_VALS(&src_trx->ts[bi->tn]));
- /* If there is an ECU active on this channel, use its output */
- if (lchan->ecu_state) {
- rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);
- goto compose_l1sap;
- }
+ struct bts_trx_priv *priv = (struct bts_trx_priv *) src_trx->bts->model_priv;
+ rate_ctr_inc2(priv->ctrs, BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER);
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* HR */
- tch_data[0] = 0x70; /* F = 0, FT = 111 */
- memset(tch_data + 1, 0, 14);
- rc = 15;
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- rc = osmo_amr_rtp_enc(tch_data,
- chan_state->codec[chan_state->dl_cmr],
- chan_state->codec[chan_state->dl_ft],
- AMR_BAD);
- if (rc < 2) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "Failed to encode AMR_BAD frame (rc=%d), "
- "not sending BFI\n", rc);
- return -EINVAL;
- }
- memset(tch_data + 2, 0, rc - 2);
- break;
- default:
- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,
- "TCH mode %u invalid, please fix!\n", tch_mode);
- return -EINVAL;
- }
- }
- }
-
- if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
- return 0;
-
-compose_l1sap:
- /* TCH or BFI */
- /* Note on FN 19 or 20: If we received the last burst of a frame,
- * it actually starts at FN 8 or 9. A burst starting there, overlaps
- * with the slot 12, so an extra FN must be subtracted to get correct
- * start of frame.
- */
- return _sched_compose_tch_ind(l1t, bi->tn,
- /* FIXME: what the hell is this?!? */
- (bi->fn + GSM_HYPERFRAME - 10 - ((bi->fn%26)==19) - ((bi->fn%26)==20)) % GSM_HYPERFRAME,
- chan, tch_data, rc);
+ return NULL;
}
-/* schedule all frames of all TRX for given FN */
-static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
+/* Route a given Uplink burst indication to the scheduler depending on freq. hopping state */
+int trx_sched_route_burst_ind(const struct gsm_bts_trx *trx, struct trx_ul_burst_ind *bi)
{
- struct gsm_bts_trx *trx;
- uint8_t tn;
- const ubit_t *bits;
- uint8_t gain;
- uint16_t nbits = 0;
-
- /* send time indication */
- l1if_mph_time_ind(bts, fn);
+ /* no frequency hopping => nothing to do */
+ if (!trx->ts[bi->tn].hopping.enabled)
+ return trx_sched_ul_burst(trx->ts[bi->tn].priv, bi);
- /* process every TRX */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- 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;
+ trx = ulfh_route_bi(bi, trx);
+ if (trx == NULL)
+ return -ENODEV;
- /* we don't schedule, if power is off */
- if (!trx_if_powered(l1h))
- continue;
-
- /* process every TS of TRX */
- for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
- /* ready-to-send */
- _sched_rts(l1t, tn,
- (fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME);
- /* get burst for FN */
- bits = _sched_dl_burst(l1t, tn, fn, &nbits);
- if (!bits) {
- /* if no bits, send no burst */
- continue;
- } else
- gain = 0;
- if (nbits)
- trx_if_send_burst(l1h, tn, fn, gain, bits, nbits);
- }
- }
-
- return 0;
+ return trx_sched_ul_burst(trx->ts[bi->tn].priv, bi);
}
-/*
- * TRX frame clock handling
- *
- * In a "normal" synchronous PHY layer, we would be polled every time
- * the PHY needs data for a given frame number. However, the
- * OpenBTS-inherited TRX protocol works differently: We (L1) must
- * autonomously send burst data based on our own clock, and every so
- * often (currently every ~ 216 frames), we get a clock indication from
- * the TRX.
- *
- * We're using a MONOTONIC timerfd interval timer for the 4.615ms frame
- * intervals, and then compute + send the 8 bursts for that frame.
- *
- * Upon receiving a clock indication from the TRX, we compensate
- * accordingly: If we were transmitting too fast, we're delaying the
- * next interval timer accordingly. If we were too slow, we immediately
- * send burst data for the missing frame numbers.
- */
-
-/*! clock state of a given TRX */
-struct osmo_trx_clock_state {
- /*! number of FN periods without TRX clock indication */
- uint32_t fn_without_clock_ind;
- struct {
- /*! last FN we processed based on FN period timer */
- uint32_t fn;
- /*! time at which we last processed FN */
- struct timespec tv;
- } last_fn_timer;
- struct {
- /*! last FN we received a clock indication for */
- uint32_t fn;
- /*! time at which we received the last clock indication */
- struct timespec tv;
- } last_clk_ind;
- /*! Osmocom FD wrapper for timerfd */
- struct osmo_fd fn_timer_ofd;
-};
-
-/* TODO: This must go and become part of the phy_link */
-static struct osmo_trx_clock_state g_clk_s = { .fn_timer_ofd.fd = -1 };
-
-/*! duration of a GSM frame in nano-seconds. (120ms/26) */
-#define FRAME_DURATION_nS 4615384
-/*! duration of a GSM frame in micro-seconds (120s/26) */
-#define FRAME_DURATION_uS (FRAME_DURATION_nS/1000)
/*! maximum number of 'missed' frame periods we can tolerate of OS doesn't schedule us*/
#define MAX_FN_SKEW 50
/*! maximum number of frame periods we can tolerate without TRX Clock Indication*/
@@ -1641,9 +389,9 @@ static inline int64_t compute_elapsed_us(const struct timespec *last, const stru
/*! compute the number of frame number intervals elapsed between \a last and \a now */
static inline int compute_elapsed_fn(const uint32_t last, const uint32_t now)
{
- int elapsed_fn = (now + GSM_HYPERFRAME - last) % GSM_HYPERFRAME;
+ int elapsed_fn = GSM_TDMA_FN_SUB(now, last);
if (elapsed_fn >= 135774)
- elapsed_fn -= GSM_HYPERFRAME;
+ elapsed_fn -= GSM_TDMA_HYPERFRAME;
return elapsed_fn;
}
@@ -1654,22 +402,18 @@ static inline void normalize_timespec(struct timespec *ts)
ts->tv_nsec = ts->tv_nsec % 1000000000;
}
-/*! Increment a GSM frame number modulo GSM_HYPERFRAME */
-#define INCREMENT_FN(fn) (fn) = (((fn) + 1) % GSM_HYPERFRAME)
-
-extern int quit;
-
/*! this is the timerfd-callback firing for every FN to be processed */
static int trx_fn_timer_cb(struct osmo_fd *ofd, unsigned int what)
{
struct gsm_bts *bts = ofd->data;
- struct osmo_trx_clock_state *tcs = &g_clk_s;
+ struct bts_trx_priv *bts_trx = (struct bts_trx_priv *)bts->model_priv;
+ struct osmo_trx_clock_state *tcs = &bts_trx->clk_s;
struct timespec tv_now;
uint64_t expire_count;
int64_t elapsed_us, error_us;
int rc, i;
- if (!(what & BSC_FD_READ))
+ if (!(what & OSMO_FD_READ))
return 0;
/* read from timerfd: number of expirations of periodic timer */
@@ -1680,7 +424,8 @@ static int trx_fn_timer_cb(struct osmo_fd *ofd, unsigned int what)
if (expire_count > 1) {
LOGP(DL1C, LOGL_NOTICE, "FN timer expire_count=%"PRIu64": We missed %"PRIu64" timers\n",
- expire_count, expire_count-1);
+ expire_count, expire_count - 1);
+ rate_ctr_add(rate_ctr_group_get_ctr(bts_trx->ctrs, BTSTRX_CTR_SCHED_DL_MISS_FN), expire_count - 1);
}
/* check if transceiver is still alive */
@@ -1692,7 +437,7 @@ static int trx_fn_timer_cb(struct osmo_fd *ofd, unsigned int what)
/* compute actual elapsed time and resulting OS scheduling error */
clock_gettime(CLOCK_MONOTONIC, &tv_now);
elapsed_us = compute_elapsed_us(&tcs->last_fn_timer.tv, &tv_now);
- error_us = elapsed_us - FRAME_DURATION_uS;
+ error_us = elapsed_us - GSM_TDMA_FN_DURATION_uS;
#ifdef DEBUG_CLOCK
printf("%s(): %09ld, elapsed_us=%05" PRId64 ", error_us=%-d: fn=%d\n", __func__,
tv_now.tv_nsec, elapsed_us, error_us, tcs->last_fn_timer.fn+1);
@@ -1700,45 +445,83 @@ static int trx_fn_timer_cb(struct osmo_fd *ofd, unsigned int what)
tcs->last_fn_timer.tv = tv_now;
/* if someone played with clock, or if the process stalled */
- if (elapsed_us > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed_us < 0) {
+ if (elapsed_us > GSM_TDMA_FN_DURATION_uS * MAX_FN_SKEW || elapsed_us < 0) {
LOGP(DL1C, LOGL_ERROR, "PC clock skew: elapsed_us=%" PRId64 ", error_us=%" PRId64 "\n",
elapsed_us, error_us);
goto no_clock;
}
- /* call trx_sched_fn() for all expired FN */
- for (i = 0; i < expire_count; i++) {
- INCREMENT_FN(tcs->last_fn_timer.fn);
- trx_sched_fn(bts, tcs->last_fn_timer.fn);
- }
+ /* call bts_sched_fn() for all expired FN */
+ for (i = 0; i < expire_count; i++)
+ bts_sched_fn(bts, GSM_TDMA_FN_INC(tcs->last_fn_timer.fn));
return 0;
no_clock:
osmo_timerfd_disable(&tcs->fn_timer_ofd);
- transceiver_available = 0;
-
bts_shutdown(bts, "No clock from osmo-trx");
+ return -1;
+}
+/*! \brief This is the cb of the initial timer set upon start. On timeout, it
+ * means it wasn't replaced and hence no CLOCK IND was received. */
+static int trx_start_noclockind_to_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ struct gsm_bts *bts = ofd->data;
+ struct bts_trx_priv *bts_trx = (struct bts_trx_priv *)bts->model_priv;
+ struct osmo_trx_clock_state *tcs = &bts_trx->clk_s;
+
+ osmo_fd_close(&tcs->fn_timer_ofd); /* Avoid being called again */
+ bts_shutdown(bts, "No clock since TRX was started");
return -1;
}
+/*! \brief PHY informs us clock indications should start to be received */
+int trx_sched_clock_started(struct gsm_bts *bts)
+{
+ struct bts_trx_priv *bts_trx = (struct bts_trx_priv *)bts->model_priv;
+ struct osmo_trx_clock_state *tcs = &bts_trx->clk_s;
+ const struct timespec it_val = {3, 0};
+ const struct timespec it_intval = {0, 0};
+
+ LOGP(DL1C, LOGL_NOTICE, "GSM clock started, waiting for clock indications\n");
+ osmo_fd_close(&tcs->fn_timer_ofd);
+ memset(tcs, 0, sizeof(*tcs));
+ tcs->fn_timer_ofd.fd = -1;
+ /* Set up timeout to shutdown BTS if no clock ind is received in a few
+ * seconds. Upon clock ind receival, fn_timer_ofd will be reused and
+ * timeout won't trigger.
+ */
+ osmo_timerfd_setup(&tcs->fn_timer_ofd, trx_start_noclockind_to_cb, bts);
+ osmo_timerfd_schedule(&tcs->fn_timer_ofd, &it_val, &it_intval);
+ return 0;
+}
+
+/*! \brief PHY informs us no more clock indications should be received anymore */
+int trx_sched_clock_stopped(struct gsm_bts *bts)
+{
+ struct bts_trx_priv *bts_trx = (struct bts_trx_priv *)bts->model_priv;
+ struct osmo_trx_clock_state *tcs = &bts_trx->clk_s;
+
+ LOGP(DL1C, LOGL_NOTICE, "GSM clock stopped\n");
+ osmo_fd_close(&tcs->fn_timer_ofd);
+
+ return 0;
+}
+
/*! reset clock with current fn and schedule it. Called when trx becomes
* available or when max clock skew is reached */
static int trx_setup_clock(struct gsm_bts *bts, struct osmo_trx_clock_state *tcs,
struct timespec *tv_now, const struct timespec *interval, uint32_t fn)
{
- tcs->last_fn_timer.fn = fn;
- /* call trx cheduler function for new 'last' FN */
- trx_sched_fn(bts, tcs->last_fn_timer.fn);
-
/* schedule first FN clock timer */
osmo_timerfd_setup(&tcs->fn_timer_ofd, trx_fn_timer_cb, bts);
osmo_timerfd_schedule(&tcs->fn_timer_ofd, NULL, interval);
+ tcs->last_fn_timer.fn = fn;
tcs->last_fn_timer.tv = *tv_now;
- tcs->last_clk_ind.tv = *tv_now;
- tcs->last_clk_ind.fn = fn;
+ /* call trx scheduler function for new 'last' FN */
+ bts_sched_fn(bts, tcs->last_fn_timer.fn);
return 0;
}
@@ -1746,36 +529,19 @@ static int trx_setup_clock(struct gsm_bts *bts, struct osmo_trx_clock_state *tcs
/*! called every time we receive a clock indication from TRX */
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
{
- struct osmo_trx_clock_state *tcs = &g_clk_s;
+ struct bts_trx_priv *bts_trx = (struct bts_trx_priv *)bts->model_priv;
+ struct osmo_trx_clock_state *tcs = &bts_trx->clk_s;
struct timespec tv_now;
int elapsed_fn;
int64_t elapsed_us, elapsed_us_since_clk, elapsed_fn_since_clk, error_us_since_clk;
unsigned int fn_caught_up = 0;
- const struct timespec interval = { .tv_sec = 0, .tv_nsec = FRAME_DURATION_nS };
-
- if (quit)
- return 0;
+ const struct timespec interval = { .tv_sec = 0, .tv_nsec = GSM_TDMA_FN_DURATION_nS };
/* reset lost counter */
tcs->fn_without_clock_ind = 0;
clock_gettime(CLOCK_MONOTONIC, &tv_now);
- /* clock becomes valid */
- if (!transceiver_available) {
- LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", fn);
-
- transceiver_available = 1;
-
- /* start provisioning transceiver */
- l1if_provision_transceiver(bts);
-
- /* tell BSC */
- check_transceiver_availability(bts, 1);
-
- return trx_setup_clock(bts, tcs, &tv_now, &interval, fn);
- }
-
/* calculate elapsed time +fn since last timer */
elapsed_us = compute_elapsed_us(&tcs->last_fn_timer.tv, &tv_now);
elapsed_fn = compute_elapsed_fn(tcs->last_fn_timer.fn, fn);
@@ -1792,7 +558,7 @@ int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
elapsed_us_since_clk = compute_elapsed_us(&tcs->last_clk_ind.tv, &tv_now);
elapsed_fn_since_clk = compute_elapsed_fn(tcs->last_clk_ind.fn, fn);
/* error (delta) between local clock since last CLK and CLK based on FN clock at TRX */
- error_us_since_clk = elapsed_us_since_clk - (FRAME_DURATION_uS * elapsed_fn_since_clk);
+ error_us_since_clk = elapsed_us_since_clk - (GSM_TDMA_FN_DURATION_uS * elapsed_fn_since_clk);
LOGP(DL1C, LOGL_INFO, "TRX Clock Ind: elapsed_us=%7"PRId64", "
"elapsed_fn=%3"PRId64", error_us=%+5"PRId64"\n",
elapsed_us_since_clk, elapsed_fn_since_clk, error_us_since_clk);
@@ -1813,14 +579,14 @@ int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
}
LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %" PRId64 "us (elapsed_fn=%d)\n",
- elapsed_fn * FRAME_DURATION_uS - elapsed_us, elapsed_fn);
+ elapsed_fn * GSM_TDMA_FN_DURATION_uS - elapsed_us, elapsed_fn);
/* too many frames have been processed already */
if (elapsed_fn < 0) {
struct timespec first = interval;
/* set clock to the time or last FN should have been
* transmitted. */
- first.tv_nsec += (0 - elapsed_fn) * FRAME_DURATION_nS;
+ first.tv_nsec += (0 - elapsed_fn) * GSM_TDMA_FN_DURATION_nS;
normalize_timespec(&first);
LOGP(DL1C, LOGL_NOTICE, "We were %d FN faster than TRX, compensating\n", -elapsed_fn);
/* set time to the time our next FN has to be transmitted */
@@ -1830,8 +596,7 @@ int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
/* transmit what we still need to transmit */
while (fn != tcs->last_fn_timer.fn) {
- INCREMENT_FN(tcs->last_fn_timer.fn);
- trx_sched_fn(bts, tcs->last_fn_timer.fn);
+ bts_sched_fn(bts, GSM_TDMA_FN_INC(tcs->last_fn_timer.fn));
fn_caught_up++;
}
@@ -1843,9 +608,9 @@ int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
return 0;
}
-void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
+void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate)
{
- struct phy_instance *pinst = trx_phy_instance(l1t->trx);
+ struct phy_instance *pinst = trx_phy_instance(trx);
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (activate)
@@ -1853,3 +618,92 @@ void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int ac
else
trx_if_cmd_nohandover(l1h, tn, ss);
}
+
+/* Add a set of UL burst measurements to the history */
+void trx_sched_meas_push(struct l1sched_chan_state *chan_state,
+ const struct trx_ul_burst_ind *bi)
+{
+ unsigned int hist_size = ARRAY_SIZE(chan_state->meas.buf);
+ unsigned int current = chan_state->meas.current;
+
+ chan_state->meas.buf[current] = (struct l1sched_meas_set) {
+ .fn = bi->fn,
+ .ci_cb = (bi->flags & TRX_BI_F_CI_CB) ? bi->ci_cb : 0,
+ .toa256 = bi->toa256,
+ .rssi = bi->rssi,
+ };
+
+ chan_state->meas.current = (current + 1) % hist_size;
+}
+
+/* Measurement averaging mode sets: [MODE] = { SHIFT, NUM } */
+static const uint8_t trx_sched_meas_modeset[][2] = {
+ [SCHED_MEAS_AVG_M_S24N22] = { 24, 22 },
+ [SCHED_MEAS_AVG_M_S22N22] = { 22, 22 },
+ [SCHED_MEAS_AVG_M_S4N4] = { 4, 4 },
+ [SCHED_MEAS_AVG_M_S8N8] = { 8, 8 },
+ [SCHED_MEAS_AVG_M_S6N4] = { 6, 4 },
+ [SCHED_MEAS_AVG_M_S6N6] = { 6, 6 },
+ [SCHED_MEAS_AVG_M_S8N4] = { 8, 4 },
+ [SCHED_MEAS_AVG_M_S6N2] = { 6, 2 },
+ [SCHED_MEAS_AVG_M_S4N2] = { 4, 2 },
+};
+
+/* Calculate the AVG of n measurements from the history */
+void trx_sched_meas_avg(const struct l1sched_chan_state *chan_state,
+ struct l1sched_meas_set *avg,
+ enum sched_meas_avg_mode mode)
+{
+ unsigned int hist_size = ARRAY_SIZE(chan_state->meas.buf);
+ unsigned int current = chan_state->meas.current;
+ const struct l1sched_meas_set *set;
+ unsigned int pos, i;
+
+ float rssi_sum = 0;
+ int toa256_sum = 0;
+ int ci_cb_sum = 0;
+
+ const unsigned int shift = trx_sched_meas_modeset[mode][0];
+ const unsigned int num = trx_sched_meas_modeset[mode][1];
+
+ /* Calculate the sum of n entries starting from pos */
+ for (i = 0; i < num; i++) {
+ pos = (current + hist_size - shift + i) % hist_size;
+ set = &chan_state->meas.buf[pos];
+
+ rssi_sum += set->rssi;
+ toa256_sum += set->toa256;
+ ci_cb_sum += set->ci_cb;
+ }
+
+ /* First sample contains TDMA frame number of the first burst */
+ pos = (current + hist_size - shift) % hist_size;
+ set = &chan_state->meas.buf[pos];
+
+ /* Calculate the average for each value */
+ *avg = (struct l1sched_meas_set) {
+ .fn = set->fn, /* first burst */
+ .rssi = (rssi_sum / num),
+ .toa256 = (toa256_sum / num),
+ .ci_cb = (ci_cb_sum / num),
+ };
+
+ LOGP(DMEAS, LOGL_DEBUG, "%s%sMeasurement AVG (num=%u, shift=%u): "
+ "RSSI %f, ToA256 %d, C/I %d cB\n",
+ chan_state->lchan ? gsm_lchan_name(chan_state->lchan) : "",
+ chan_state->lchan ? " " : "",
+ num, shift, avg->rssi, avg->toa256, avg->ci_cb);
+}
+
+/* Lookup TDMA frame number of the N-th sample in the history */
+uint32_t trx_sched_lookup_fn(const struct l1sched_chan_state *chan_state,
+ const unsigned int shift)
+{
+ const unsigned int hist_size = ARRAY_SIZE(chan_state->meas.buf);
+ const unsigned int current = chan_state->meas.current;
+ unsigned int pos;
+
+ /* First sample contains TDMA frame number of the first burst */
+ pos = (current + hist_size - shift) % hist_size;
+ return chan_state->meas.buf[pos].fn;
+}
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index 6c6d5ad9..b6b20e94 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -8,6 +8,7 @@
* Copyright (C) 2013 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2016-2017 Harald Welte <laforge@gnumonks.org>
* Copyright (C) 2019 Vadim Yanitskiy <axilirator@gmail.com>
+ * Copyright (C) 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -39,6 +40,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
@@ -47,8 +49,20 @@
#include "l1_if.h"
#include "trx_if.h"
+#include "trx_provision_fsm.h"
-int transceiver_available = 0;
+#include "btsconfig.h"
+
+#ifdef HAVE_SYSTEMTAP
+/* include the generated probes header and put markers in code */
+#include "probes.h"
+#define TRACE(probe) probe
+#define TRACE_ENABLED(probe) probe ## _ENABLED()
+#else
+/* Wrap the probe to allow it to be removed when no systemtap available */
+#define TRACE(probe)
+#define TRACE_ENABLED(probe) (0)
+#endif /* HAVE_SYSTEMTAP */
/*
* socket helper functions
@@ -95,15 +109,19 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct phy_link *plink = ofd->data;
struct phy_instance *pinst = phy_instance_by_num(plink, 0);
- char buf[1500];
- int len;
+ char buf[TRXC_MSG_BUF_SIZE];
+ ssize_t len;
uint32_t fn;
OSMO_ASSERT(pinst);
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
- if (len <= 0)
+ if (len <= 0) {
+ strerror_r(errno, (char *)buf, sizeof(buf));
+ LOGPPHI(pinst, DTRX, LOGL_ERROR,
+ "recv() failed on TRXD with rc=%zd (%s)\n", len, buf);
return len;
+ }
buf[len] = '\0';
if (!!strncmp(buf, "IND CLOCK ", 10)) {
@@ -119,12 +137,16 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
LOGPPHI(pinst, DTRX, LOGL_INFO, "Clock indication: fn=%u\n", fn);
- if (fn >= GSM_HYPERFRAME) {
- fn %= GSM_HYPERFRAME;
+ if (fn >= GSM_TDMA_HYPERFRAME) {
+ fn %= GSM_TDMA_HYPERFRAME;
LOGPPHI(pinst, DTRX, LOGL_ERROR, "Indicated clock's FN is not "
"wrapping correctly, correcting to fn=%u\n", fn);
}
+ if (!plink->u.osmotrx.powered) {
+ LOGPPHI(pinst, DTRX, LOGL_NOTICE, "Ignoring CLOCK IND %u, TRX not yet powered on\n", fn);
+ return 0;
+ }
/* inform core TRX clock handling code that a FN has been received */
trx_sched_clock(pinst->trx->bts, fn);
@@ -140,8 +162,9 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
static void trx_ctrl_send(struct trx_l1h *l1h)
{
struct trx_ctrl_msg *tcm;
- char buf[1500];
+ char buf[TRXC_MSG_BUF_SIZE];
int len;
+ ssize_t snd_len;
/* get first command */
if (llist_empty(&l1h->trx_ctrl_list))
@@ -153,7 +176,12 @@ static void trx_ctrl_send(struct trx_l1h *l1h)
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "Sending control '%s'\n", buf);
/* send command */
- send(l1h->trx_ofd_ctrl.fd, buf, len+1, 0);
+ snd_len = send(l1h->trx_ofd_ctrl.fd, buf, len+1, 0);
+ if (snd_len <= 0) {
+ strerror_r(errno, (char *)buf, sizeof(buf));
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "send() failed on TRXC with rc=%zd (%s)\n", snd_len, buf);
+ }
/* start timer */
osmo_timer_schedule(&l1h->trx_ctrl_timer, 2, 0);
@@ -179,36 +207,32 @@ void trx_if_init(struct trx_l1h *l1h)
{
l1h->trx_ctrl_timer.cb = trx_ctrl_timer_cb;
l1h->trx_ctrl_timer.data = l1h;
+
+ /* initialize ctrl queue */
+ INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
+
+ l1h->trx_ofd_ctrl.fd = -1;
+ l1h->trx_ofd_data.fd = -1;
}
/*! Send a new TRX control command.
* \param[inout] l1h TRX Layer1 handle to which to send command
- * \param[in] criticial
+ * \param[in] critical
* \param[in] cb callback function to be called when valid response is
* received. Type of cb depends on type of message.
* \param[in] cmd zero-terminated string containing command
* \param[in] fmt Format string (+ variable list of arguments)
* \returns 0 on success; negative on error
*
- * The new ocommand will be added to the end of the control command
+ * The new command will be added to the end of the control command
* queue.
*/
-static int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, const char *cmd,
- const char *fmt, ...)
+int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb,
+ const char *cmd, const char *fmt, ...)
{
struct trx_ctrl_msg *tcm;
struct trx_ctrl_msg *prev = NULL;
va_list ap;
- int pending;
-
- if (!transceiver_available &&
- !(!strcmp(cmd, "POWEROFF") || !strcmp(cmd, "POWERON"))) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "CTRL %s ignored: No clock from "
- "transceiver, please fix!\n", cmd);
- return -EIO;
- }
-
- pending = !llist_empty(&l1h->trx_ctrl_list);
/* create message */
tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg);
@@ -231,71 +255,60 @@ static int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, const ch
tcm->cb = cb;
/* Avoid adding consecutive duplicate messages, eg: two consecutive POWEROFF */
- if(pending)
+ if (!llist_empty(&l1h->trx_ctrl_list))
prev = llist_entry(l1h->trx_ctrl_list.prev, struct trx_ctrl_msg, list);
-
- if (!pending ||
- !(strcmp(tcm->cmd, prev->cmd) == 0 && strcmp(tcm->params, prev->params) == 0)) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO, "Enqueuing TRX control command 'CMD %s%s%s'\n",
- tcm->cmd, tcm->params_len ? " ":"", tcm->params);
- llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);
+ if (prev != NULL && !strcmp(tcm->cmd, prev->cmd)
+ && !strcmp(tcm->params, prev->params)) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
+ "Not sending duplicate command '%s'\n", tcm->cmd);
+ talloc_free(tcm);
+ return 0;
}
- /* send message, if we didn't already have pending messages */
- if (!pending)
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO, "Enqueuing TRX control command 'CMD %s%s%s'\n",
+ tcm->cmd, tcm->params_len ? " " : "", tcm->params);
+ llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);
+
+ /* send message, if we didn't already have pending messages.
+ * If we are in the rx_rsp callback code path, skip sending, the
+ * callback will do so when returning to it. */
+ if (prev == NULL && !l1h->in_trx_ctrl_read_cb)
trx_ctrl_send(l1h);
return 0;
}
-#define trx_ctrl_cmd(l1h, critical, cmd, fmt, ...) trx_ctrl_cmd_cb(l1h, critical, NULL, cmd, fmt, ##__VA_ARGS__)
/*! Send "POWEROFF" command to TRX */
-int trx_if_cmd_poweroff(struct trx_l1h *l1h)
+int trx_if_cmd_poweroff(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb)
{
- struct phy_instance *pinst = l1h->phy_inst;
- if (pinst->num == 0)
- return trx_ctrl_cmd(l1h, 1, "POWEROFF", "");
- else
- return 0;
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "POWEROFF", "");
}
/*! Send "POWERON" command to TRX */
-int trx_if_cmd_poweron(struct trx_l1h *l1h)
+int trx_if_cmd_poweron(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb)
{
- struct phy_instance *pinst = l1h->phy_inst;
- if (pinst->num == 0)
- return trx_ctrl_cmd(l1h, 1, "POWERON", "");
- else
- return 0;
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "POWERON", "");
}
-/*! Send "SETFORMAT" command to TRX: change TRXD header format version */
-int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver)
+/*! Send "SETFORMAT" command to TRX: change TRXD PDU version */
+int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver, trx_if_cmd_generic_cb *cb)
{
LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO,
- "Requesting TRXD header format version %u\n", ver);
+ "Requesting TRXD PDU version %u\n", ver);
- return trx_ctrl_cmd(l1h, 0, "SETFORMAT", "%u", ver);
+ return trx_ctrl_cmd_cb(l1h, 0, cb, "SETFORMAT", "%u", ver);
}
/*! Send "SETTSC" command to TRX */
-int trx_if_cmd_settsc(struct trx_l1h *l1h, uint8_t tsc)
+int trx_if_cmd_settsc(struct trx_l1h *l1h, uint8_t tsc, trx_if_cmd_generic_cb *cb)
{
- struct phy_instance *pinst = l1h->phy_inst;
- if (pinst->phy_link->u.osmotrx.use_legacy_setbsic)
- return 0;
-
- return trx_ctrl_cmd(l1h, 1, "SETTSC", "%d", tsc);
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "SETTSC", "%d", tsc);
}
/*! Send "SETBSIC" command to TRX */
-int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic)
+int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic, trx_if_cmd_generic_cb *cb)
{
- struct phy_instance *pinst = l1h->phy_inst;
- if (!pinst->phy_link->u.osmotrx.use_legacy_setbsic)
- return 0;
-
- return trx_ctrl_cmd(l1h, 1, "SETBSIC", "%d", bsic);
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "SETBSIC", "%d", bsic);
}
/*! Send "SETRXGAIN" command to TRX */
@@ -304,10 +317,16 @@ int trx_if_cmd_setrxgain(struct trx_l1h *l1h, int db)
return trx_ctrl_cmd(l1h, 0, "SETRXGAIN", "%d", db);
}
+/*! Send "NOMTXPOWER" command to TRX */
+int trx_if_cmd_getnompower(struct trx_l1h *l1h, trx_if_cmd_getnompower_cb *cb)
+{
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "NOMTXPOWER", "");
+}
+
/*! Send "SETPOWER" command to TRX */
-int trx_if_cmd_setpower(struct trx_l1h *l1h, int db)
+int trx_if_cmd_setpower_att(struct trx_l1h *l1h, int power_att_db, trx_if_cmd_setpower_att_cb *cb)
{
- return trx_ctrl_cmd(l1h, 0, "SETPOWER", "%d", db);
+ return trx_ctrl_cmd_cb(l1h, 0, cb, "SETPOWER", "%d", power_att_db);
}
/*! Send "SETMAXDLY" command to TRX, i.e. maximum delay for RACH bursts */
@@ -322,14 +341,27 @@ int trx_if_cmd_setmaxdlynb(struct trx_l1h *l1h, int dly)
return trx_ctrl_cmd(l1h, 0, "SETMAXDLYNB", "%d", dly);
}
-/*! Send "SETSLOT" command to TRX: Configure Channel Combination for TS */
-int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn, uint8_t type, trx_if_cmd_setslot_cb *cb)
+/*! Send "SETSLOT" command to TRX: Configure Channel Combination and TSC for TS */
+int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn,
+ trx_if_cmd_setslot_cb *cb)
{
- return trx_ctrl_cmd_cb(l1h, 1, cb, "SETSLOT", "%d %d", tn, type);
+ const struct trx_config *cfg = &l1h->config;
+ const struct phy_instance *pinst = l1h->phy_inst;
+
+ if (cfg->setslot[tn].tsc_valid && cfg->setslot[tn].tsc_val != BTS_TSC(pinst->trx->bts)) {
+ /* PHY is instructed to use a custom TSC */
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "SETSLOT", "%u %u C%u/S%u",
+ tn, cfg->setslot[tn].slottype,
+ cfg->setslot[tn].tsc_val,
+ cfg->setslot[tn].tsc_set);
+ } else { /* PHY is instructed to use the default TSC from 'SETTSC' */
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "SETSLOT", "%u %u",
+ tn, cfg->setslot[tn].slottype);
+ }
}
/*! Send "RXTUNE" command to TRX: Tune Receiver to given ARFCN */
-int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn)
+int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb)
{
struct phy_instance *pinst = l1h->phy_inst;
uint16_t freq10;
@@ -344,11 +376,11 @@ int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn)
return -ENOTSUP;
}
- return trx_ctrl_cmd(l1h, 1, "RXTUNE", "%d", freq10 * 100);
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "RXTUNE", "%d", freq10 * 100);
}
/*! Send "TXTUNE" command to TRX: Tune Transmitter to given ARFCN */
-int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn)
+int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb)
{
struct phy_instance *pinst = l1h->phy_inst;
uint16_t freq10;
@@ -363,7 +395,7 @@ int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn)
return -ENOTSUP;
}
- return trx_ctrl_cmd(l1h, 1, "TXTUNE", "%d", freq10 * 100);
+ return trx_ctrl_cmd_cb(l1h, 1, cb, "TXTUNE", "%d", freq10 * 100);
}
/*! Send "HANDOVER" command to TRX: Enable handover RACH Detection on timeslot/sub-slot */
@@ -378,6 +410,12 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss)
return trx_ctrl_cmd(l1h, 1, "NOHANDOVER", "%d %d", tn, ss);
}
+/*! Send "RFMUTE" command to TRX: Mute or Unmute RF transmission */
+int trx_if_cmd_rfmute(struct trx_l1h *l1h, bool mute)
+{
+ return trx_ctrl_cmd(l1h, 0, "RFMUTE", mute ? "1" : "0");
+}
+
struct trx_ctrl_rsp {
char cmd[50];
char params[100];
@@ -387,6 +425,7 @@ struct trx_ctrl_rsp {
static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp)
{
+ size_t nlen, plen;
char *p, *k;
if (strncmp(buf_in, "RSP ", 4))
@@ -396,14 +435,17 @@ static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp
if (!(p = strchr(buf_in + 4, ' ')))
goto parse_err;
- if (p - buf_in >= sizeof(rsp->cmd)) {
- LOGP(DTRX, LOGL_ERROR, "cmd buffer too small %lu >= %lu\n",
- p - buf_in, sizeof(rsp->cmd));
+ /* Calculate length of the name part */
+ nlen = p - (buf_in + 4);
+
+ if (nlen >= sizeof(rsp->cmd)) {
+ LOGP(DTRX, LOGL_ERROR, "TRXC command name part is too long: "
+ "%zu >= %zu\n", nlen, sizeof(rsp->cmd));
goto parse_err;
}
- rsp->cmd[0] = '\0';
- strncat(rsp->cmd, buf_in + 4, p - buf_in - 4);
+ memcpy(&rsp->cmd[0], buf_in + 4, nlen);
+ rsp->cmd[nlen] = '\0';
/* Now comes the status code of the response */
p++;
@@ -417,18 +459,22 @@ static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp
else
k = p + strlen(p);
- if (strlen(k) >= sizeof(rsp->params)) {
- LOGP(DTRX, LOGL_ERROR, "params buffer too small %lu >= %lu\n",
- strlen(k), sizeof(rsp->params));
+ /* Calculate length of the parameters part */
+ plen = strlen(k);
+
+ if (plen >= sizeof(rsp->params)) {
+ LOGP(DTRX, LOGL_ERROR, "TRXC command parameters part is too long: "
+ "%zu >= %zu\n", plen, sizeof(rsp->params));
goto parse_err;
}
- rsp->params[0] = '\0';
- strcat(rsp->params, k);
+
+ memcpy(&rsp->params[0], k, plen);
+ rsp->params[plen] = '\0';
+
return 0;
parse_err:
- LOGP(DTRX, LOGL_NOTICE, "Unknown message on ctrl port: %s\n",
- buf_in);
+ LOGP(DTRX, LOGL_NOTICE, "Unknown TRXC message: %s\n", buf_in);
return -1;
}
@@ -448,6 +494,35 @@ static bool cmd_matches_rsp(struct trx_ctrl_msg *tcm, struct trx_ctrl_rsp *rsp)
return true;
}
+static int trx_ctrl_rx_rsp_poweron(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
+{
+ trx_if_cmd_poweronoff_cb *cb = (trx_if_cmd_poweronoff_cb*) rsp->cb;
+
+ if (rsp->status != 0)
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
+ "transceiver rejected POWERON command (%d), re-trying in a few seconds\n",
+ rsp->status);
+
+ if (cb)
+ cb(l1h, true, rsp->status);
+
+ /* If TRX fails, try again after 5 sec */
+ return rsp->status == 0 ? 0 : 5;
+}
+
+static int trx_ctrl_rx_rsp_poweroff(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
+{
+ trx_if_cmd_poweronoff_cb *cb = (trx_if_cmd_poweronoff_cb*) rsp->cb;
+
+ if (rsp->status == 0) {
+ if (cb)
+ cb(l1h, false, rsp->status);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int trx_ctrl_rx_rsp_setslot(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_setslot_cb *cb = (trx_if_cmd_setslot_cb*) rsp->cb;
@@ -471,7 +546,7 @@ static int trx_ctrl_rx_rsp_setslot(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp
return rsp->status == 0 ? 0 : -EINVAL;
}
-/* TRXD header format negotiation handler.
+/* TRXD PDU format negotiation handler.
*
* If the transceiver does not support the format negotiation, it would
* reject SETFORMAT with 'RSP ERR 1'. If the requested version is not
@@ -481,42 +556,72 @@ static int trx_ctrl_rx_rsp_setslot(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp
static int trx_ctrl_rx_rsp_setformat(struct trx_l1h *l1h,
struct trx_ctrl_rsp *rsp)
{
+ trx_if_cmd_generic_cb *cb;
+
/* Old transceivers reject 'SETFORMAT' with 'RSP ERR 1' */
if (strcmp(rsp->cmd, "SETFORMAT") != 0) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
"Transceiver rejected the format negotiation command, "
- "using legacy TRXD header format version (0)\n");
- l1h->config.trxd_hdr_ver_use = 0;
+ "using legacy TRXD PDU version (0)\n");
+ if (rsp->cb) {
+ cb = (trx_if_cmd_generic_cb*) rsp->cb;
+ cb(l1h, 0);
+ }
return 0;
}
/* Status shall indicate a proper version supported by the transceiver */
- if (rsp->status < 0 || rsp->status > l1h->config.trxd_hdr_ver_req) {
+ if (rsp->status < 0 || rsp->status > l1h->config.trxd_pdu_ver_req) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Transceiver indicated an out of range "
- "header format version %d (requested %u)\n",
- rsp->status, l1h->config.trxd_hdr_ver_req);
+ "PDU version %d (requested %u)\n",
+ rsp->status, l1h->config.trxd_pdu_ver_req);
return -EINVAL;
}
- /* Transceiver may suggest a lower version (than requested) */
- if (rsp->status == l1h->config.trxd_hdr_ver_req) {
- l1h->config.trxd_hdr_ver_use = rsp->status;
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO,
- "Using TRXD header format version %u\n",
- l1h->config.trxd_hdr_ver_use);
- } else {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
- "Transceiver suggests TRXD header version %u (requested %u)\n",
- rsp->status, l1h->config.trxd_hdr_ver_req);
- /* Send another SETFORMAT with suggested version */
- l1h->config.trxd_hdr_ver_req = rsp->status;
- trx_if_cmd_setformat(l1h, rsp->status);
+ if (rsp->cb) {
+ cb = (trx_if_cmd_generic_cb*) rsp->cb;
+ cb(l1h, rsp->status);
}
return 0;
}
+static int trx_ctrl_rx_rsp_nomtxpower(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
+{
+ trx_if_cmd_getnompower_cb *cb = (trx_if_cmd_getnompower_cb*) rsp->cb;
+ struct phy_instance *pinst = l1h->phy_inst;
+ int nominal_power;
+
+ if (rsp->status)
+ LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver NOMTXPOWER failed "
+ "with status %d. If your transceiver doesn't support this "
+ "command, then please set the nominal transmit power manually "
+ "through VTY cmd 'nominal-tx-power'.\n",
+ rsp->status);
+ if (cb) {
+ sscanf(rsp->params, "%d", &nominal_power);
+ cb(l1h, nominal_power, rsp->status);
+ }
+ return 0;
+}
+
+static int trx_ctrl_rx_rsp_setpower(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
+{
+ trx_if_cmd_setpower_att_cb *cb = (trx_if_cmd_setpower_att_cb*) rsp->cb;
+ struct phy_instance *pinst = l1h->phy_inst;
+ int power_att;
+
+ if (rsp->status)
+ LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver SETPOWER failed with status %d\n",
+ rsp->status);
+ if (cb) {
+ sscanf(rsp->params, "%d", &power_att);
+ cb(l1h, power_att, rsp->status);
+ }
+ return 0;
+}
+
/* -EINVAL: unrecoverable error, exit BTS
* N > 0: try sending originating command again after N seconds
* 0: Done with response, get originating command out from send queue
@@ -525,28 +630,28 @@ static int trx_ctrl_rx_rsp(struct trx_l1h *l1h,
struct trx_ctrl_rsp *rsp,
struct trx_ctrl_msg *tcm)
{
- struct phy_instance *pinst = l1h->phy_inst;
+ trx_if_cmd_generic_cb *cb;
- /* If TRX fails, try again after 1 sec */
if (strcmp(rsp->cmd, "POWERON") == 0) {
- if (rsp->status == 0) {
- if (pinst->phy_link->state != PHY_LINK_CONNECTED)
- phy_link_state_set(pinst->phy_link, PHY_LINK_CONNECTED);
- return 0;
- } else {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
- "transceiver rejected POWERON command (%d), re-trying in a few seconds\n",
- rsp->status);
- if (pinst->phy_link->state != PHY_LINK_SHUTDOWN)
- phy_link_state_set(pinst->phy_link, PHY_LINK_SHUTDOWN);
- return 5;
- }
+ return trx_ctrl_rx_rsp_poweron(l1h, rsp);
+ } else if (strcmp(rsp->cmd, "POWEROFF") == 0) {
+ return trx_ctrl_rx_rsp_poweroff(l1h, rsp);
} else if (strcmp(rsp->cmd, "SETSLOT") == 0) {
return trx_ctrl_rx_rsp_setslot(l1h, rsp);
/* We may get 'RSP ERR 1' if 'SETFORMAT' is not supported,
* so that's why we should use tcm instead of rsp. */
} else if (strcmp(tcm->cmd, "SETFORMAT") == 0) {
return trx_ctrl_rx_rsp_setformat(l1h, rsp);
+ } else if (strcmp(tcm->cmd, "NOMTXPOWER") == 0) {
+ return trx_ctrl_rx_rsp_nomtxpower(l1h, rsp);
+ } else if (strcmp(tcm->cmd, "SETPOWER") == 0) {
+ return trx_ctrl_rx_rsp_setpower(l1h, rsp);
+ }
+
+ /* Generic callback if available */
+ if (rsp->cb) {
+ cb = (trx_if_cmd_generic_cb*) rsp->cb;
+ cb(l1h, rsp->status);
}
if (rsp->status) {
@@ -565,10 +670,11 @@ 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];
+ char buf[TRXC_MSG_BUF_SIZE];
struct trx_ctrl_rsp rsp;
int len, rc;
struct trx_ctrl_msg *tcm;
+ bool flushed;
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
if (len <= 0)
@@ -581,8 +687,7 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO, "Response message: '%s'\n", buf);
/* abort timer and send next message, if any */
- if (osmo_timer_pending(&l1h->trx_ctrl_timer))
- osmo_timer_del(&l1h->trx_ctrl_timer);
+ osmo_timer_del(&l1h->trx_ctrl_timer);
/* get command for response message */
if (llist_empty(&l1h->trx_ctrl_list)) {
@@ -619,21 +724,34 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
rsp.cb = tcm->cb;
/* check for response code */
+ l1h->in_trx_ctrl_read_cb = true;
rc = trx_ctrl_rx_rsp(l1h, &rsp, tcm);
+ /* Reset state: */
+ flushed = l1h->flushed_while_in_trx_ctrl_read_cb;
+ l1h->flushed_while_in_trx_ctrl_read_cb = false;
+ l1h->in_trx_ctrl_read_cb = false;
+
if (rc == -EINVAL)
goto rsp_error;
/* re-schedule last cmd in rc seconds time */
if (rc > 0) {
- osmo_timer_schedule(&l1h->trx_ctrl_timer, rc, 0);
+ /* The queue may have been flushed in the trx_ctrl_rx_rsp(): */
+ if (!llist_empty(&l1h->trx_ctrl_list))
+ osmo_timer_schedule(&l1h->trx_ctrl_timer, rc, 0);
return 0;
}
- /* remove command from list, save it to last_acked and removed previous last_acked */
- llist_del(&tcm->list);
- talloc_free(l1h->last_acked);
- l1h->last_acked = tcm;
+ if (!flushed) {
+ /* Remove command from list, save it to last_acked and removed
+ * previous last_acked */
+ llist_del(&tcm->list);
+ talloc_free(l1h->last_acked);
+ l1h->last_acked = tcm;
+ } /* else: tcm was freed by trx_if_flush(), do not access it. */
+
+ /* Send next message waiting in the list: */
trx_ctrl_send(l1h);
return 0;
@@ -649,93 +767,119 @@ rsp_error:
* TRX burst data socket
*/
-/* Maximum DATA message length (header + burst) */
-#define TRX_DATA_MSG_MAX_LEN 512
-
-/* Common header length: 1/2 VER + 1/2 TDMA TN + 4 TDMA FN */
-#define TRX_CHDR_LEN (1 + 4)
-/* Uplink v0 header length: 1 RSSI + 2 ToA256 */
-#define TRX_UL_V0HDR_LEN (TRX_CHDR_LEN + 1 + 2)
-/* Uplink v1 header length: + 1 MTS + 2 C/I */
+/* Uplink TRXDv0 header length: TDMA TN + FN + RSSI + ToA256 */
+#define TRX_UL_V0HDR_LEN (1 + 4 + 1 + 2)
+/* Uplink TRXDv1 header length: additional MTS + C/I */
#define TRX_UL_V1HDR_LEN (TRX_UL_V0HDR_LEN + 1 + 2)
+/* Uplink TRXDv2 header length: TDMA TN + TRXN + MTS + RSSI + ToA256 + C/I */
+#define TRX_UL_V2HDR_LEN (1 + 1 + 1 + 1 + 2 + 2)
+
+/* Minimum Uplink TRXD header length for all PDU versions */
+static const uint8_t trx_data_rx_hdr_len[] = {
+ TRX_UL_V0HDR_LEN, /* TRXDv0 */
+ TRX_UL_V1HDR_LEN, /* TRXDv1 */
+ TRX_UL_V2HDR_LEN, /* TRXDv2 */
+};
-/* TRXD header dissector for version 0 */
-static int trx_data_handle_hdr_v0(struct trx_l1h *l1h,
- struct trx_ul_burst_ind *bi,
- const uint8_t *buf, size_t buf_len)
-{
- /* Make sure we have enough data */
- if (buf_len < TRX_UL_V0HDR_LEN) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "Short read on TRXD, missing version 0 header "
- "(len=%zu vs expected %d)\n", buf_len, TRX_UL_V0HDR_LEN);
- return -EIO;
- }
+static const uint8_t trx_data_mod_val[] = {
+ [TRX_MOD_T_GMSK] = 0x00, /* .00xx... */
+ [TRX_MOD_T_8PSK] = 0x20, /* .010x... */
+ [TRX_MOD_T_AQPSK] = 0x60, /* .11xx... */
+};
+/* Header dissector for TRXDv0 (and part of TRXDv1) */
+static inline void trx_data_handle_hdr_v0_part(struct trx_ul_burst_ind *bi,
+ const uint8_t *buf)
+{
bi->tn = buf[0] & 0b111;
bi->fn = osmo_load32be(buf + 1);
bi->rssi = -(int8_t)buf[5];
bi->toa256 = (int16_t) osmo_load16be(buf + 6);
-
- if (bi->fn >= GSM_HYPERFRAME) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "Illegal TDMA fn=%u\n", bi->fn);
- return -EINVAL;
- }
-
- return TRX_UL_V0HDR_LEN;
}
-/* TRXD header dissector for version 0x01 */
-static int trx_data_handle_hdr_v1(struct trx_l1h *l1h,
+/* TRXD header dissector for version 0x00 */
+static int trx_data_handle_hdr_v0(struct phy_instance *phy_inst,
struct trx_ul_burst_ind *bi,
const uint8_t *buf, size_t buf_len)
{
- uint8_t mts;
- int rc;
+ /* Parse TRXDv0 specific header part */
+ trx_data_handle_hdr_v0_part(bi, buf);
+ buf_len -= TRX_UL_V0HDR_LEN;
- /* Make sure we have enough data */
- if (buf_len < TRX_UL_V1HDR_LEN) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "Short read on TRXD, missing version 1 header "
- "(len=%zu vs expected %d)\n", buf_len, TRX_UL_V1HDR_LEN);
- return -EIO;
+ /* Guess modulation and burst length by the rest octets.
+ * NOTE: a legacy transceiver may append two garbage bytes. */
+ switch (buf_len) {
+ case EGPRS_BURST_LEN + 2:
+ case EGPRS_BURST_LEN:
+ bi->mod = TRX_MOD_T_8PSK;
+ break;
+ case GSM_BURST_LEN + 2:
+ case GSM_BURST_LEN:
+ bi->mod = TRX_MOD_T_GMSK;
+ break;
+ default:
+ LOGPPHI(phy_inst, DTRX, LOGL_NOTICE,
+ "Rx TRXD PDU with odd burst length %zu\n", buf_len);
+ return -EINVAL;
}
- /* Parse v0 specific part */
- rc = trx_data_handle_hdr_v0(l1h, bi, buf, buf_len);
- if (rc < 0)
- return rc;
-
- /* Move closer to the v1 specific part */
- buf_len -= rc;
- buf += rc;
+ return TRX_UL_V0HDR_LEN;
+}
- /* IDLE / NOPE frame indication */
- if (buf[0] & (1 << 7)) {
+/* Parser for MTS (Modulation and Training Sequence) */
+static inline int trx_data_parse_mts(struct phy_instance *phy_inst,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t mts)
+{
+ if (mts & (1 << 7)) {
bi->flags |= TRX_BI_F_NOPE_IND;
- return TRX_UL_V1HDR_LEN;
+ return 0;
}
- /* Modulation info and TSC set */
- mts = (buf[0] >> 3) & 0b1111;
- if ((mts & 0b1100) == 0x00) {
- bi->bt = TRX_BURST_GMSK;
- bi->tsc_set = mts & 0b11;
- bi->flags |= TRX_BI_F_MOD_TYPE;
- } else if ((mts & 0b0100) == 0b0100) {
- bi->bt = TRX_BURST_8PSK;
- bi->tsc_set = mts & 0b1;
- bi->flags |= TRX_BI_F_MOD_TYPE;
+ /* | 7 6 5 4 3 2 1 0 | Bitmask / description
+ * | . 0 0 X X . . . | GMSK, 4 TSC sets (0..3)
+ * | . 0 1 0 X . . . | 8-PSK, 2 TSC sets (0..1)
+ * | . 0 1 1 0 . . . | GMSK, Access Burst */
+ if ((mts >> 5) == 0x00) {
+ bi->mod = TRX_MOD_T_GMSK;
+ bi->tsc_set = (mts >> 3) & 0x03;
+ } else if ((mts >> 4) == 0x02) {
+ bi->mod = TRX_MOD_T_8PSK;
+ bi->tsc_set = (mts >> 3) & 0x01;
+ } else if ((mts >> 3) == 0x06) {
+ bi->flags |= TRX_BI_F_ACCESS_BURST;
+ bi->mod = TRX_MOD_T_GMSK;
+ bi->tsc_set = 0;
} else {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "Indicated modulation 0x%02x is not supported\n", mts & 0b1110);
+ LOGPPHI(phy_inst, DTRX, LOGL_ERROR,
+ "Rx TRXD PDU with unknown or not supported "
+ "modulation (MTS=0x%02x)\n", mts);
return -ENOTSUP;
}
/* Training Sequence Code */
- bi->tsc = buf[0] & 0b111;
- bi->flags |= TRX_BI_F_TS_INFO;
+ bi->tsc = mts & 0x07;
+
+ bi->flags |= (TRX_BI_F_MOD_TYPE | TRX_BI_F_TS_INFO);
+
+ return 0;
+}
+
+/* TRXD header dissector for version 0x01 */
+static int trx_data_handle_hdr_v1(struct phy_instance *phy_inst,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
+{
+ int rc;
+
+ /* Parse TRXDv0 specific header part */
+ trx_data_handle_hdr_v0_part(bi, buf);
+ buf += TRX_UL_V0HDR_LEN;
+
+ /* MTS (Modulation and Training Sequence) */
+ rc = trx_data_parse_mts(phy_inst, bi, buf[0]);
+ if (OSMO_UNLIKELY(rc < 0))
+ return rc;
/* C/I: Carrier-to-Interference ratio (in centiBels) */
bi->ci_cb = (int16_t) osmo_load16be(buf + 1);
@@ -744,64 +888,82 @@ static int trx_data_handle_hdr_v1(struct trx_l1h *l1h,
return TRX_UL_V1HDR_LEN;
}
-/* TRXD burst handler for header version 0 */
-static int trx_data_handle_burst_v0(struct trx_l1h *l1h,
- struct trx_ul_burst_ind *bi,
- const uint8_t *buf, size_t buf_len)
+/* TRXD header dissector for version 0x01 */
+static int trx_data_handle_pdu_v2(struct phy_instance *phy_inst,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
{
- size_t i;
+ int rc;
- /* Verify burst length */
- switch (buf_len) {
- /* Legacy transceivers append two padding bytes */
- case EGPRS_BURST_LEN + 2:
- case GSM_BURST_LEN + 2:
- bi->burst_len = buf_len - 2;
- break;
- case EGPRS_BURST_LEN:
- case GSM_BURST_LEN:
- bi->burst_len = buf_len;
- break;
+ /* TDMA timeslot number (other bits are RFU) */
+ bi->tn = buf[0] & 0x07;
- default:
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
- "Rx TRXD message with odd burst length %zu\n", buf_len);
- return -EINVAL;
- }
+ if (buf[1] & (1 << 7)) /* BATCH.ind */
+ bi->flags |= TRX_BI_F_BATCH_IND;
+ if (buf[1] & (1 << 6)) /* VAMOS.ind */
+ bi->flags |= TRX_BI_F_SHADOW_IND;
- /* Convert unsigned soft-bits [254..0] to soft-bits [-127..127] */
- for (i = 0; i < bi->burst_len; i++) {
- if (buf[i] == 255)
- bi->burst[i] = -127;
- else
- bi->burst[i] = 127 - buf[i];
+ /* TRX (RF channel) number */
+ bi->trx_num = buf[1] & 0x3f;
+ bi->flags |= TRX_BI_F_TRX_NUM;
+
+ /* MTS (Modulation and Training Sequence) */
+ rc = trx_data_parse_mts(phy_inst, bi, buf[2]);
+ if (OSMO_UNLIKELY(rc < 0))
+ return rc;
+
+ bi->rssi = -(int8_t)buf[3];
+ bi->toa256 = (int16_t) osmo_load16be(&buf[4]);
+ bi->ci_cb = (int16_t) osmo_load16be(&buf[6]);
+ bi->flags |= TRX_BI_F_CI_CB;
+
+ /* TDMA frame number is absent in batched PDUs */
+ if (bi->_num_pdus == 0) {
+ if (OSMO_UNLIKELY(buf_len < sizeof(bi->fn) + TRX_UL_V2HDR_LEN)) {
+ LOGPPHI(phy_inst, DTRX, LOGL_ERROR,
+ "Rx malformed TRXDv2 PDU: not enough bytes "
+ "to parse TDMA frame number\n");
+ return -EINVAL;
+ }
+
+ bi->fn = osmo_load32be(buf + TRX_UL_V2HDR_LEN);
+ return TRX_UL_V2HDR_LEN + sizeof(bi->fn);
}
- return 0;
+ return TRX_UL_V2HDR_LEN;
}
-/* TRXD burst handler for header version 1 */
-static int trx_data_handle_burst_v1(struct trx_l1h *l1h,
- struct trx_ul_burst_ind *bi,
- const uint8_t *buf, size_t buf_len)
+/* TRXD burst handler (version independent) */
+static int trx_data_handle_burst(struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
{
+ size_t i;
+
+ /* NOPE.ind contains no burst */
+ if (bi->flags & TRX_BI_F_NOPE_IND) {
+ bi->burst_len = 0;
+ return 0;
+ }
+
/* Modulation types defined in 3GPP TS 45.002 */
static const size_t bl[] = {
- [TRX_BURST_GMSK] = 148, /* 1 bit per symbol */
- [TRX_BURST_8PSK] = 444, /* 3 bits per symbol */
+ [TRX_MOD_T_GMSK] = 148, /* 1 bit per symbol */
+ [TRX_MOD_T_8PSK] = 444, /* 3 bits per symbol */
};
- /* Verify burst length */
- if (bl[bi->bt] != buf_len) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
- "Rx TRXD message with odd burst length %zu, "
- "expected %zu\n", buf_len, bl[bi->bt]);
+ bi->burst_len = bl[bi->mod];
+ if (OSMO_UNLIKELY(buf_len < bi->burst_len))
return -EINVAL;
+
+ /* Convert unsigned soft-bits [254..0] to soft-bits [-127..127] */
+ for (i = 0; i < bi->burst_len; i++) {
+ if (buf[i] == 255)
+ bi->burst[i] = -127;
+ else
+ bi->burst[i] = 127 - buf[i];
}
- /* The burst format is the same as for version 0.
- * NOTE: other modulation types to be handled separately. */
- return trx_data_handle_burst_v0(l1h, bi, buf, buf_len);
+ return 0;
}
static const char *trx_data_desc_msg(const struct trx_ul_burst_ind *bi)
@@ -811,8 +973,8 @@ static const char *trx_data_desc_msg(const struct trx_ul_burst_ind *bi)
/* Modulation types defined in 3GPP TS 45.002 */
static const char *mod_names[] = {
- [TRX_BURST_GMSK] = "GMSK",
- [TRX_BURST_8PSK] = "8-PSK",
+ [TRX_MOD_T_GMSK] = "GMSK",
+ [TRX_MOD_T_8PSK] = "8-PSK",
};
/* Initialize the string buffer */
@@ -821,279 +983,236 @@ static const char *trx_data_desc_msg(const struct trx_ul_burst_ind *bi)
/* Common TDMA parameters */
OSMO_STRBUF_PRINTF(sb, "tn=%u fn=%u", bi->tn, bi->fn);
- /* Nothing else to print for NOPE.ind */
- if (bi->flags & TRX_BI_F_NOPE_IND)
- return buf;
+ /* TRX (RF channel number) */
+ if (bi->flags & TRX_BI_F_TRX_NUM)
+ OSMO_STRBUF_PRINTF(sb, " trx_num=%u", bi->trx_num);
/* RSSI and ToA256 */
OSMO_STRBUF_PRINTF(sb, " rssi=%d toa256=%d", bi->rssi, bi->toa256);
+ /* C/I: Carrier-to-Interference ratio (in centiBels) */
+ if (bi->flags & TRX_BI_F_CI_CB)
+ OSMO_STRBUF_PRINTF(sb, " C/I=%d cB", bi->ci_cb);
+
+ /* Nothing else to print for NOPE.ind */
+ if (bi->flags & TRX_BI_F_NOPE_IND)
+ return buf;
+
/* Modulation and TSC set */
if (bi->flags & TRX_BI_F_MOD_TYPE)
- OSMO_STRBUF_PRINTF(sb, " mod=%s", mod_names[bi->bt]);
+ OSMO_STRBUF_PRINTF(sb, " mod=%s", mod_names[bi->mod]);
/* Training Sequence Code */
if (bi->flags & TRX_BI_F_TS_INFO)
OSMO_STRBUF_PRINTF(sb, " set=%u tsc=%u", bi->tsc_set, bi->tsc);
- /* C/I: Carrier-to-Interference ratio (in centiBels) */
- if (bi->flags & TRX_BI_F_CI_CB)
- OSMO_STRBUF_PRINTF(sb, " C/I=%d cB", bi->ci_cb);
-
/* Burst length */
OSMO_STRBUF_PRINTF(sb, " burst_len=%zu", bi->burst_len);
return buf;
}
-/* Parse TRXD message from transceiver, compose an UL burst indication.
- *
- * This message contains a demodulated Uplink burst with fixed-size
- * header preceding the burst bits. The header consists of the common
- * and message specific part.
- *
- * +---------------+-----------------+------------+
- * | common header | specific header | burst bits |
- * +---------------+-----------------+------------+
- *
- * Common header is the same as for Downlink message:
- *
- * +-----------------+----------------+-------------------+
- * | VER (1/2 octet) | TN (1/2 octet) | FN (4 octets, BE) |
- * +-----------------+----------------+-------------------+
- *
- * and among with TDMA parameters, contains the version indicator:
- *
- * +-----------------+------------------------+
- * | 7 6 5 4 3 2 1 0 | bit numbers |
- * +-----------------+------------------------+
- * | X X X X . . . . | header version (0..15) |
- * +-----------------+------------------------+
- * | . . . . . X X X | TDMA TN (0..7) |
- * +-----------------+------------------------+
- * | . . . . X . . . | RESERVED (0) |
- * +-----------------+------------------------+
- *
- * which is encoded in 4 MSB bits of the first octet, which used to be
- * zero-initialized due to the value range of TDMA TN. Therefore, the
- * old header format has implicit version 0x00.
- *
- * The message specific header has the following structure:
- *
- * == Version 0x00
- *
- * +------+-----+--------------------+
- * | RSSI | ToA | soft-bits (254..0) |
- * +------+-----+--------------------+
- *
- * == Version 0x01
- *
- * +------+-----+-----+-----+--------------------+
- * | RSSI | ToA | MTS | C/I | soft-bits (254..0) |
- * +------+-----+-----+-----+--------------------+
- *
- * where:
- *
- * - RSSI (1 octet) - Received Signal Strength Indication
- * encoded without the negative sign.
- * - ToA (2 octets) - Timing of Arrival in units of 1/256
- * of symbol (big endian).
- * - MTS (1 octet) - Modulation and Training Sequence info.
- * - C/I (2 octets) - Carrier-to-Interference ratio (big endian).
- *
- * == Coding of MTS: Modulation and Training Sequence info
- *
- * 3GPP TS 45.002 version 15.1.0 defines several modulation types,
- * and a few sets of training sequences for each type. The most
- * common are GMSK and 8-PSK (which is used in EDGE).
- *
- * +-----------------+---------------------------------------+
- * | 7 6 5 4 3 2 1 0 | bit numbers (value range) |
- * +-----------------+---------------------------------------+
- * | . . . . . X X X | Training Sequence Code (0..7) |
- * +-----------------+---------------------------------------+
- * | . X X X X . . . | Modulation, TS set number (see below) |
- * +-----------------+---------------------------------------+
- * | X . . . . . . . | IDLE / nope frame indication (0 or 1) |
- * +-----------------+---------------------------------------+
- *
- * The bit number 7 (MSB) is set to high when either nothing has been
- * detected, or during IDLE frames, so we can deliver noise levels,
- * and avoid clock gaps on the L1 side. Other bits are ignored,
- * and should be set to low (0) in this case. L16 shall be set to 0x00.
- *
- * == Coding of modulation and TS set number
- *
- * GMSK has 4 sets of training sequences (see tables 5.2.3a-d),
- * while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets.
- * Access and Synchronization bursts also have several synch.
- * sequences.
- *
- * +-----------------+---------------------------------------+
- * | 7 6 5 4 3 2 1 0 | bit numbers (value range) |
- * +-----------------+---------------------------------------+
- * | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) |
- * +-----------------+---------------------------------------+
- * | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) |
- * +-----------------+---------------------------------------+
- * | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) |
- * +-----------------+---------------------------------------+
- * | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) |
- * +-----------------+---------------------------------------+
- * | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) |
- * +-----------------+---------------------------------------+
- * | . 1 1 1 X . . . | RESERVED (0) |
- * +-----------------+---------------------------------------+
- *
- * NOTE: we only support GMSK and 8-PSK.
- *
- * == C/I: Carrier-to-Interference ratio
- *
- * The C/I value can be computed from the training sequence of each
- * burst, where we can compare the "ideal" training sequence with
- * the actual training sequence and then express that in centiBels.
- *
- * == Coding of the burst bits
- *
- * Unlike to be transmitted bursts, the received bursts are designated
- * using the soft-bits notation, so the receiver can indicate its
- * assurance from 0 to -127 that a given bit is 1, and from 0 to +127
- * that a given bit is 0.
- *
- * Each soft-bit (-127..127) of the burst is encoded as an unsigned
- * value in range (254..0) respectively using the constant shift.
- *
- */
+/* TRXD buffer used by Rx/Tx handlers */
+static uint8_t trx_data_buf[TRXD_MSG_BUF_SIZE];
+
+/* Parse TRXD message from transceiver, compose an UL burst indication. */
static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
{
+ const uint8_t *buf = &trx_data_buf[0];
struct trx_l1h *l1h = ofd->data;
- uint8_t buf[TRX_DATA_MSG_MAX_LEN];
struct trx_ul_burst_ind bi;
ssize_t hdr_len, buf_len;
- uint8_t hdr_ver;
- int rc;
+ uint8_t pdu_ver;
- buf_len = recv(ofd->fd, buf, sizeof(buf), 0);
- if (buf_len <= 0) {
+ buf_len = recv(ofd->fd, trx_data_buf, sizeof(trx_data_buf), 0);
+ if (OSMO_UNLIKELY(buf_len <= 0)) {
+ strerror_r(errno, (char *) trx_data_buf, sizeof(trx_data_buf));
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "recv() failed on TRXD with rc=%zd\n", buf_len);
+ "recv() failed on TRXD with rc=%zd (%s)\n",
+ buf_len, trx_data_buf);
return buf_len;
}
- /* Pre-clean (initialize) the flags */
- bi.flags = 0x00;
+ /* Parse PDU version first */
+ pdu_ver = buf[0] >> 4;
- /* Parse the header depending on its version */
- hdr_ver = buf[0] >> 4;
- switch (hdr_ver) {
- case 0:
- /* Legacy protocol has no version indicator */
- hdr_len = trx_data_handle_hdr_v0(l1h, &bi, buf, buf_len);
- break;
- case 1:
- hdr_len = trx_data_handle_hdr_v1(l1h, &bi, buf, buf_len);
- break;
- default:
+ /* Make sure that PDU version matches our expectations */
+ if (OSMO_UNLIKELY(pdu_ver != l1h->config.trxd_pdu_ver_use)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "TRXD header version %u is not supported\n", hdr_ver);
- return -ENOTSUP;
+ "Rx TRXD PDU with unexpected version %u (expected %u)\n",
+ pdu_ver, l1h->config.trxd_pdu_ver_use);
+ return -EIO;
}
- /* Header parsing error */
- if (hdr_len < 0)
- return hdr_len;
+ /* We're about to parse the first PDU */
+ bi._num_pdus = 0;
- /* TODO: we can use NOPE indications to get noise levels on IDLE
- * TDMA frames, and properly drive scheduler if nothing has been
- * detected on non-IDLE channels. */
- if (bi.flags & TRX_BI_F_NOPE_IND) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
- "IDLE / NOPE indications are not (yet) supported\n");
- return -ENOTSUP;
- }
+ /* Starting from TRXDv2, there can be batched PDUs */
+ do {
+ /* (Re)initialize the flags */
+ bi.flags = 0x00;
- /* We're done with the header now */
- buf_len -= hdr_len;
+ /* Make sure that we have enough bytes to parse the header */
+ if (OSMO_UNLIKELY(buf_len < trx_data_rx_hdr_len[pdu_ver])) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Rx malformed TRXDv%u PDU: len=%zd < expected %u\n",
+ pdu_ver, buf_len, trx_data_rx_hdr_len[pdu_ver]);
+ return -EINVAL;
+ }
- /* Handle burst bits */
- switch (hdr_ver) {
- case 0:
- rc = trx_data_handle_burst_v0(l1h, &bi, buf + hdr_len, buf_len);
- break;
- case 1:
- rc = trx_data_handle_burst_v1(l1h, &bi, buf + hdr_len, buf_len);
- break;
- default:
- /* Shall not happen, just to make GCC happy */
- OSMO_ASSERT(0);
- }
+ /* Parse header depending on the PDU version */
+ switch (pdu_ver) {
+ case 0: /* TRXDv0 */
+ hdr_len = trx_data_handle_hdr_v0(l1h->phy_inst, &bi, buf, buf_len);
+ break;
+ case 1: /* TRXDv1 */
+ hdr_len = trx_data_handle_hdr_v1(l1h->phy_inst, &bi, buf, buf_len);
+ break;
+ case 2: /* TRXDv2 */
+ hdr_len = trx_data_handle_pdu_v2(l1h->phy_inst, &bi, buf, buf_len);
+ break;
+ default:
+ /* Shall not happen */
+ OSMO_ASSERT(0);
+ }
- /* Burst parsing error */
- if (rc < 0)
- return rc;
+ /* Header parsing error */
+ if (OSMO_UNLIKELY(hdr_len < 0))
+ return hdr_len;
- /* Print header & burst info */
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "Rx %s (hdr_ver=%u): %s\n",
- (bi.flags & TRX_BI_F_NOPE_IND) ? "NOPE.ind" : "UL burst",
- hdr_ver, trx_data_desc_msg(&bi));
+ if (OSMO_UNLIKELY(bi.fn >= GSM_TDMA_HYPERFRAME)) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Rx malformed TRXDv%u PDU: illegal TDMA fn=%u\n",
+ pdu_ver, bi.fn);
+ return -EINVAL;
+ }
+
+ /* We're done with the header now */
+ buf_len -= hdr_len;
+ buf += hdr_len;
+
+ /* Calculate burst length and parse it (if present) */
+ if (OSMO_UNLIKELY(trx_data_handle_burst(&bi, buf, buf_len) != 0)) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Rx malformed TRXDv%u PDU: odd burst length=%zd\n",
+ pdu_ver, buf_len);
+ return -EINVAL;
+ }
- /* feed received burst into scheduler code */
- trx_sched_ul_burst(&l1h->l1s, &bi);
+ /* We're done with the burst bits now */
+ buf_len -= bi.burst_len;
+ buf += bi.burst_len;
+
+ /* Print header & burst info */
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "Rx %s (pdu_ver=%u): %s\n",
+ (bi.flags & TRX_BI_F_NOPE_IND) ? "NOPE.ind" : "UL burst",
+ pdu_ver, trx_data_desc_msg(&bi));
+
+ /* Number of processed PDUs */
+ bi._num_pdus++;
+
+ /* feed received burst into scheduler code */
+ TRACE(OSMO_BTS_TRX_UL_DATA_START(l1h->phy_inst->trx->nr, bi.tn, bi.fn));
+ trx_sched_route_burst_ind(l1h->phy_inst->trx, &bi);
+ TRACE(OSMO_BTS_TRX_UL_DATA_DONE(l1h->phy_inst->trx->nr, bi.tn, bi.fn));
+ } while (bi.flags & TRX_BI_F_BATCH_IND);
return 0;
}
/*! Send burst data for given FN/timeslot to TRX
* \param[inout] l1h TRX Layer1 handle referring to TX
- * \param[in] tn Timeslot Number (0..7)
- * \param[in] fn GSM Frame Number
- * \param[in] pwr Transmit Power to use
- * \param[in] bits Unpacked bits to be transmitted
- * \param[in] nbits Number of \a bits
+ * \param[in] br Downlink burst request structure
* \returns 0 on success; negative on error */
-int trx_if_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
- const ubit_t *bits, uint16_t nbits)
+int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br)
{
- uint8_t hdr_ver = l1h->config.trxd_hdr_ver_use;
- uint8_t buf[TRX_DATA_MSG_MAX_LEN];
-
- if ((nbits != GSM_BURST_LEN) && (nbits != EGPRS_BURST_LEN)) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Tx burst length %u invalid\n", nbits);
- return -1;
+ uint8_t pdu_ver = l1h->config.trxd_pdu_ver_use;
+ static uint8_t *buf = &trx_data_buf[0];
+ static uint8_t *last_pdu = NULL;
+ static unsigned int pdu_num = 0;
+ ssize_t snd_len, buf_len;
+
+ /* Make sure that the PHY is powered on */
+ if (OSMO_UNLIKELY(!trx_if_powered(l1h))) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Ignoring Tx data, transceiver is powered off\n");
+ return -ENODEV;
}
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
- "Tx burst (hdr_ver=%u): tn=%u fn=%u pwr=%u\n",
- hdr_ver, tn, fn, pwr);
+ /* Burst batching breaker */
+ if (br == NULL) {
+ if (pdu_num > 0)
+ goto sendall;
+ return -ENOMSG;
+ }
- switch (hdr_ver) {
- case 0:
- case 1:
- /* Both versions have the same header format */
+ /* Pointer to the last encoded PDU */
+ last_pdu = &buf[0];
+
+ switch (pdu_ver) {
+ /* Both versions have the same PDU format */
+ case 0: /* TRXDv0 */
+ case 1: /* TRXDv1 */
+ buf[0] = ((pdu_ver & 0x0f) << 4) | br->tn;
+ osmo_store32be(br->fn, buf + 1);
+ buf[5] = br->att;
+ buf += 6;
+ break;
+ case 2: /* TRXDv2 */
+ buf[0] = br->tn;
+ /* BATCH.ind will be unset in the last PDU */
+ buf[1] = (br->trx_num & 0x3f) | (1 << 7);
+ buf[2] = trx_data_mod_val[br->mod]
+ | (br->tsc_set << 3)
+ | (br->tsc & 0x07);
+ buf[3] = br->att;
+ buf[4] = (uint8_t) br->scpir;
+ buf[5] = buf[6] = buf[7] = 0x00; /* Spare */
+ /* Some fields are not present in batched PDUs */
+ if (pdu_num == 0) {
+ buf[0] |= (pdu_ver & 0x0f) << 4;
+ osmo_store32be(br->fn, buf + 8);
+ buf += 4;
+ }
+ buf += 8;
break;
-
default:
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
- "Requested TRXD header version %u is not supported\n", hdr_ver);
- return -ENOTSUP;
+ /* Shall not happen */
+ OSMO_ASSERT(0);
}
- buf[0] = ((hdr_ver & 0x0f) << 4) | tn;
- buf[1] = (fn >> 24) & 0xff;
- buf[2] = (fn >> 16) & 0xff;
- buf[3] = (fn >> 8) & 0xff;
- buf[4] = (fn >> 0) & 0xff;
- buf[5] = pwr;
-
/* copy ubits {0,1} */
- memcpy(buf + 6, bits, nbits);
+ memcpy(buf, br->burst, br->burst_len);
+ buf += br->burst_len;
+
+ /* One more PDU in the buffer */
+ pdu_num++;
+
+ /* TRXDv2: wait for the batching breaker */
+ if (pdu_ver >= 2)
+ return 0;
+
+sendall:
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
+ "Tx TRXDv%u datagram with %u PDU(s)\n",
+ pdu_ver, pdu_num);
+
+ /* TRXDv2: unset BATCH.ind in the last PDU */
+ if (pdu_ver >= 2)
+ last_pdu[1] &= ~(1 << 7);
+
+ buf_len = buf - &trx_data_buf[0];
+ buf = &trx_data_buf[0];
+ pdu_num = 0;
- /* we must be sure that we have clock, and we have sent all control
- * data */
- if (transceiver_available && llist_empty(&l1h->trx_ctrl_list)) {
- send(l1h->trx_ofd_data.fd, buf, nbits + 6, 0);
- } else
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Ignoring TX data, transceiver offline.\n");
+ snd_len = send(l1h->trx_ofd_data.fd, trx_data_buf, buf_len, 0);
+ if (OSMO_UNLIKELY(snd_len <= 0)) {
+ strerror_r(errno, (char *) trx_data_buf, sizeof(trx_data_buf));
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "send() failed on TRXD with rc=%zd (%s)\n",
+ snd_len, trx_data_buf);
+ return -2;
+ }
return 0;
}
@@ -1116,12 +1235,21 @@ void trx_if_flush(struct trx_l1h *l1h)
talloc_free(tcm);
}
talloc_free(l1h->last_acked);
+ l1h->last_acked = NULL;
+
+ /* Tx queue is now empty, so there's no point in keeping the retrans timer armed: */
+ osmo_timer_del(&l1h->trx_ctrl_timer);
+
+ /* If we are in read_cb, signal to the returning code path that we freed the list. */
+ if (l1h->in_trx_ctrl_read_cb)
+ l1h->flushed_while_in_trx_ctrl_read_cb = true;
}
/*! close the TRX for given handle (data + control socket) */
void trx_if_close(struct trx_l1h *l1h)
{
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Close transceiver\n");
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Closing TRXC/TRXD connections to %s\n",
+ l1h->phy_inst->phy_link->u.osmotrx.remote_ip);
trx_if_flush(l1h);
@@ -1131,7 +1259,7 @@ void trx_if_close(struct trx_l1h *l1h)
}
/*! compute UDP port number used for TRX protocol */
-static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data)
+static uint16_t compute_port(struct phy_instance *pinst, bool remote, bool is_data)
{
struct phy_link *plink = pinst->phy_link;
uint16_t inc = 1;
@@ -1145,46 +1273,32 @@ static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data
return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc;
}
-/*! open a TRX interface. creates contro + data sockets */
+/*! open a TRX interface. creates control + data sockets */
static int trx_if_open(struct trx_l1h *l1h)
{
struct phy_instance *pinst = l1h->phy_inst;
struct phy_link *plink = pinst->phy_link;
int rc;
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Open transceiver\n");
-
- /* initialize ctrl queue */
- INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
+ LOGPPHI(pinst, DTRX, LOGL_NOTICE, "Opening TRXC/TRXD connections to %s\n", plink->u.osmotrx.remote_ip);
/* open sockets */
rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl,
plink->u.osmotrx.local_ip,
- compute_port(pinst, 0, 0),
+ compute_port(pinst, false, false),
plink->u.osmotrx.remote_ip,
- compute_port(pinst, 1, 0), trx_ctrl_read_cb);
+ compute_port(pinst, true, false), trx_ctrl_read_cb);
if (rc < 0)
- goto err;
+ return rc;
rc = trx_udp_open(l1h, &l1h->trx_ofd_data,
plink->u.osmotrx.local_ip,
- compute_port(pinst, 0, 1),
+ compute_port(pinst, false, true),
plink->u.osmotrx.remote_ip,
- compute_port(pinst, 1, 1), trx_data_read_cb);
+ compute_port(pinst, true, true), trx_data_read_cb);
if (rc < 0)
- goto err;
-
- /* enable all slots */
- l1h->config.slotmask = 0xff;
-
- /* FIXME: why was this only for TRX0 ? */
- //if (l1h->trx->nr == 0)
- trx_if_cmd_poweroff(l1h);
+ return rc;
return 0;
-
-err:
- trx_if_close(l1h);
- return rc;
}
/*! close the control + burst data sockets for one phy_instance */
@@ -1193,7 +1307,8 @@ static void trx_phy_inst_close(struct phy_instance *pinst)
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
trx_if_close(l1h);
- trx_sched_exit(&l1h->l1s);
+ if (pinst->trx)
+ trx_sched_clean(pinst->trx);
}
/*! open the control + burst data sockets for one phy_instance */
@@ -1206,11 +1321,9 @@ static int trx_phy_inst_open(struct phy_instance *pinst)
if (!l1h)
return -EINVAL;
- rc = trx_sched_init(&l1h->l1s, pinst->trx);
- if (rc < 0) {
- LOGPPHI(l1h->phy_inst, DL1C, LOGL_FATAL, "Cannot initialize scheduler\n");
- return -EIO;
- }
+ /* PHY instance may be not associated with a TRX instance */
+ if (pinst->trx != NULL)
+ trx_sched_init(pinst->trx);
rc = trx_if_open(l1h);
if (rc < 0) {
@@ -1244,11 +1357,12 @@ int bts_model_phy_link_open(struct phy_link *plink)
/* open the individual instances with their ctrl+data sockets */
llist_for_each_entry(pinst, &plink->instances, list) {
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (trx_phy_inst_open(pinst) < 0)
goto cleanup;
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_OPEN, NULL);
}
- /* FIXME: is there better way to check/report TRX availability? */
- transceiver_available = 1;
+
return 0;
cleanup:
@@ -1263,8 +1377,27 @@ cleanup:
return -1;
}
+/*! close the PHY link using TRX protocol */
+int bts_model_phy_link_close(struct phy_link *plink)
+{
+ bool clock_stopped = false;
+ struct phy_instance *pinst;
+ llist_for_each_entry(pinst, &plink->instances, list) {
+ if (!clock_stopped) {
+ clock_stopped = true;
+ trx_sched_clock_stopped(pinst->trx->bts);
+ }
+ trx_phy_inst_close(pinst);
+ }
+ trx_udp_close(&plink->u.osmotrx.trx_ofd_clk);
+ phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
+ return 0;
+}
+
/*! determine if the TRX for given handle is powered up */
int trx_if_powered(struct trx_l1h *l1h)
{
- return l1h->config.poweron;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+ return plink->u.osmotrx.powered;
}
diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h
index dda7116e..3a22a1b4 100644
--- a/src/osmo-bts-trx/trx_if.h
+++ b/src/osmo-bts-trx/trx_if.h
@@ -1,8 +1,11 @@
-#ifndef TRX_IF_H
-#define TRX_IF_H
+#pragma once
-extern int transceiver_available;
+/* TRXC read/send buffer size */
+#define TRXC_MSG_BUF_SIZE 1500
+/* TRXD read/send buffer size (max. lo MTU) */
+#define TRXD_MSG_BUF_SIZE 65536
+struct trx_dl_burst_req;
struct trx_l1h;
struct trx_ctrl_msg {
@@ -15,30 +18,37 @@ struct trx_ctrl_msg {
void *cb;
};
+typedef void trx_if_cmd_generic_cb(struct trx_l1h *l1h, int rc);
+typedef void trx_if_cmd_poweronoff_cb(struct trx_l1h *l1h, bool poweronoff, int rc);
typedef void trx_if_cmd_setslot_cb(struct trx_l1h *l1h, uint8_t tn, uint8_t type, int rc);
+typedef void trx_if_cmd_getnompower_cb(struct trx_l1h *l1h, int nominal_power, int rc);
+typedef void trx_if_cmd_setpower_att_cb(struct trx_l1h *l1h, int power_att_db, int rc);
void trx_if_init(struct trx_l1h *l1h);
-int trx_if_cmd_poweroff(struct trx_l1h *l1h);
-int trx_if_cmd_poweron(struct trx_l1h *l1h);
-int trx_if_cmd_settsc(struct trx_l1h *l1h, uint8_t tsc);
-int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic);
+int trx_if_cmd_poweroff(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb);
+int trx_if_cmd_poweron(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb);
+int trx_if_cmd_settsc(struct trx_l1h *l1h, uint8_t tsc, trx_if_cmd_generic_cb *cb);
+int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic, trx_if_cmd_generic_cb *cb);
int trx_if_cmd_setrxgain(struct trx_l1h *l1h, int db);
-int trx_if_cmd_setpower(struct trx_l1h *l1h, int db);
+int trx_if_cmd_getnompower(struct trx_l1h *l1h, trx_if_cmd_getnompower_cb *cb);
+int trx_if_cmd_setpower_att(struct trx_l1h *l1h, int power_att_db, trx_if_cmd_setpower_att_cb *cb);
int trx_if_cmd_setmaxdly(struct trx_l1h *l1h, int dly);
int trx_if_cmd_setmaxdlynb(struct trx_l1h *l1h, int dly);
-int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn, uint8_t type, trx_if_cmd_setslot_cb *cb);
-int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn);
-int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn);
+int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn, trx_if_cmd_setslot_cb *cb);
+int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb);
+int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb);
int trx_if_cmd_handover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
-int trx_if_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
- const ubit_t *bits, uint16_t nbits);
+int trx_if_cmd_rfmute(struct trx_l1h *l1h, bool mute);
+int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br);
int trx_if_powered(struct trx_l1h *l1h);
-/* The latest supported TRXD header format version */
-#define TRX_DATA_FORMAT_VER 1
+/* The latest supported TRXD PDU version */
+#define TRX_DATA_PDU_VER 2
/* Format negotiation command */
-int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver);
+int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver, trx_if_cmd_generic_cb *cb);
-#endif /* TRX_IF_H */
+int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb,
+ const char *cmd, const char *fmt, ...);
+#define trx_ctrl_cmd(l1h, critical, cmd, fmt, ...) trx_ctrl_cmd_cb(l1h, critical, NULL, cmd, fmt, ##__VA_ARGS__)
diff --git a/src/osmo-bts-trx/trx_provision_fsm.c b/src/osmo-bts-trx/trx_provision_fsm.c
new file mode 100644
index 00000000..5ca23e31
--- /dev/null
+++ b/src/osmo-bts-trx/trx_provision_fsm.c
@@ -0,0 +1,740 @@
+/* TRX provision FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/nm_common_fsm.h>
+#include <osmo-bts/signal.h>
+
+#include "l1_if.h"
+#include "trx_provision_fsm.h"
+
+#define X(s) (1 << (s))
+
+#define trx_prov_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
+
+static void l1if_poweronoff_cb(struct trx_l1h *l1h, bool poweronoff, int rc)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+
+ plink->u.osmotrx.powered = poweronoff;
+
+ if (poweronoff) {
+ plink->u.osmotrx.poweron_sent = false;
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_POWERON_CNF, (void*)(intptr_t)rc);
+ } else {
+ plink->u.osmotrx.poweroff_sent = false;
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_POWEROFF_CNF, (void*)(intptr_t)rc);
+ }
+}
+
+
+void l1if_rxtune_cb(struct trx_l1h *l1h, int rc)
+{
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_RXTUNE_CNF, (void*)(intptr_t)rc);
+}
+
+void l1if_txtune_cb(struct trx_l1h *l1h, int rc)
+{
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_TXTUNE_CNF, (void*)(intptr_t)rc);
+}
+
+void l1if_settsc_cb(struct trx_l1h *l1h, int rc)
+{
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_SETTSC_CNF, (void*)(intptr_t)rc);
+}
+
+void l1if_setbsic_cb(struct trx_l1h *l1h, int rc)
+{
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_SETBSIC_CNF, (void*)(intptr_t)rc);
+}
+
+static void l1if_getnompower_cb(struct trx_l1h *l1h, int nominal_power, int rc)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ LOGPPHI(pinst, DL1C, LOGL_DEBUG, "l1if_getnompower_cb(nominal_power=%d, rc=%d)\n", nominal_power, rc);
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_NOMTXPOWER_CNF, (void*)(intptr_t)nominal_power);
+}
+
+void l1if_setformat_cb(struct trx_l1h *l1h, int rc)
+{
+ osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_SETFORMAT_CNF, (void*)(intptr_t)rc);
+}
+
+/*
+ * transceiver provisioning
+ */
+
+static void trx_provision_reset(struct trx_l1h *l1h)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ uint8_t tn;
+
+ l1h->config.trxd_pdu_ver_req = pinst->phy_link->u.osmotrx.trxd_pdu_ver_max;
+ l1h->config.trxd_pdu_ver_use = 0;
+ l1h->config.setformat_sent = false;
+ l1h->config.setformat_acked = false;
+
+ l1h->config.enabled = false;
+ l1h->config.arfcn_valid = false;
+ l1h->config.arfcn = 0;
+ l1h->config.rxtune_sent = false;
+ l1h->config.rxtune_acked = false;
+ l1h->config.txtune_sent = false;
+ l1h->config.txtune_acked = false;
+
+ l1h->config.tsc_valid = false;
+ l1h->config.tsc = 0;
+ l1h->config.tsc_sent = false;
+ l1h->config.tsc_acked = false;
+
+ l1h->config.bsic_valid = false;
+ l1h->config.bsic = 0;
+ l1h->config.bsic_sent = false;
+ l1h->config.bsic_acked = false;
+
+ l1h->config.rxgain_sent = false;
+
+ l1h->config.nomtxpower_sent = false;
+ l1h->config.nomtxpower_acked = false;
+
+ l1h->config.maxdly_sent = false;
+
+ l1h->config.maxdlynb_sent = false;
+
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ l1h->config.setslot_valid[tn] = false;
+ l1h->config.setslot_sent[tn] = false;
+ l1h->config.setslot[tn].slottype = 0;
+ l1h->config.setslot[tn].tsc_set = 0;
+ l1h->config.setslot[tn].tsc_val = 0;
+ l1h->config.setslot[tn].tsc_valid = 0;
+ }
+}
+int l1if_provision_transceiver_trx(struct trx_l1h *l1h)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+
+ /* During setup, pinst may still not be associated to a TRX nr */
+ if (!pinst->trx) {
+ LOGPPHI(pinst, DL1C, LOGL_INFO,
+ "Delaying provision, TRX not yet assigned to phy instance\n");
+ return -EIO;
+ }
+
+ if (phy_link_state_get(plink) == PHY_LINK_SHUTDOWN) {
+ LOGPPHI(pinst, DL1C, LOGL_INFO,
+ "Delaying provision, TRX not yet available\n");
+ return -EIO;
+ }
+
+ /* before power on */
+ if (l1h->config.arfcn_valid) {
+ if (!l1h->config.rxtune_sent) {
+ trx_if_cmd_rxtune(l1h, l1h->config.arfcn, l1if_rxtune_cb);
+ l1h->config.rxtune_sent = true;
+ l1h->config.rxtune_acked = false;
+ }
+ if (!l1h->config.txtune_sent) {
+ trx_if_cmd_txtune(l1h, l1h->config.arfcn, l1if_txtune_cb);
+ l1h->config.txtune_sent = true;
+ l1h->config.txtune_acked = false;
+ }
+ if (l1h->config.txtune_acked) {
+ /* After TXTUNE is sent to TRX, get the tx nominal power
+ * (which may vary precisly on band/arfcn. Avoid sending
+ * it if we are forced by VTY to use a specific nominal
+ * power (because TRX may not support the command or
+ * provide broken values) */
+ if (!l1h->config.nominal_power_set_by_vty && !l1h->config.nomtxpower_sent) {
+ trx_if_cmd_getnompower(l1h, l1if_getnompower_cb);
+ l1h->config.nomtxpower_sent = true;
+ l1h->config.nomtxpower_acked = false;
+ }
+ }
+ }
+ if (!pinst->phy_link->u.osmotrx.use_legacy_setbsic &&
+ l1h->config.tsc_valid && !l1h->config.tsc_sent) {
+ trx_if_cmd_settsc(l1h, l1h->config.tsc, l1if_settsc_cb);
+ l1h->config.tsc_sent = true;
+ l1h->config.tsc_acked = false;
+ }
+ if (pinst->phy_link->u.osmotrx.use_legacy_setbsic &&
+ l1h->config.bsic_valid && !l1h->config.bsic_sent) {
+ trx_if_cmd_setbsic(l1h, l1h->config.bsic, l1if_setbsic_cb);
+ l1h->config.bsic_sent = true;
+ l1h->config.bsic_acked = false;
+ }
+
+ /* Ask transceiver to use the newest TRXD PDU version if not using it yet */
+ if (!l1h->config.setformat_sent) {
+ l1h->config.setformat_sent = true;
+ if (plink->u.osmotrx.trxd_pdu_ver_max == 0) {
+ LOGPPHI(pinst, DL1C, LOGL_INFO,
+ "No need to negotiate max TRXD version 0");
+ l1h->config.trxd_pdu_ver_use = 0;
+ l1h->config.setformat_acked = true;
+ } else {
+ trx_if_cmd_setformat(l1h, l1h->config.trxd_pdu_ver_req, l1if_setformat_cb);
+ l1h->config.setformat_acked = false;
+ }
+ }
+ return 0;
+}
+
+static void l1if_setslot_cb(struct trx_l1h *l1h, uint8_t tn, uint8_t type, int rc)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct gsm_bts_trx *trx = pinst->trx;
+ struct gsm_bts_trx_ts *ts;
+ enum gsm_phys_chan_config pchan;
+
+ if (tn >= TRX_NR_TS) {
+ LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TN (%" PRIu8 ")\n",
+ tn);
+ return;
+ }
+
+ pchan = transceiver_chan_type_2_pchan(type);
+ if (pchan == GSM_PCHAN_UNKNOWN) {
+ LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TS_TYPE (%" PRIu8 ")\n",
+ type);
+ return;
+ }
+
+ ts = &trx->ts[tn];
+ LOGPPHI(pinst, DL1C, LOGL_DEBUG, "%s l1if_setslot_cb(as_pchan=%s),"
+ " calling cb_ts_connected(rc=%d)\n",
+ gsm_ts_name(ts), gsm_pchan_name(pchan), rc);
+ cb_ts_connected(ts, rc);
+}
+
+static void update_ts_data(struct trx_l1h *l1h, struct trx_prov_ev_cfg_ts_data *data)
+{
+ l1h->config.setslot[data->tn].slottype = data->slottype;
+ l1h->config.setslot[data->tn].tsc_set = data->tsc_set;
+ l1h->config.setslot[data->tn].tsc_val = data->tsc_val;
+ l1h->config.setslot[data->tn].tsc_valid = data->tsc_valid;
+
+ l1h->config.setslot_valid[data->tn] = true;
+ l1h->config.setslot_sent[data->tn] = false;
+}
+
+/* Whether a given TRX is fully configured */
+static bool trx_is_provisioned(struct trx_l1h *l1h)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ if (l1h->config.rxtune_acked && l1h->config.txtune_acked &&
+ (l1h->config.bsic_acked || !pinst->phy_link->u.osmotrx.use_legacy_setbsic) &&
+ (l1h->config.tsc_acked || pinst->phy_link->u.osmotrx.use_legacy_setbsic) &&
+ (l1h->config.nomtxpower_acked || l1h->config.nominal_power_set_by_vty) &&
+ (l1h->config.setformat_acked)) {
+ return true;
+ }
+ return false;
+}
+
+/* Whether a given TRX is fully configured and can be powered on */
+static bool trx_is_provisioned_and_enabled(struct trx_l1h *l1h)
+{
+ return l1h->config.enabled && trx_is_provisioned(l1h);
+}
+
+static void trx_signal_ready_trx0(struct trx_l1h *l1h)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_instance *pinst_it;
+
+ llist_for_each_entry(pinst_it, &pinst->phy_link->instances, list) {
+ struct trx_l1h *l1h_it = pinst_it->u.osmotrx.hdl;
+ if (l1h_it->phy_inst->num != 0)
+ continue;
+ osmo_fsm_inst_dispatch(l1h_it->provision_fi, TRX_PROV_EV_OTHER_TRX_READY, NULL);
+ return;
+ }
+}
+
+/* Called from TRX0 to check if other TRX are already configured so POWERON can be sent */
+static bool trx_other_trx0_ready(struct trx_l1h *l1h)
+{
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_instance *pinst_it;
+
+ /* Don't POWERON until all trx are ready */
+ llist_for_each_entry(pinst_it, &pinst->phy_link->instances, list) {
+ struct trx_l1h *l1h_it = pinst_it->u.osmotrx.hdl;
+ if (l1h_it->phy_inst->num == 0)
+ continue;
+ if (!trx_is_provisioned(l1h_it))
+ return false;
+ }
+ return true;
+}
+
+/* Closes a phy_link and all its associated TRX */
+static void trx_prov_fsm_apply_close(struct phy_link *plink, int rc)
+{
+ struct trx_l1h *l1h;
+ struct phy_instance *pinst;
+
+ if (plink->state == PHY_LINK_SHUTDOWN)
+ return;
+
+ bts_model_phy_link_close(plink);
+ /* Notify TRX close on all TRX associated with this phy */
+ llist_for_each_entry(pinst, &plink->instances, list) {
+ l1h = pinst->u.osmotrx.hdl;
+ trx_prov_fsm_state_chg(l1h->provision_fi, TRX_PROV_ST_CLOSED);
+ bts_model_trx_close_cb(pinst->trx, rc);
+ }
+}
+
+static int trx_prov_fsm_signal_cb(unsigned int subsys, unsigned int signal,
+ void *hdlr_data, void *signal_data)
+{
+ struct nm_statechg_signal_data *nsd;
+ struct gsm_bts_trx *trx;
+
+ if (subsys != SS_GLOBAL)
+ return -EINVAL;
+
+ if (signal != S_NEW_OP_STATE)
+ return 0;
+
+ nsd = (struct nm_statechg_signal_data *)signal_data;
+
+ if (nsd->mo->obj_class != NM_OC_RADIO_CARRIER)
+ return 0;
+
+ if (nsd->old_state != NM_OPSTATE_ENABLED && nsd->new_state == NM_OPSTATE_ENABLED) {
+ trx = gsm_objclass2obj(nsd->mo->bts, nsd->mo->obj_class, &nsd->mo->obj_inst, NULL);
+ l1if_trx_start_power_ramp(trx, NULL);
+ }
+ return 0;
+}
+
+//////////////////////////
+// FSM STATE ACTIONS
+//////////////////////////
+
+static void st_closed(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+
+ switch (event) {
+ case TRX_PROV_EV_OPEN:
+ /* enable all slots */
+ l1h->config.slotmask = 0xff;
+ if (l1h->phy_inst->num == 0)
+ trx_if_cmd_poweroff(l1h, NULL); /* TODO: jump to poweroff upon cb received */
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWEROFF);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_open_poweroff_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+
+ trx_provision_reset(l1h);
+
+ if (pinst->trx == NULL) {
+ trx_if_cmd_rfmute(l1h, true);
+ return;
+ }
+
+ /* Apply initial RFMUTE state */
+ trx_if_cmd_rfmute(l1h, pinst->trx->mo.nm_state.administrative != NM_STATE_UNLOCKED);
+
+ osmo_fsm_inst_dispatch(pinst->trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(pinst->trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
+}
+
+static void st_open_poweroff(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct gsm_bts_trx *trx = pinst->trx;
+ uint16_t arfcn;
+ int nominal_power;
+ int status;
+ bool waiting_other_trx;
+ bool was_ready = trx_is_provisioned(l1h);
+
+ switch (event) {
+ case TRX_PROV_EV_CLOSE:
+ /* In this state, we didn't for sure send a POWERON yet, hence we
+ are save directly applying the close as if we received a
+ POWEROFF RSP: */
+ if (pinst->num == 0)
+ trx_prov_fsm_apply_close(pinst->phy_link, 0);
+ return;
+ case TRX_PROV_EV_CFG_ENABLE:
+ l1h->config.enabled =(bool)data;
+ break;
+ case TRX_PROV_EV_CFG_BSIC:
+ /* We always get BSIC from the BSC, TSC can be derived from the BCC */
+ if (!pinst->phy_link->u.osmotrx.use_legacy_setbsic) {
+ const uint8_t tsc = BSIC2BCC((uint8_t)(intptr_t)data);
+ if (l1h->config.tsc != tsc || !l1h->config.tsc_valid) {
+ l1h->config.tsc = tsc;
+ l1h->config.tsc_valid = true;
+ l1h->config.tsc_sent = false;
+ }
+ } else {
+ const uint8_t bsic = (uint8_t)(intptr_t)data;
+ if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) {
+ l1h->config.bsic = bsic;
+ l1h->config.bsic_valid = true;
+ l1h->config.bsic_sent = false;
+ }
+ }
+ break;
+ case TRX_PROV_EV_CFG_ARFCN:
+ arfcn = (uint16_t)(intptr_t)data;
+ if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) {
+ l1h->config.arfcn = arfcn;
+ l1h->config.arfcn_valid = true;
+ l1h->config.txtune_sent = false;
+ l1h->config.rxtune_sent = false;
+ l1h->config.nomtxpower_sent = false;
+ }
+ break;
+ case TRX_PROV_EV_CFG_TS:
+ update_ts_data(l1h, (struct trx_prov_ev_cfg_ts_data*)data);
+ break;
+
+ /* CONFIRMATIONS FROM TRXC */
+ case TRX_PROV_EV_RXTUNE_CNF:
+ if (l1h->config.rxtune_sent)
+ l1h->config.rxtune_acked = true;
+ break;
+ case TRX_PROV_EV_TXTUNE_CNF:
+ if (l1h->config.txtune_sent)
+ l1h->config.txtune_acked = true;
+ break;
+ case TRX_PROV_EV_NOMTXPOWER_CNF:
+ nominal_power = (int)(intptr_t)data;
+ if (l1h->config.nomtxpower_sent)
+ l1h->config.nomtxpower_acked = true;
+ l1if_trx_set_nominal_power(trx, nominal_power);
+ break;
+ case TRX_PROV_EV_SETBSIC_CNF:
+ if (l1h->config.bsic_sent)
+ l1h->config.bsic_acked = true;
+ break;
+ case TRX_PROV_EV_SETTSC_CNF:
+ if (l1h->config.tsc_sent)
+ l1h->config.tsc_acked = true;
+ break;
+ case TRX_PROV_EV_SETFORMAT_CNF:
+ status = (int)(intptr_t)data;
+ /* Transceiver may suggest a lower version (than requested) */
+ if (status == l1h->config.trxd_pdu_ver_req) {
+ l1h->config.trxd_pdu_ver_use = status;
+ l1h->config.setformat_acked = true;
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO,
+ "Using TRXD PDU version %u\n",
+ l1h->config.trxd_pdu_ver_use);
+ } else {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
+ "Transceiver suggests TRXD PDU version %u (requested %u)\n",
+ status, l1h->config.trxd_pdu_ver_req);
+ /* Send another SETFORMAT with suggested version */
+ l1h->config.trxd_pdu_ver_req = status;
+ l1h->config.setformat_sent = false;
+ }
+ break;
+ case TRX_PROV_EV_OTHER_TRX_READY:
+ OSMO_ASSERT(pinst->num == 0);
+ /* Do nothing here, we were triggered to see if we can finally poweron TRX0 below */
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ l1if_provision_transceiver_trx(l1h);
+
+ if (l1h->phy_inst->num == 0) {
+ waiting_other_trx = !trx_other_trx0_ready(l1h);
+ } else {
+ waiting_other_trx = false; /* we don't care about others in TRX!=0 */
+ /* If we just became ready for TRX0 POWERON (aka this TRX becomes provisioned), signal it to TRX0: */
+ if (l1h->phy_inst->num != 0 && (!was_ready && trx_is_provisioned(l1h)))
+ trx_signal_ready_trx0(l1h);
+ }
+
+ /* if we gathered all data and could go forward. For TRX0, only after
+ * all other TRX are prepared, since it will send POWERON commad */
+ if (trx_is_provisioned_and_enabled(l1h) && !waiting_other_trx) {
+ if (l1h->phy_inst->num != 0)
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWERON);
+ else
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_WAIT_POWERON_CNF);
+ } else {
+ LOGPFSML(fi, LOGL_INFO, "Delay poweron, wait for:%s%s%s%s%s%s%s%s\n",
+ l1h->config.enabled ? "" :" enable",
+ pinst->phy_link->u.osmotrx.use_legacy_setbsic ?
+ (l1h->config.bsic_valid ? (l1h->config.bsic_acked ? "" : " bsic-ack") : " bsic") :
+ (l1h->config.tsc_valid ? (l1h->config.tsc_acked ? "" : " tsc-ack") : " tsc"),
+ l1h->config.arfcn_valid ? "" : " arfcn",
+ l1h->config.rxtune_acked ? "" : " rxtune-ack",
+ l1h->config.txtune_acked ? "" : " txtune-ack",
+ l1h->config.nominal_power_set_by_vty ? "" : (l1h->config.nomtxpower_acked ? "" : " nomtxpower-ack"),
+ l1h->config.setformat_acked ? "" : " setformat-ack",
+ waiting_other_trx ? "" : " other-trx"
+ );
+ }
+}
+
+
+static void st_open_wait_power_cnf_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+
+ trx_if_cmd_poweron(l1h, l1if_poweronoff_cb);
+ pinst->phy_link->u.osmotrx.poweron_sent = true;
+}
+
+static void st_open_wait_power_cnf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+ int rc;
+
+ switch (event) {
+ case TRX_PROV_EV_POWERON_CNF:
+ rc = (uint16_t)(intptr_t)data;
+ if (rc == 0 && plink->state != PHY_LINK_CONNECTED) {
+ trx_sched_clock_started(pinst->trx->bts);
+ phy_link_state_set(plink, PHY_LINK_CONNECTED);
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWERON);
+ } else if (rc != 0 && plink->state != PHY_LINK_SHUTDOWN) {
+ trx_sched_clock_stopped(pinst->trx->bts);
+ phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
+ }
+ break;
+ case TRX_PROV_EV_CFG_TS:
+ update_ts_data(l1h, (struct trx_prov_ev_cfg_ts_data*)data);
+ break;
+ case TRX_PROV_EV_CLOSE:
+ /* power off transceiver, if not already */
+ if (pinst->num == 0 && !plink->u.osmotrx.poweroff_sent) {
+ trx_if_cmd_poweroff(l1h, l1if_poweronoff_cb);
+ plink->u.osmotrx.poweroff_sent = true;
+ }
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_open_poweron_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ uint8_t tn;
+
+ /* after power on */
+ if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) {
+ trx_if_cmd_setrxgain(l1h, l1h->config.rxgain);
+ l1h->config.rxgain_sent = true;
+ }
+ if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) {
+ trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly);
+ l1h->config.maxdly_sent = true;
+ }
+ if (l1h->config.maxdlynb_valid && !l1h->config.maxdlynb_sent) {
+ trx_if_cmd_setmaxdlynb(l1h, l1h->config.maxdlynb);
+ l1h->config.maxdlynb_sent = true;
+ }
+
+ for (tn = 0; tn < TRX_NR_TS; tn++) {
+ if (l1h->config.setslot_valid[tn]
+ && !l1h->config.setslot_sent[tn]) {
+ trx_if_cmd_setslot(l1h, tn, l1if_setslot_cb);
+ l1h->config.setslot_sent[tn] = true;
+ }
+ }
+}
+
+static void st_open_poweron(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+ struct trx_prov_ev_cfg_ts_data* ts_data;
+
+ switch (event) {
+ case TRX_PROV_EV_CLOSE:
+ /* power off transceiver, if not already */
+ if (pinst->num == 0 && plink->u.osmotrx.powered && !plink->u.osmotrx.poweroff_sent) {
+ trx_if_cmd_poweroff(l1h, l1if_poweronoff_cb);
+ plink->u.osmotrx.poweroff_sent = true;
+ }
+ trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF);
+ break;
+ case TRX_PROV_EV_CFG_TS:
+ ts_data = (struct trx_prov_ev_cfg_ts_data*)data;
+ update_ts_data(l1h, ts_data);
+ /* While in this state we can send SETSLOT immediately */
+ trx_if_cmd_setslot(l1h, ts_data->tn, l1if_setslot_cb);
+ l1h->config.setslot_sent[ts_data->tn] = true;
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_open_wait_poweroff_cnf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct trx_l1h *l1h = (struct trx_l1h *)fi->priv;
+ struct phy_instance *pinst = l1h->phy_inst;
+ struct phy_link *plink = pinst->phy_link;
+ int rc;
+
+ switch (event) {
+ case TRX_PROV_EV_POWEROFF_CNF:
+ rc = (uint16_t)(intptr_t)data;
+ trx_prov_fsm_apply_close(plink, rc);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static struct osmo_fsm_state trx_prov_fsm_states[] = {
+ [TRX_PROV_ST_CLOSED] = {
+ .in_event_mask =
+ X(TRX_PROV_EV_OPEN),
+ .out_state_mask =
+ X(TRX_PROV_ST_OPEN_POWEROFF),
+ .name = "CLOSED",
+ .action = st_closed,
+ },
+ [TRX_PROV_ST_OPEN_POWEROFF] = {
+ .in_event_mask =
+ X(TRX_PROV_EV_CLOSE) |
+ X(TRX_PROV_EV_OTHER_TRX_READY) |
+ X(TRX_PROV_EV_CFG_ENABLE) |
+ X(TRX_PROV_EV_CFG_BSIC) |
+ X(TRX_PROV_EV_CFG_ARFCN) |
+ X(TRX_PROV_EV_CFG_TS) |
+ X(TRX_PROV_EV_RXTUNE_CNF) |
+ X(TRX_PROV_EV_TXTUNE_CNF) |
+ X(TRX_PROV_EV_NOMTXPOWER_CNF) |
+ X(TRX_PROV_EV_SETBSIC_CNF) |
+ X(TRX_PROV_EV_SETTSC_CNF) |
+ X(TRX_PROV_EV_SETFORMAT_CNF),
+ .out_state_mask =
+ X(TRX_PROV_ST_CLOSED) |
+ X(TRX_PROV_ST_OPEN_WAIT_POWERON_CNF) |
+ X(TRX_PROV_ST_OPEN_POWERON),
+ .name = "OPEN_POWEROFF",
+ .onenter = st_open_poweroff_on_enter,
+ .action = st_open_poweroff,
+ },
+ [TRX_PROV_ST_OPEN_WAIT_POWERON_CNF] = {
+ .in_event_mask =
+ X(TRX_PROV_EV_CLOSE) |
+ X(TRX_PROV_EV_POWERON_CNF) |
+ X(TRX_PROV_EV_CFG_TS),
+ .out_state_mask =
+ X(TRX_PROV_ST_OPEN_POWERON) |
+ X(TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF),
+ .name = "OPEN_WAIT_POWERON_CNF",
+ .onenter = st_open_wait_power_cnf_on_enter,
+ .action = st_open_wait_power_cnf,
+ },
+ [TRX_PROV_ST_OPEN_POWERON] = {
+ .in_event_mask =
+ X(TRX_PROV_EV_CLOSE) |
+ X(TRX_PROV_EV_CFG_TS),
+ .out_state_mask =
+ X(TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF),
+ .name = "OPEN_POWERON",
+ .onenter = st_open_poweron_on_enter,
+ .action = st_open_poweron,
+ },
+ [TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF] = {
+ .in_event_mask =
+ X(TRX_PROV_EV_POWEROFF_CNF),
+ .out_state_mask =
+ X(TRX_PROV_ST_CLOSED),
+ .name = "OPEN_WAIT_POWEROFF_CNF",
+ .action = st_open_wait_poweroff_cnf,
+ },
+};
+
+const struct value_string trx_prov_fsm_event_names[] = {
+ OSMO_VALUE_STRING(TRX_PROV_EV_OTHER_TRX_READY),
+ OSMO_VALUE_STRING(TRX_PROV_EV_OPEN),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_ENABLE),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_BSIC),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_ARFCN),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_TS),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_RXGAIN),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CFG_SETMAXDLY),
+ OSMO_VALUE_STRING(TRX_PROV_EV_RXTUNE_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_TXTUNE_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_NOMTXPOWER_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_SETBSIC_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_SETTSC_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_SETFORMAT_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_POWERON_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_POWEROFF_CNF),
+ OSMO_VALUE_STRING(TRX_PROV_EV_CLOSE),
+ { 0, NULL }
+};
+
+struct osmo_fsm trx_prov_fsm = {
+ .name = "TRX_PROV",
+ .states = trx_prov_fsm_states,
+ .num_states = ARRAY_SIZE(trx_prov_fsm_states),
+ .event_names = trx_prov_fsm_event_names,
+ .log_subsys = DL1C,
+};
+
+static __attribute__((constructor)) void trx_prov_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&trx_prov_fsm) == 0);
+ OSMO_ASSERT(osmo_signal_register_handler(SS_GLOBAL, trx_prov_fsm_signal_cb, NULL) == 0);
+}
diff --git a/src/osmo-bts-trx/trx_provision_fsm.h b/src/osmo-bts-trx/trx_provision_fsm.h
new file mode 100644
index 00000000..e89cd328
--- /dev/null
+++ b/src/osmo-bts-trx/trx_provision_fsm.h
@@ -0,0 +1,68 @@
+/* Provision TRX over TRXC protocol FSM */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 Affero 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/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include <osmocom/core/fsm.h>
+
+enum trx_provision_fsm_states {
+ TRX_PROV_ST_CLOSED,
+ TRX_PROV_ST_OPEN_POWEROFF,
+ TRX_PROV_ST_OPEN_WAIT_POWERON_CNF,
+ TRX_PROV_ST_OPEN_POWERON,
+ TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF,
+};
+
+struct trx_prov_ev_cfg_ts_data {
+ uint8_t tn;
+ uint8_t slottype;
+
+ /* Training Sequence Code and Set */
+ uint8_t tsc_set;
+ uint8_t tsc_val;
+ bool tsc_valid;
+};
+
+enum trx_provision_fsm_events {
+ TRX_PROV_EV_OTHER_TRX_READY,
+ TRX_PROV_EV_OPEN,
+ TRX_PROV_EV_CFG_ENABLE,
+ TRX_PROV_EV_CFG_BSIC,
+ TRX_PROV_EV_CFG_ARFCN,
+ TRX_PROV_EV_CFG_TSC,
+ TRX_PROV_EV_CFG_TS,
+ TRX_PROV_EV_CFG_RXGAIN,
+ TRX_PROV_EV_CFG_SETMAXDLY,
+ TRX_PROV_EV_RXTUNE_CNF,
+ TRX_PROV_EV_TXTUNE_CNF,
+ TRX_PROV_EV_NOMTXPOWER_CNF,
+ TRX_PROV_EV_SETBSIC_CNF,
+ TRX_PROV_EV_SETTSC_CNF,
+ TRX_PROV_EV_SETFORMAT_CNF,
+ TRX_PROV_EV_POWERON_CNF,
+ TRX_PROV_EV_POWEROFF_CNF,
+ TRX_PROV_EV_CLOSE,
+};
+
+extern struct osmo_fsm trx_prov_fsm;
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index c52908e0..9056f027 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -1,4 +1,4 @@
-/* VTY interface for sysmoBTS */
+/* VTY interface for osmo-bts-trx */
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
*
@@ -42,37 +42,35 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/vty.h>
#include <osmo-bts/scheduler.h>
+#include <osmo-bts/bts.h>
#include "l1_if.h"
#include "trx_if.h"
-#include "loops.h"
+#include "amr_loop.h"
-#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n"
+#define X(x) (1 << x)
-static struct gsm_bts *vty_bts;
+#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n"
DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
SHOW_STR "Display information about transceivers\n")
{
- struct gsm_bts *bts = vty_bts;
struct gsm_bts_trx *trx;
struct trx_l1h *l1h;
+ unsigned int tn;
- if (!transceiver_available) {
- vty_out(vty, "transceiver is not connected%s", VTY_NEWLINE);
- } else {
- vty_out(vty, "transceiver is connected%s", VTY_NEWLINE);
- }
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
+ llist_for_each_entry(trx, &g_bts->trx_list, list) {
struct phy_instance *pinst = trx_phy_instance(trx);
- char *sname = osmo_sock_get_name(NULL, pinst->phy_link->u.osmotrx.trx_ofd_clk.fd);
+ struct phy_link *plink = pinst->phy_link;
+ char *sname = osmo_sock_get_name(NULL, plink->u.osmotrx.trx_ofd_clk.fd);
l1h = pinst->u.osmotrx.hdl;
vty_out(vty, "TRX %d %s%s", trx->nr, sname, VTY_NEWLINE);
talloc_free(sname);
vty_out(vty, " %s%s",
- (l1h->config.poweron) ? "poweron":"poweroff",
+ trx_if_powered(l1h) ? "poweron":"poweroff",
VTY_NEWLINE);
+ vty_out(vty, "phy link state: %s%s",
+ phy_link_state_name(phy_link_state_get(plink)), VTY_NEWLINE);
if (l1h->config.arfcn_valid)
vty_out(vty, " arfcn : %d%s%s",
(l1h->config.arfcn & ~ARFCN_PCS),
@@ -89,7 +87,28 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver",
vty_out(vty, " bsic : %d%s", l1h->config.bsic,
VTY_NEWLINE);
else
- vty_out(vty, " bisc : undefined%s", VTY_NEWLINE);
+ vty_out(vty, " bsic : undefined%s", VTY_NEWLINE);
+
+ /* trx->ts[tn].priv is NULL in absence of the A-bis connection */
+ if (trx->bb_transc.rsl.link == NULL)
+ continue;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ const struct l1sched_ts *l1ts = ts->priv;
+ const struct trx_sched_multiframe *mf;
+
+ OSMO_ASSERT(l1ts != NULL);
+ mf = &trx_sched_multiframes[l1ts->mf_index];
+
+ vty_out(vty, " timeslot #%u (%s)%s",
+ tn, mf->name, VTY_NEWLINE);
+ vty_out(vty, " pending DL prims : %u%s",
+ llist_count(&l1ts->dl_prims), VTY_NEWLINE);
+ vty_out(vty, " interference : %ddBm%s",
+ l1ts->chan_state[TRXC_IDLE].meas.interf_avg,
+ VTY_NEWLINE);
+ }
}
return CMD_SUCCESS;
@@ -100,20 +119,25 @@ static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst)
{
uint8_t tn;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ struct gsm_bts_trx *trx = pinst->trx;
- vty_out(vty, "PHY Instance %s%s",
- phy_instance_name(pinst), VTY_NEWLINE);
+ vty_out(vty, "PHY Instance '%s': bound to %s%s",
+ phy_instance_name(pinst),
+ gsm_trx_name(trx),
+ VTY_NEWLINE);
+
+ if (trx != NULL) {
+ const int actual = get_p_actual_mdBm(trx, trx->power_params.p_total_tgt_mdBm);
+ const int max = get_p_max_out_mdBm(trx);
+ vty_out(vty, " tx-attenuation : %d dB%s",
+ (max - actual) / 1000, VTY_NEWLINE);
+ }
if (l1h->config.rxgain_valid)
vty_out(vty, " rx-gain : %d dB%s",
l1h->config.rxgain, VTY_NEWLINE);
else
vty_out(vty, " rx-gain : undefined%s", VTY_NEWLINE);
- if (l1h->config.power_valid)
- vty_out(vty, " tx-attenuation : %d dB%s",
- l1h->config.power, VTY_NEWLINE);
- else
- vty_out(vty, " tx-attenuation : undefined%s", VTY_NEWLINE);
if (l1h->config.maxdly_valid)
vty_out(vty, " maxdly : %d%s", l1h->config.maxdly,
VTY_NEWLINE);
@@ -125,16 +149,23 @@ static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst)
else
vty_out(vty, " maxdlynb : undefined%s", VTY_NEWLINE);
for (tn = 0; tn < TRX_NR_TS; tn++) {
- if (!((1 << tn) & l1h->config.slotmask))
+ 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
+ continue;
+ } else if (!l1h->config.setslot_valid[tn]) {
vty_out(vty, " slot #%d: undefined%s", tn,
VTY_NEWLINE);
+ continue;
+ }
+
+ vty_out(vty, " slot #%d: type %d", tn,
+ l1h->config.setslot[tn].slottype);
+ if (l1h->config.setslot[tn].tsc_valid)
+ vty_out(vty, " TSC-s%dc%d",
+ l1h->config.setslot[tn].tsc_set,
+ l1h->config.setslot[tn].tsc_val);
+ vty_out(vty, "%s", VTY_NEWLINE);
}
}
@@ -163,96 +194,146 @@ DEFUN(show_phy, show_phy_cmd, "show phy",
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_ms_power_loop, cfg_phy_ms_power_loop_cmd,
+DEFUN_HIDDEN(test_send_trxc,
+ test_send_trxc_cmd,
+ "test send-trxc-cmd <0-255> CMD [.ARGS]",
+ "Various testing commands\n"
+ "Send an arbitrary TRX command\n"
+ "Transceiver number\n"
+ "TRXC command\n" "TRXC command arguments\n")
+{
+ const struct gsm_bts_trx *trx;
+ const struct phy_instance *pinst;
+ struct trx_l1h *l1h;
+ int rc;
+
+ trx = gsm_bts_trx_num(g_bts, atoi(argv[0]));
+ if (trx == NULL) {
+ vty_out(vty, "%% Could not find TRX%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ pinst = trx_phy_instance(trx);
+ l1h = pinst->u.osmotrx.hdl;
+
+ if (argc > 2) {
+ char *cmd_args = argv_concat(argv, argc, 2);
+ rc = trx_ctrl_cmd(l1h, 0, argv[1], "%s", cmd_args);
+ talloc_free(cmd_args);
+ } else {
+ rc = trx_ctrl_cmd(l1h, 0, argv[1], "");
+ }
+
+ return (rc == 0) ? CMD_SUCCESS : CMD_WARNING;
+}
+
+DEFUN_USRATTR(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "nominal-tx-power <-10-100>",
+ "Manually set (force) the nominal transmit output power in dBm\n"
+ "Nominal transmit output power level in dBm\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ int val = atoi(argv[0]);
+
+ l1if_trx_set_nominal_power(trx, val);
+ l1h->config.nominal_power_set_by_vty = true;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(cfg_trx_no_nominal_power, cfg_trx_no_nominal_power_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no nominal-tx-power",
+ NO_STR
+ "Manually set (force) the nominal transmit output power; ask the TRX instead (default)\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+
+ l1h->config.nominal_power_set_by_vty = false;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_DEPRECATED(cfg_phy_ms_power_loop, cfg_phy_ms_power_loop_cmd,
"osmotrx ms-power-loop <-127-127>", OSMOTRX_STR
"Enable MS power control loop\nTarget RSSI value (transceiver specific, "
"should be 6dB or more above noise floor)\n")
{
- struct phy_link *plink = vty->index;
+ vty_out(vty, "'%s' is deprecated, MS Power Control is now managed by BSC%s",
+ self->string, VTY_NEWLINE);
- plink->u.osmotrx.trx_target_rssi = atoi(argv[0]);
- plink->u.osmotrx.trx_ms_power_loop = true;
+ uint8_t rxlev = dbm2rxlev(atoi(argv[0]));
+ g_bts->ms_dpc_params.rxlev_meas.lower_thresh = rxlev;
+ g_bts->ms_dpc_params.rxlev_meas.upper_thresh = rxlev;
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_no_ms_power_loop, cfg_phy_no_ms_power_loop_cmd,
+DEFUN_DEPRECATED(cfg_phy_no_ms_power_loop, cfg_phy_no_ms_power_loop_cmd,
"no osmotrx ms-power-loop",
NO_STR OSMOTRX_STR "Disable MS power control loop\n")
{
- struct phy_link *plink = vty->index;
-
- plink->u.osmotrx.trx_ms_power_loop = false;
+ vty_out(vty, "'%s' is deprecated, MS Power Control is now managed by BSC%s",
+ self->string, VTY_NEWLINE);
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_timing_advance_loop, cfg_phy_timing_advance_loop_cmd,
+DEFUN_DEPRECATED(cfg_phy_timing_advance_loop, cfg_phy_timing_advance_loop_cmd,
"osmotrx timing-advance-loop", OSMOTRX_STR
"Enable timing advance control loop\n")
{
- struct phy_link *plink = vty->index;
-
- plink->u.osmotrx.trx_ta_loop = true;
+ vty_out(vty, "'%s' is deprecated, Timing Advance loop is now active by default%s",
+ self->string, VTY_NEWLINE);
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_no_timing_advance_loop, cfg_phy_no_timing_advance_loop_cmd,
+DEFUN_DEPRECATED(cfg_phy_no_timing_advance_loop, cfg_phy_no_timing_advance_loop_cmd,
"no osmotrx timing-advance-loop",
NO_STR OSMOTRX_STR "Disable timing advance control loop\n")
{
- struct phy_link *plink = vty->index;
-
- plink->u.osmotrx.trx_ta_loop = false;
+ vty_out(vty, "'%s' is deprecated, Timing Advance loop is now active by default%s",
+ self->string, VTY_NEWLINE);
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd,
- "osmotrx maxdly <0-31>",
- OSMOTRX_STR
- "Set the maximum acceptable delay of an Access Burst (in GSM symbols)."
- " Access Burst is the first burst a mobile transmits in order to establish"
- " a connection and it is used to estimate Timing Advance (TA) which is"
- " then applied to Normal Bursts to compensate for signal delay due to"
- " distance. So changing this setting effectively changes maximum range of"
- " the cell, because if we receive an Access Burst with a delay higher than"
- " this value, it will be ignored and connection is dropped.\n"
- "GSM symbols (approx. 1.1km per symbol)\n")
+DEFUN_USRATTR(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx maxdly <0-63>",
+ OSMOTRX_STR
+ "Set the maximum acceptable delay of an Access Burst\n"
+ "Delay in GSMK symbol periods (approx. 550m per symbol)\n")
{
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;
- l1h->config.maxdly_sent = 0;
- l1if_provision_transceiver_trx(l1h);
+ l1h->config.maxdly_sent = false;
return CMD_SUCCESS;
}
-
-DEFUN(cfg_phyinst_maxdlynb, cfg_phyinst_maxdlynb_cmd,
- "osmotrx maxdlynb <0-31>",
- OSMOTRX_STR
- "Set the maximum acceptable delay of a Normal Burst (in GSM symbols)."
- " USE FOR TESTING ONLY, DON'T CHANGE IN PRODUCTION USE!"
- " During normal operation, Normal Bursts delay are controlled by a Timing"
- " Advance control loop and thus Normal Bursts arrive to a BTS with no more"
- " than a couple GSM symbols, which is already taken into account in osmo-trx."
- " So changing this setting will have no effect in production installations"
- " except increasing osmo-trx CPU load. This setting is only useful when"
- " testing with a transmitter which can't precisely synchronize to the BTS"
- " downlink signal, like e.g. R&S CMD57.\n"
- "GSM symbols (approx. 1.1km per symbol)\n")
+DEFUN_ATTR_USRATTR(cfg_phyinst_maxdlynb, cfg_phyinst_maxdlynb_cmd,
+ CMD_ATTR_HIDDEN, /* expert mode command */
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx maxdlynb <0-63>",
+ OSMOTRX_STR
+ "Set the maximum acceptable delay of a Normal Burst\n"
+ "Delay in GMSK symbol periods (approx. 550m per symbol)\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
l1h->config.maxdlynb = atoi(argv[0]);
l1h->config.maxdlynb_valid = 1;
- l1h->config.maxdlynb_sent = 0;
- l1if_provision_transceiver_trx(l1h);
+ l1h->config.maxdlynb_sent = false;
return CMD_SUCCESS;
}
@@ -277,7 +358,7 @@ DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_power_on, cfg_phyinst_power_on_cmd,
+DEFUN_DEPRECATED(cfg_phyinst_power_on, cfg_phyinst_power_on_cmd,
"osmotrx power (on|off)",
OSMOTRX_STR
"Change TRX state\n"
@@ -286,21 +367,26 @@ DEFUN(cfg_phyinst_power_on, cfg_phyinst_power_on_cmd,
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ vty_out (vty, "'osmotrx power' is deprecated, use OML's standard "
+ "Administrative State instead to control each TRX "
+ "('rf_locked' VTY cmd in osmo-bsc)%s", VTY_NEWLINE);
+
if (strcmp(argv[0], "on"))
- vty_out(vty, "OFF: %d%s", trx_if_cmd_poweroff(l1h), VTY_NEWLINE);
+ vty_out(vty, "OFF: %d%s", trx_if_cmd_poweroff(l1h, NULL), VTY_NEWLINE);
else {
- vty_out(vty, "ON: %d%s", trx_if_cmd_poweron(l1h), VTY_NEWLINE);
+ vty_out(vty, "ON: %d%s", trx_if_cmd_poweron(l1h, NULL), VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-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")
+DEFUN_ATTR(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",
+ CMD_ATTR_IMMEDIATE)
{
struct phy_link *plink = vty->index;
@@ -309,12 +395,13 @@ DEFUN(cfg_phy_fn_advance, cfg_phy_fn_advance_cmd,
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")
+DEFUN_ATTR(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",
+ CMD_ATTR_IMMEDIATE)
{
struct phy_link *plink = vty->index;
@@ -323,61 +410,49 @@ DEFUN(cfg_phy_rts_advance, cfg_phy_rts_advance_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_rxgain, cfg_phyinst_rxgain_cmd,
- "osmotrx rx-gain <0-50>",
- OSMOTRX_STR
- "Set the receiver gain in dB\n"
- "Gain in dB\n")
+DEFUN_USRATTR(cfg_phyinst_rxgain, cfg_phyinst_rxgain_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx rx-gain <0-50>",
+ OSMOTRX_STR
+ "Set the receiver gain in dB\n"
+ "Gain in dB\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
l1h->config.rxgain = atoi(argv[0]);
l1h->config.rxgain_valid = 1;
- l1h->config.rxgain_sent = 0;
- l1if_provision_transceiver_trx(l1h);
+ l1h->config.rxgain_sent = false;
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_tx_atten, cfg_phyinst_tx_atten_cmd,
- "osmotrx tx-attenuation <0-50>",
- OSMOTRX_STR
- "Set the transmitter attenuation\n"
- "Fixed attenuation in dB, overriding OML\n")
+DEFUN_ATTR(cfg_phyinst_tx_atten, cfg_phyinst_tx_atten_cmd,
+ "osmotrx tx-attenuation (oml|<0-50>)",
+ OSMOTRX_STR
+ "Set the transmitter attenuation\n"
+ "Use NM_ATT_RF_MAXPOWR_R (max power reduction) from BSC via OML (default)\n"
+ "Fixed attenuation in dB, overriding OML (default)\n",
+ CMD_ATTR_IMMEDIATE)
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
- 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_phyinst_tx_atten_oml, cfg_phyinst_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_instance *pinst = vty->index;
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+ if (strcmp(argv[0], "oml") == 0)
+ l1h->config.forced_max_power_red = -1;
+ else
+ l1h->config.forced_max_power_red = atoi(argv[0]);
- l1h->config.power_oml = 1;
- l1h->config.power_valid = 1;
- l1h->config.power_sent = 0;
- l1if_provision_transceiver_trx(l1h);
+ if (pinst->trx && pinst->trx->mo.nm_state.operational == NM_OPSTATE_ENABLED)
+ l1if_trx_start_power_ramp(pinst->trx, NULL);
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_no_rxgain, cfg_phyinst_no_rxgain_cmd,
- "no osmotrx rx-gain",
- NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n")
+DEFUN_USRATTR(cfg_phyinst_no_rxgain, cfg_phyinst_no_rxgain_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no osmotrx rx-gain",
+ NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
@@ -387,22 +462,11 @@ DEFUN(cfg_phyinst_no_rxgain, cfg_phyinst_no_rxgain_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_no_tx_atten, cfg_phyinst_no_tx_atten_cmd,
- "no osmotrx tx-attenuation",
- NO_STR OSMOTRX_STR "Unset the transmitter attenuation\n")
-{
- struct phy_instance *pinst = vty->index;
- struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
-
- l1h->config.power_valid = 0;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd,
- "no osmotrx maxdly",
- NO_STR OSMOTRX_STR
- "Unset the maximum delay of GSM symbols\n")
+DEFUN_USRATTR(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no osmotrx maxdly",
+ NO_STR OSMOTRX_STR
+ "Unset the maximum delay of GSM symbols\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
@@ -412,10 +476,11 @@ DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phyinst_no_maxdlynb, cfg_phyinst_no_maxdlynb_cmd,
- "no osmotrx maxdlynb",
- NO_STR OSMOTRX_STR
- "Unset the maximum delay of GSM symbols\n")
+DEFUN_USRATTR(cfg_phyinst_no_maxdlynb, cfg_phyinst_no_maxdlynb_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no osmotrx maxdlynb",
+ NO_STR OSMOTRX_STR
+ "Unset the maximum delay of GSM symbols\n")
{
struct phy_instance *pinst = vty->index;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
@@ -472,9 +537,10 @@ DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_setbsic, cfg_phy_setbsic_cmd,
- "osmotrx legacy-setbsic", OSMOTRX_STR
- "Use SETBSIC to configure transceiver (use ONLY with OpenBTS Transceiver!)\n")
+DEFUN_USRATTR(cfg_phy_setbsic, cfg_phy_setbsic_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx legacy-setbsic", OSMOTRX_STR
+ "Use SETBSIC to configure transceiver (use ONLY with OpenBTS Transceiver!)\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.use_legacy_setbsic = true;
@@ -486,9 +552,10 @@ DEFUN(cfg_phy_setbsic, cfg_phy_setbsic_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_no_setbsic, cfg_phy_no_setbsic_cmd,
- "no osmotrx legacy-setbsic",
- NO_STR OSMOTRX_STR "Disable Legacy SETBSIC to configure transceiver\n")
+DEFUN_USRATTR(cfg_phy_no_setbsic, cfg_phy_no_setbsic_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no osmotrx legacy-setbsic",
+ NO_STR OSMOTRX_STR "Disable Legacy SETBSIC to configure transceiver\n")
{
struct phy_link *plink = vty->index;
plink->u.osmotrx.use_legacy_setbsic = false;
@@ -496,30 +563,31 @@ DEFUN(cfg_phy_no_setbsic, cfg_phy_no_setbsic_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_phy_trxd_max_version, cfg_phy_trxd_max_version_cmd,
- "osmotrx trxd-max-version (latest|<0-15>)", OSMOTRX_STR
- "Set maximum TRXD format version to negotiate with TRX\n"
- "Use latest supported TRXD format version (default)\n"
- "Maximum TRXD format version number\n")
+DEFUN_USRATTR(cfg_phy_trxd_max_version, cfg_phy_trxd_max_version_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx trxd-max-version (latest|<0-15>)", OSMOTRX_STR
+ "Set maximum TRXD format version to negotiate with TRX\n"
+ "Use latest supported TRXD format version (default)\n"
+ "Maximum TRXD format version number\n")
{
struct phy_link *plink = vty->index;
int max_ver;
if (strcmp(argv[0], "latest") == 0)
- max_ver = TRX_DATA_FORMAT_VER;
+ max_ver = TRX_DATA_PDU_VER;
else
max_ver = atoi(argv[0]);
- if (max_ver > TRX_DATA_FORMAT_VER) {
+ if (max_ver > TRX_DATA_PDU_VER) {
vty_out(vty, "%% Format version %d is not supported, maximum supported is %d%s",
- max_ver, TRX_DATA_FORMAT_VER, VTY_NEWLINE);
+ max_ver, TRX_DATA_PDU_VER, VTY_NEWLINE);
return CMD_WARNING;
}
- plink->u.osmotrx.trxd_hdr_ver_max = max_ver;
+ plink->u.osmotrx.trxd_pdu_ver_max = max_ver;
return CMD_SUCCESS;
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
if (plink->u.osmotrx.local_ip)
vty_out(vty, " osmotrx ip local %s%s",
@@ -528,12 +596,6 @@ void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
vty_out(vty, " osmotrx ip remote %s%s",
plink->u.osmotrx.remote_ip, VTY_NEWLINE);
- if (plink->u.osmotrx.trx_ms_power_loop)
- vty_out(vty, " osmotrx ms-power-loop %d%s", plink->u.osmotrx.trx_target_rssi, VTY_NEWLINE);
- else
- vty_out(vty, " no osmotrx ms-power-loop%s", VTY_NEWLINE);
- vty_out(vty, " %sosmotrx timing-advance-loop%s", (plink->u.osmotrx.trx_ta_loop) ? "" : "no ", VTY_NEWLINE);
-
if (plink->u.osmotrx.base_port_local)
vty_out(vty, " osmotrx base-port local %"PRIu16"%s",
plink->u.osmotrx.base_port_local, VTY_NEWLINE);
@@ -549,24 +611,22 @@ void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
if (plink->u.osmotrx.use_legacy_setbsic)
vty_out(vty, " osmotrx legacy-setbsic%s", VTY_NEWLINE);
- if (plink->u.osmotrx.trxd_hdr_ver_max != TRX_DATA_FORMAT_VER)
- vty_out(vty, " osmotrx trxd-max-version %d%s", plink->u.osmotrx.trxd_hdr_ver_max, VTY_NEWLINE);
+ if (plink->u.osmotrx.trxd_pdu_ver_max != TRX_DATA_PDU_VER)
+ vty_out(vty, " osmotrx trxd-max-version %d%s", plink->u.osmotrx.trxd_pdu_ver_max, VTY_NEWLINE);
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (l1h->config.rxgain_valid)
vty_out(vty, " osmotrx rx-gain %d%s",
l1h->config.rxgain, VTY_NEWLINE);
- if (l1h->config.power_valid) {
- if (l1h->config.power_oml)
- vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE);
- else
- vty_out(vty, " osmotrx tx-attenuation %d%s",
- l1h->config.power, VTY_NEWLINE);
- }
+ if (l1h->config.forced_max_power_red == -1)
+ vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE);
+ else
+ vty_out(vty, " osmotrx tx-attenuation %d%s",
+ l1h->config.forced_max_power_red, VTY_NEWLINE);
if (l1h->config.maxdly_valid)
vty_out(vty, " osmotrx maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE);
if (l1h->config.maxdlynb_valid)
@@ -584,21 +644,30 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst
VTY_NEWLINE);
}
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
{
}
-void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
+
+ if (l1h->config.nominal_power_set_by_vty)
+ vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,
+ VTY_NEWLINE);
}
-int bts_model_vty_init(struct gsm_bts *bts)
+int bts_model_vty_init(void *ctx)
{
- vty_bts = bts;
-
install_element_ve(&show_transceiver_cmd);
install_element_ve(&show_phy_cmd);
+ install_element(ENABLE_NODE, &test_send_trxc_cmd);
+
+ install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
+ install_element(TRX_NODE, &cfg_trx_no_nominal_power_cmd);
+
install_element(PHY_NODE, &cfg_phy_ms_power_loop_cmd);
install_element(PHY_NODE, &cfg_phy_no_ms_power_loop_cmd);
install_element(PHY_NODE, &cfg_phy_timing_advance_loop_cmd);
@@ -614,9 +683,7 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(PHY_INST_NODE, &cfg_phyinst_rxgain_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_tx_atten_cmd);
- install_element(PHY_INST_NODE, &cfg_phyinst_tx_atten_oml_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_no_rxgain_cmd);
- install_element(PHY_INST_NODE, &cfg_phyinst_no_tx_atten_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_slotmask_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_power_on_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd);
diff --git a/src/osmo-bts-virtual/Makefile.am b/src/osmo-bts-virtual/Makefile.am
index 070efed6..bbb79eca 100644
--- a/src/osmo-bts-virtual/Makefile.am
+++ b/src/osmo-bts-virtual/Makefile.am
@@ -1,10 +1,50 @@
-AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBGPS_CFLAGS)
+AM_CFLAGS = \
+ -Wall -fno-strict-aliasing \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBGPS_CFLAGS) \
+ $(NULL)
+
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -Iinclude
-COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) -ldl
-noinst_HEADERS = l1_if.h osmo_mcast_sock.h virtual_um.h
+COMMON_LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ -ldl \
+ $(NULL)
+
+noinst_HEADERS = \
+ l1_if.h \
+ osmo_mcast_sock.h \
+ virtual_um.h \
+ $(NULL)
bin_PROGRAMS = osmo-bts-virtual
-osmo_bts_virtual_SOURCES = main.c bts_model.c virtualbts_vty.c scheduler_virtbts.c l1_if.c virtual_um.c osmo_mcast_sock.c
-osmo_bts_virtual_LDADD = $(top_builddir)/src/common/libl1sched.a $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
+osmo_bts_virtual_SOURCES = \
+ main.c \
+ bts_model.c \
+ virtualbts_vty.c \
+ scheduler_virtbts.c \
+ l1_if.c \
+ virtual_um.c \
+ osmo_mcast_sock.c \
+ $(NULL)
+
+osmo_bts_virtual_LDADD = \
+ $(top_builddir)/src/common/libl1sched.a \
+ $(top_builddir)/src/common/libbts.a \
+ $(COMMON_LDADD) \
+ $(NULL)
diff --git a/src/osmo-bts-virtual/bts_model.c b/src/osmo-bts-virtual/bts_model.c
index b971af5c..a70abfb3 100644
--- a/src/osmo-bts-virtual/bts_model.c
+++ b/src/osmo-bts-virtual/bts_model.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -23,6 +23,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/codec/codec.h>
+#include <osmocom/core/fsm.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/phy_link.h>
@@ -34,6 +35,9 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/nm_common_fsm.h>
+
+#include "virtual_um.h"
/* TODO: check if dummy method is sufficient, else implement */
int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
@@ -50,10 +54,17 @@ int osmo_amr_rtp_dec(const uint8_t *rtppayload, int payload_len, uint8_t *cmr,
return -1;
}
-int bts_model_trx_close(struct gsm_bts_trx *trx)
+void bts_model_trx_close(struct gsm_bts_trx *trx)
{
- LOGP(DL1C, LOGL_NOTICE, "Unimplemented %s\n", __func__);
- return 0;
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct phy_link *plink = pinst->phy_link;
+
+ if (phy_link_state_get(plink) != PHY_LINK_SHUTDOWN) {
+ virt_um_destroy(plink->u.virt.virt_um);
+ plink->u.virt.virt_um = NULL;
+ phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
+ }
+ bts_model_trx_close_cb(trx, 0);
}
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
@@ -72,18 +83,11 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
static uint8_t vbts_set_bts(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
- uint8_t tn;
llist_for_each_entry(trx, &bts->trx_list, list) {
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
-
- for (tn = 0; tn < TRX_NR_TS; tn++)
- oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
-
/* report availability of trx to the bts. this will trigger the rsl connection */
- oml_mo_tx_sw_act_rep(&trx->mo);
- oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
}
return 0;
}
@@ -96,34 +100,78 @@ static uint8_t vbts_set_trx(struct gsm_bts_trx *trx)
static uint8_t vbts_set_ts(struct gsm_bts_trx_ts *ts)
{
- struct phy_instance *pinst = trx_phy_instance(ts->trx);
- int rc;
+ enum gsm_phys_chan_config pchan;
+
+ /* For dynamic timeslots, pick the pchan type that should currently be
+ * active. This should only be called during init, PDCH transitions
+ * will call trx_set_ts_as_pchan() directly. */
+ switch (ts->pchan) {
+ case GSM_PCHAN_TCH_F_PDCH:
+ OSMO_ASSERT((ts->flags & TS_F_PDCH_PENDING_MASK) == 0);
+ if (ts->flags & TS_F_PDCH_ACTIVE)
+ pchan = GSM_PCHAN_PDCH;
+ else
+ pchan = GSM_PCHAN_TCH_F;
+ break;
+ case GSM_PCHAN_OSMO_DYN:
+ OSMO_ASSERT(ts->dyn.pchan_is == ts->dyn.pchan_want);
+ pchan = ts->dyn.pchan_is;
+ break;
+ default:
+ pchan = ts->pchan;
+ break;
+ }
- rc = trx_sched_set_pchan(&pinst->u.virt.sched, ts->nr, ts->pchan);
- if (rc)
+ if (trx_sched_set_pchan(ts, pchan) != 0)
return NM_NACK_RES_NOTAVAIL;
+ /* activate lchans for [CBCH/]BCCH/CCCH */
+ switch (pchan) {
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ /* using RSL_CHAN_OSMO_CBCH4 is correct here, because the scheduler
+ * does not distinguish between SDCCH/4+CBCH abd SDCCH/8+CBCH. */
+ trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
+ RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
+ break;
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
+ RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
+ /* fall-through */
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH:
+ trx_sched_set_bcch_ccch(&ts->lchan[CCCH_LCHAN], true);
+ ts->lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML;
+ lchan_set_state(&ts->lchan[CCCH_LCHAN], LCHAN_S_ACTIVE);
+ break;
+ default:
+ break;
+ }
+
return 0;
}
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- int cause = 0;
+ int rc;
switch (foh->msg_type) {
case NM_MT_SET_BTS_ATTR:
- cause = vbts_set_bts(obj);
+ rc = vbts_set_bts(obj);
break;
case NM_MT_SET_RADIO_ATTR:
- cause = vbts_set_trx(obj);
+ rc = vbts_set_trx(obj);
break;
case NM_MT_SET_CHAN_ATTR:
- cause = vbts_set_ts(obj);
+ rc = vbts_set_ts(obj);
+ break;
+ default:
+ rc = 0;
break;
}
- return oml_fom_ack_nack(msg, cause);
+
+ return rc;
}
/* MO: TS 12.21 Managed Object */
@@ -132,16 +180,15 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)
int rc;
switch (mo->obj_class) {
- case NM_OC_RADIO_CARRIER:
- case NM_OC_CHANNEL:
case NM_OC_SITE_MANAGER:
- case NM_OC_BASEB_TRANSC:
case NM_OC_BTS:
+ case NM_OC_RADIO_CARRIER:
+ case NM_OC_BASEB_TRANSC:
+ case NM_OC_CHANNEL:
case NM_OC_GPRS_NSE:
case NM_OC_GPRS_CELL:
case NM_OC_GPRS_NSVC:
- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
- rc = oml_mo_opstart_ack(mo);
+ rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
break;
default:
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
@@ -166,6 +213,7 @@ int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
{
LOGP(DL1C, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ power_trx_change_compl(trx, p_trxout_mdBm);
return 0;
}
diff --git a/src/osmo-bts-virtual/l1_if.c b/src/osmo-bts-virtual/l1_if.c
index acd8ea2b..2408557d 100644
--- a/src/osmo-bts-virtual/l1_if.c
+++ b/src/osmo-bts-virtual/l1_if.c
@@ -42,6 +42,7 @@
#include <osmo-bts/amr.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/scheduler.h>
+#include <osmo-bts/handover.h>
#include "virtual_um.h"
extern int vbts_sched_start(struct gsm_bts *bts);
@@ -128,12 +129,7 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
break;
case GSMTAP_CHANNEL_TCH_F:
case GSMTAP_CHANNEL_TCH_H:
-#if 0
- /* TODO: handle voice messages */
- if (!facch && ! tch_acch) {
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, msg);
- }
-#endif
+ /* This is TCH signalling, for voice frames see GSMTAP_CHANNEL_VOICE */
case GSMTAP_CHANNEL_SDCCH4:
case GSMTAP_CHANNEL_SDCCH8:
case GSMTAP_CHANNEL_PACCH:
@@ -151,6 +147,19 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
l1sap.u.data.pdch_presence_info = PRES_INFO_BOTH;
l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0);
break;
+ case GSMTAP_CHANNEL_VOICE_F:
+ case GSMTAP_CHANNEL_VOICE_H:
+ /* the first byte indicates the type of voice codec (gsmtap_um_voice_type) */
+ msg->l2h = msgb_pull(msg, 1);
+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, msg);
+ l1sap.u.tch.chan_nr = chan_nr;
+ l1sap.u.tch.fn = fn;
+ l1sap.u.tch.rssi = 0; /* Radio Signal Strength Indicator. Best -> 0 */
+ l1sap.u.tch.ber10k = 0; /* Bit Error Rate in 0.01%. Best -> 0 */
+ l1sap.u.tch.ta_offs_256bits = 0; /* Burst time of arrival in quarter bits. Probably used for Timing Advance calc. Best -> 0 */
+ l1sap.u.tch.lqual_cb = 10 * signal_dbm; /* Link quality in centiBel = 10 * dB. */
+ l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0);
+ break;
case GSMTAP_CHANNEL_AGCH:
case GSMTAP_CHANNEL_PCH:
case GSMTAP_CHANNEL_BCCH:
@@ -179,6 +188,11 @@ nomessage:
/* called by common part once OML link is established */
int bts_model_oml_estab(struct gsm_bts *bts)
{
+ struct phy_instance *pinst = trx_phy_instance(bts->c0);
+
+ if (vbts_sched_start(pinst->trx->bts) < 0)
+ return -ENOLINK;
+
return 0;
}
@@ -196,7 +210,7 @@ int bts_model_phy_link_open(struct phy_link *plink)
plink->u.virt.virt_um = virt_um_init(plink, plink->u.virt.ms_mcast_group, plink->u.virt.ms_mcast_port,
plink->u.virt.bts_mcast_group, plink->u.virt.bts_mcast_port,
- virt_um_rcv_cb);
+ plink->u.virt.ttl, plink->u.virt.mcast_dev, virt_um_rcv_cb);
if (!plink->u.virt.virt_um) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1;
@@ -206,20 +220,9 @@ int bts_model_phy_link_open(struct phy_link *plink)
/* iterate over list of PHY instances and initialize the scheduler */
llist_for_each_entry(pinst, &plink->instances, list) {
- trx_sched_init(&pinst->u.virt.sched, pinst->trx);
- /* Only start the scheduler for the transceiver on C0.
- * If we have multiple tranceivers, CCCH is always on C0
- * and has to be auto active */
- /* Other TRX are activated via OML by a PRIM_INFO_MODIFY
- * / PRIM_INFO_ACTIVATE */
- if (pinst->trx && pinst->trx == pinst->trx->bts->c0) {
- vbts_sched_start(pinst->trx->bts);
- /* init lapdm layer 3 callback for the trx on timeslot 0 == BCCH */
- lchan_init_lapdm(&pinst->trx->ts[0].lchan[CCCH_LCHAN]);
- /* FIXME: This is probably the wrong location to set the CCCH to active... the OML link def. needs to be reworked and fixed. */
- pinst->trx->ts[0].lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML;
- lchan_set_state(&pinst->trx->ts[0].lchan[CCCH_LCHAN], LCHAN_S_ACTIVE);
- }
+ if (pinst->trx == NULL)
+ continue;
+ trx_sched_init(pinst->trx);
}
/* this will automatically update the MO state of all associated TRX objects */
@@ -236,28 +239,19 @@ int bts_model_phy_link_open(struct phy_link *plink)
/* enable ciphering */
static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink)
{
- struct gsm_bts_trx *trx = lchan->ts->trx;
- struct phy_instance *pinst = trx_phy_instance(trx);
- struct l1sched_trx *sched = &pinst->u.virt.sched;
-
/* ciphering already enabled in both directions */
if (lchan->ciph_state == LCHAN_CIPH_RXTX_CONF)
return -EINVAL;
if (!downlink) {
/* set uplink */
- trx_sched_set_cipher(sched, chan_nr, 0, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ trx_sched_set_cipher(lchan, chan_nr, false);
lchan->ciph_state = LCHAN_CIPH_RX_CONF;
} else {
/* set downlink and also set uplink, if not already */
- if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) {
- trx_sched_set_cipher(sched, chan_nr, 0,
- lchan->encr.alg_id - 1, lchan->encr.key,
- lchan->encr.key_len);
- }
- trx_sched_set_cipher(sched, chan_nr, 1, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ if (lchan->ciph_state != LCHAN_CIPH_RX_CONF)
+ trx_sched_set_cipher(lchan, chan_nr, false);
+ trx_sched_set_cipher(lchan, chan_nr, true);
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
}
@@ -318,12 +312,12 @@ static int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t f
/* 100% BER is n_bits_total is 0 */
float ber = n_bits_total==0 ? 1.0 : (float)n_errors / (float)n_bits_total;
- DEBUGPFN(DMEAS, fn, "RX L1 frame %s chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
- "ber=%.2f%% (%d/%d bits) L1_ta=%d rqd_ta=%d toa=%.2f\n",
- gsm_lchan_name(lchan), chan_nr, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
- rssi, ber*100, n_errors, n_bits_total, lchan->meas.l1_info[1], lchan->rqd_ta, toa);
+ LOGPLCFN(lchan, fn, DMEAS, LOGL_DEBUG, "RX L1 frame chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
+ "ber=%.2f%% (%d/%d bits) L1_ta=%d ta_ctrl.current=%d toa=%.2f\n", chan_nr,
+ ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power_ctrl.max), rssi, ber * 100, n_errors,
+ n_bits_total, lchan->meas.l1_info.ta, lchan->ta_ctrl.current, toa);
- l1if_fill_meas_res(&l1sap, chan_nr, lchan->rqd_ta + toa, ber, rssi, fn);
+ l1if_fill_meas_res(&l1sap, chan_nr, lchan->ta_ctrl.current + toa, ber, rssi, fn);
return l1sap_up(trx, &l1sap);
}
@@ -333,11 +327,8 @@ static int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t f
/* primitive from common part */
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
- struct phy_instance *pinst = trx_phy_instance(trx);
- struct l1sched_trx *sched = &pinst->u.virt.sched;
struct msgb *msg = l1sap->oph.msg;
uint8_t chan_nr;
- uint8_t tn, ss;
int rc = 0;
struct gsm_lchan *lchan;
@@ -346,95 +337,94 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_ph_data_req(sched, l1sap);
+ return trx_sched_ph_data_req(trx, l1sap);
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_tch_req(sched, l1sap);
+ return trx_sched_tch_req(trx, l1sap);
case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST):
+ if (l1sap->u.info.type == PRIM_INFO_ACT_CIPH)
+ chan_nr = l1sap->u.info.u.ciph_req.chan_nr;
+ else /* u.act_req used by PRIM_INFO_{ACTIVATE,DEACTIVATE,MODIFY} */
+ chan_nr = l1sap->u.info.u.act_req.chan_nr;
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ if (OSMO_UNLIKELY(lchan == NULL)) {
+ LOGP(DL1C, LOGL_ERROR,
+ "Rx MPH-INFO.req (type=0x%02x) for non-existent lchan (%s)\n",
+ l1sap->u.info.type, rsl_chan_nr_str(chan_nr));
+ rc = -ENODEV;
+ break;
+ }
+
switch (l1sap->u.info.type) {
case PRIM_INFO_ACT_CIPH:
- chan_nr = l1sap->u.info.u.ciph_req.chan_nr;
- tn = L1SAP_CHAN2TS(chan_nr);
- ss = l1sap_chan2ss(chan_nr);
- lchan = &trx->ts[tn].lchan[ss];
if (l1sap->u.info.u.ciph_req.uplink)
l1if_set_ciphering(lchan, chan_nr, 0);
if (l1sap->u.info.u.ciph_req.downlink)
l1if_set_ciphering(lchan, chan_nr, 1);
break;
case PRIM_INFO_ACTIVATE:
- case PRIM_INFO_DEACTIVATE:
- case PRIM_INFO_MODIFY:
- chan_nr = l1sap->u.info.u.act_req.chan_nr;
- tn = L1SAP_CHAN2TS(chan_nr);
- ss = l1sap_chan2ss(chan_nr);
- lchan = &trx->ts[tn].lchan[ss];
- /* we receive a channel activation request from the BSC,
- * e.g. as a response to a channel req on RACH */
- if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) {
- if ((chan_nr & 0xE0) == 0x80) {
- LOGP(DL1C, LOGL_ERROR, "Cannot activate"
- " chan_nr 0x%02x\n", chan_nr);
- break;
- }
- /* activate dedicated channel */
- trx_sched_set_lchan(sched, chan_nr, LID_DEDIC, 1);
- /* activate associated channel */
- trx_sched_set_lchan(sched, chan_nr, LID_SACCH, 1);
- /* set mode */
- trx_sched_set_mode(sched, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- (lchan->ho.active == 1));
- /* init lapdm */
- lchan_init_lapdm(lchan);
- /* set lchan active */
- lchan_set_state(lchan, LCHAN_S_ACTIVE);
- /* set initial ciphering */
- l1if_set_ciphering(lchan, chan_nr, 0);
- l1if_set_ciphering(lchan, chan_nr, 1);
- if (lchan->encr.alg_id)
- lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
- else
- lchan->ciph_state = LCHAN_CIPH_NONE;
-
- /* confirm */
- mph_info_chan_confirm(trx, chan_nr,
- PRIM_INFO_ACTIVATE, 0);
- break;
- }
- if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
- /* change mode */
- trx_sched_set_mode(sched, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- 0);
+ if ((chan_nr & 0xE0) == 0x80) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot activate"
+ " channel %s\n", rsl_chan_nr_str(chan_nr));
+ rc = -EPERM;
break;
}
+ /* activate dedicated channel */
+ trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true);
+ /* activate associated channel */
+ trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true);
+ /* set mode */
+ trx_sched_set_mode(lchan->ts, chan_nr,
+ lchan->rsl_cmode, lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.mode[0].mode,
+ lchan->tch.amr_mr.mode[1].mode,
+ lchan->tch.amr_mr.mode[2].mode,
+ lchan->tch.amr_mr.mode[3].mode,
+ amr_get_initial_mode(lchan),
+ (lchan->ho.active == HANDOVER_ENABLED ||
+ rsl_chan_rt_is_asci(lchan->rsl_chan_rt)));
+ /* set lchan active */
+ lchan_set_state(lchan, LCHAN_S_ACTIVE);
+ /* set initial ciphering */
+ l1if_set_ciphering(lchan, chan_nr, 0);
+ l1if_set_ciphering(lchan, chan_nr, 1);
+ if (lchan->encr.alg_id)
+ lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
+ else
+ lchan->ciph_state = LCHAN_CIPH_NONE;
+
+ /* confirm */
+ mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_ACTIVATE, 0);
+ break;
+ case PRIM_INFO_MODIFY:
+ /* change mode */
+ trx_sched_set_mode(lchan->ts, chan_nr,
+ lchan->rsl_cmode, lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.mode[0].mode,
+ lchan->tch.amr_mr.mode[1].mode,
+ lchan->tch.amr_mr.mode[2].mode,
+ lchan->tch.amr_mr.mode[3].mode,
+ amr_get_initial_mode(lchan),
+ 0);
+ break;
+ case PRIM_INFO_DEACTIVATE:
if ((chan_nr & 0xE0) == 0x80) {
- LOGP(DL1C, LOGL_ERROR, "Cannot deactivate "
- "chan_nr 0x%02x\n", chan_nr);
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot deactivate"
+ " channel %s\n", rsl_chan_nr_str(chan_nr));
+ rc = -EPERM;
break;
}
/* deactivate associated channel */
- trx_sched_set_lchan(sched, chan_nr, 0x40, 0);
+ trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, false);
if (!l1sap->u.info.u.act_req.sacch_only) {
/* set lchan inactive */
lchan_set_state(lchan, LCHAN_S_NONE);
/* deactivate dedicated channel */
- trx_sched_set_lchan(sched, chan_nr, 0x00, 0);
+ trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, false);
/* confirm only on dedicated channel */
mph_info_chan_confirm(trx, chan_nr,
PRIM_INFO_DEACTIVATE, 0);
diff --git a/src/osmo-bts-virtual/l1_if.h b/src/osmo-bts-virtual/l1_if.h
index 6a843b37..c55e2d38 100644
--- a/src/osmo-bts-virtual/l1_if.h
+++ b/src/osmo-bts-virtual/l1_if.h
@@ -5,9 +5,15 @@
#include "virtual_um.h"
+/* gsm_bts->model_priv, specific to osmo-bts-virtual */
+struct bts_virt_priv {
+ uint32_t last_fn;
+ struct timeval tv_clock;
+ struct osmo_timer_list fn_timer;
+};
+
struct vbts_l1h {
struct gsm_bts_trx *trx;
- struct l1sched_trx l1s;
struct virt_um_inst *virt_um;
};
diff --git a/src/osmo-bts-virtual/main.c b/src/osmo-bts-virtual/main.c
index aa1c608e..82becc37 100644
--- a/src/osmo-bts-virtual/main.c
+++ b/src/osmo-bts-virtual/main.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -47,39 +47,68 @@
#include <osmo-bts/l1sap.h>
#include <osmo-bts/phy_link.h>
#include "virtual_um.h"
+#include "l1_if.h"
/* dummy, since no direct dsp support */
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{
return 0;
}
int bts_model_init(struct gsm_bts *bts)
{
+ struct bts_virt_priv *bts_virt = talloc_zero(bts, struct bts_virt_priv);
+ bts->model_priv = bts_virt;
bts->variant = BTS_OSMO_VIRTUAL;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
-
- gsm_bts_set_feature(bts, BTS_FEAT_OML_ALERTS);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_EFR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_CBCH);
-
- bts_model_vty_init(bts);
+ bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
+ | NM_IPAC_MASK_GPRS_CODING_MCS;
+
+ /* order alphabetically */
+ osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_EFR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
return 0;
}
int bts_model_trx_init(struct gsm_bts_trx *trx)
{
+ /* Frequency bands indicated to the BSC */
+ trx->support.freq_bands = NM_IPAC_F_FREQ_BAND_PGSM
+ | NM_IPAC_F_FREQ_BAND_EGSM
+ | NM_IPAC_F_FREQ_BAND_RGSM
+ | NM_IPAC_F_FREQ_BAND_DCS
+ | NM_IPAC_F_FREQ_BAND_PCS
+ | NM_IPAC_F_FREQ_BAND_850
+ | NM_IPAC_F_FREQ_BAND_480
+ | NM_IPAC_F_FREQ_BAND_450;
+
+ /* Channel types and modes indicated to the BSC */
+ trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
+ | NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
+ | NM_IPAC_F_CHANT_SDCCH8_CBCH
+ | NM_IPAC_F_CHANT_PDCHF
+ | NM_IPAC_F_CHANT_TCHF_PDCHF;
+ trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH
+ | NM_IPAC_MASK_CHANM_CSD_NT
+ | NM_IPAC_MASK_CHANM_CSD_T;
+ /* TODO: missing rate adaptation for TCH/F14.4 (see OS#6167) */
+ trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_T_14k4;
+ trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_NT_14k4;
+
return 0;
}
void bts_model_print_help()
{
- LOGP(DSUM, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ LOGP(DLGLOBAL, LOGL_NOTICE, "Unimplemented %s\n", __func__);
}
int bts_model_handle_options(int argc, char **argv)
@@ -116,26 +145,27 @@ void bts_model_abis_close(struct gsm_bts *bts)
void bts_model_phy_link_set_defaults(struct phy_link *plink)
{
- plink->u.virt.bts_mcast_group = DEFAULT_BTS_MCAST_GROUP;
+ plink->u.virt.bts_mcast_group = talloc_strdup(plink, DEFAULT_BTS_MCAST_GROUP);
plink->u.virt.bts_mcast_port = DEFAULT_BTS_MCAST_PORT;
- plink->u.virt.ms_mcast_group = DEFAULT_MS_MCAST_GROUP;
+ plink->u.virt.ms_mcast_group = talloc_strdup(plink, DEFAULT_MS_MCAST_GROUP);
plink->u.virt.ms_mcast_port = DEFAULT_MS_MCAST_PORT;
+ plink->u.virt.ttl = -1; /* initialize to -1 to prevent us setting the TTL */
}
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
{
- LOGP(DSUM, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ LOGP(DLGLOBAL, LOGL_NOTICE, "Unimplemented %s\n", __func__);
}
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
{
- LOGP(DSUM, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ LOGP(DLGLOBAL, LOGL_NOTICE, "Unimplemented %s\n", __func__);
return -ENOTSUP;
}
void bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan)
{
- LOGP(DSUM, LOGL_NOTICE, "Unimplemented %s\n", __func__);
+ LOGP(DLGLOBAL, LOGL_NOTICE, "Unimplemented %s\n", __func__);
}
int main(int argc, char **argv)
diff --git a/src/osmo-bts-virtual/osmo_mcast_sock.c b/src/osmo-bts-virtual/osmo_mcast_sock.c
index c0f0af58..c802e02d 100644
--- a/src/osmo-bts-virtual/osmo_mcast_sock.c
+++ b/src/osmo-bts-virtual/osmo_mcast_sock.c
@@ -3,6 +3,7 @@
#include <netdb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/select.h>
+#include <osmocom/core/osmo_io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -10,104 +11,133 @@
#include <unistd.h>
#include "osmo_mcast_sock.h"
+static void noop_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
+{
+ /* nothing */
+}
+
+static const struct osmo_io_ops srv_ioops = {
+ /* no read call-back as we don't read from the socket */
+ /* libosmcoore before change-id I0c071a29e508884bac331ada5e510bbfcf440bbf requires write call-back
+ * even if we don't care about it */
+ .write_cb = noop_write_cb,
+};
+
/* server socket is what we use for transmission. It is not subscribed
* to a multicast group or locally bound, but it is just a normal UDP
* socket that's connected to the remote mcast group + port */
-int mcast_server_sock_setup(struct osmo_fd *ofd, const char* tx_mcast_group,
- uint16_t tx_mcast_port, bool loopback)
+static struct osmo_io_fd *
+mcast_server_sock_setup(void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port, bool loopback)
{
- int rc;
+ int rc, fd;
unsigned int flags = OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_UDP_REUSEADDR;
+ struct osmo_io_fd *iofd;
if (!loopback)
flags |= OSMO_SOCK_F_NO_MCAST_LOOP;
/* setup mcast server socket */
- rc = osmo_sock_init_ofd(ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
- tx_mcast_group, tx_mcast_port, flags);
+ rc = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, tx_mcast_group, tx_mcast_port, flags);
if (rc < 0) {
perror("Failed to create Multicast Server Socket");
- return rc;
+ return NULL;
}
+ fd = rc;
- return 0;
+ iofd = osmo_iofd_setup(ctx, rc, "mcast_server_sock", OSMO_IO_FD_MODE_READ_WRITE, &srv_ioops, NULL);
+ if (!iofd) {
+ close(fd);
+ return NULL;
+ }
+
+ osmo_iofd_register(iofd, -1);
+ return iofd;
+}
+
+static void mcast_sock_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
+{
+ struct mcast_bidir_sock *bidir_sock = osmo_iofd_get_data(iofd);
+ bidir_sock->read_cb(res, msg, bidir_sock->data);
}
+const struct osmo_io_ops clnt_ioops = {
+ .read_cb = mcast_sock_read_cb,
+ /* no write call-back as we don't write to the socket */
+};
+
/* the client socket is what we use for reception. It is a UDP socket
* that's bound to the GSMTAP UDP port and subscribed to the respective
* multicast group */
-int mcast_client_sock_setup(struct osmo_fd *ofd, const char *mcast_group, uint16_t mcast_port,
- int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
- void *osmo_fd_data)
+static struct osmo_io_fd *
+mcast_client_sock_setup(void *ctx, const char *mcast_group, uint16_t mcast_port,
+ void (*read_cb)(int rc, struct msgb *msg, void *data))
{
- int rc;
+ int rc, fd;
unsigned int flags = OSMO_SOCK_F_BIND | OSMO_SOCK_F_NO_MCAST_ALL | OSMO_SOCK_F_UDP_REUSEADDR;
-
- ofd->cb = fd_rx_cb;
- ofd->when = BSC_FD_READ;
- ofd->data = osmo_fd_data;
+ struct osmo_io_fd *iofd;
/* Create mcast client socket */
- rc = osmo_sock_init_ofd(ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
- NULL, mcast_port, flags);
+ rc = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, mcast_port, flags);
if (rc < 0) {
perror("Could not create mcast client socket");
- return rc;
+ return NULL;
}
+ fd = rc;
/* Configure and join the multicast group */
- rc = osmo_sock_mcast_subscribe(ofd->fd, mcast_group);
+ rc = osmo_sock_mcast_subscribe(fd, mcast_group);
if (rc < 0) {
perror("Failed to join to mcast goup");
- osmo_fd_close(ofd);
- return rc;
+ close(fd);
+ return NULL;
+ }
+
+ iofd = osmo_iofd_setup(ctx, fd, "mcast_client_sock", OSMO_IO_FD_MODE_READ_WRITE, &clnt_ioops, ctx);
+ if (!iofd) {
+ close(fd);
+ return NULL;
}
- return 0;
+ osmo_iofd_register(iofd, -1);
+ return iofd;
}
struct mcast_bidir_sock *
mcast_bidir_sock_setup(void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port,
const char *rx_mcast_group, uint16_t rx_mcast_port, bool loopback,
- int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
- void *osmo_fd_data)
+ void (*read_cb)(int rc, struct msgb *msg, void *data),
+ void *data)
{
struct mcast_bidir_sock *bidir_sock = talloc(ctx, struct mcast_bidir_sock);
- int rc;
if (!bidir_sock)
return NULL;
- rc = mcast_client_sock_setup(&bidir_sock->rx_ofd, rx_mcast_group, rx_mcast_port,
- fd_rx_cb, osmo_fd_data);
- if (rc < 0) {
+ bidir_sock->read_cb = read_cb;
+ bidir_sock->data = data;
+
+ bidir_sock->rx_iofd = mcast_client_sock_setup(bidir_sock, rx_mcast_group, rx_mcast_port, read_cb);
+ if (!bidir_sock->rx_iofd) {
talloc_free(bidir_sock);
return NULL;
}
- rc = mcast_server_sock_setup(&bidir_sock->tx_ofd, tx_mcast_group, tx_mcast_port, loopback);
- if (rc < 0) {
- osmo_fd_close(&bidir_sock->rx_ofd);
+ bidir_sock->tx_iofd = mcast_server_sock_setup(bidir_sock, tx_mcast_group, tx_mcast_port, loopback);
+ if (!bidir_sock->tx_iofd) {
+ osmo_iofd_free(bidir_sock->rx_iofd);
talloc_free(bidir_sock);
return NULL;
}
return bidir_sock;
-
-}
-
-int mcast_bidir_sock_tx(struct mcast_bidir_sock *bidir_sock, const uint8_t *data,
- unsigned int data_len)
-{
- return send(bidir_sock->tx_ofd.fd, data, data_len, 0);
}
-int mcast_bidir_sock_rx(struct mcast_bidir_sock *bidir_sock, uint8_t *buf, unsigned int buf_len)
+int mcast_bidir_sock_tx_msg(struct mcast_bidir_sock *bidir_sock, struct msgb *msg)
{
- return recv(bidir_sock->rx_ofd.fd, buf, buf_len, 0);
+ return osmo_iofd_write_msgb(bidir_sock->tx_iofd, msg);
}
void mcast_bidir_sock_close(struct mcast_bidir_sock *bidir_sock)
{
- osmo_fd_close(&bidir_sock->tx_ofd);
- osmo_fd_close(&bidir_sock->rx_ofd);
+ osmo_iofd_free(bidir_sock->tx_iofd);
+ osmo_iofd_free(bidir_sock->rx_iofd);
talloc_free(bidir_sock);
}
diff --git a/src/osmo-bts-virtual/osmo_mcast_sock.h b/src/osmo-bts-virtual/osmo_mcast_sock.h
index aa2013c6..5f68415b 100644
--- a/src/osmo-bts-virtual/osmo_mcast_sock.h
+++ b/src/osmo-bts-virtual/osmo_mcast_sock.h
@@ -4,26 +4,20 @@
#include <stdint.h>
#include <netinet/in.h>
#include <osmocom/core/select.h>
+#include <osmocom/core/osmo_io.h>
struct mcast_bidir_sock {
- struct osmo_fd tx_ofd;
- struct osmo_fd rx_ofd;
+ struct osmo_io_fd *tx_iofd;
+ struct osmo_io_fd *rx_iofd;
+ void (*read_cb)(int rc, struct msgb *msg, void *data);
+ void *data;
};
-struct mcast_bidir_sock *mcast_bidir_sock_setup(void *ctx,
- const char *tx_mcast_group, uint16_t tx_mcast_port,
- const char *rx_mcast_group, uint16_t rx_mcast_port, bool loopback,
- int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
- void *osmo_fd_data);
+struct mcast_bidir_sock *
+mcast_bidir_sock_setup(void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port,
+ const char *rx_mcast_group, uint16_t rx_mcast_port, bool loopback,
+ void (*read_cb)(int rc, struct msgb *msg, void *data),
+ void *data);
-int mcast_server_sock_setup(struct osmo_fd *ofd, const char *tx_mcast_group,
- uint16_t tx_mcast_port, bool loopback);
-
-int mcast_client_sock_setup(struct osmo_fd *ofd, const char *mcast_group, uint16_t mcast_port,
- int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
- void *osmo_fd_data);
-
-int mcast_bidir_sock_tx(struct mcast_bidir_sock *bidir_sock, const uint8_t *data, unsigned int data_len);
-int mcast_bidir_sock_rx(struct mcast_bidir_sock *bidir_sock, uint8_t *buf, unsigned int buf_len);
+int mcast_bidir_sock_tx_msg(struct mcast_bidir_sock *bidir_sock, struct msgb *msg);
void mcast_bidir_sock_close(struct mcast_bidir_sock* bidir_sock);
-
diff --git a/src/osmo-bts-virtual/scheduler_virtbts.c b/src/osmo-bts-virtual/scheduler_virtbts.c
index 259a573a..87596a79 100644
--- a/src/osmo-bts-virtual/scheduler_virtbts.c
+++ b/src/osmo-bts-virtual/scheduler_virtbts.c
@@ -1,7 +1,8 @@
-/* Scheduler worker functiosn for Virtua OsmoBTS */
+/* Scheduler worker functions for Virtua OsmoBTS */
/* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2017 Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
+ * Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@@ -13,7 +14,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -21,6 +22,7 @@
*/
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <ctype.h>
@@ -46,25 +48,18 @@
#define MODULO_HYPERFRAME 0
-static const char *gsmtap_hdr_stringify(const struct gsmtap_hdr *gh)
-{
- static char buf[256];
- snprintf(buf, sizeof(buf), "(ARFCN=%u, ts=%u, ss=%u, type=%u/%u)",
- gh->arfcn & GSMTAP_ARFCN_MASK, gh->timeslot, gh->sub_slot, gh->type, gh->sub_type);
- return buf;
-}
-
/**
* Send a message over the virtual um interface.
* This will at first wrap the msg with a GSMTAP header and then write it to the declared multicast socket.
- * TODO: we might want to remove unused argument uint8_t tn
*/
-static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, struct msgb *msg)
+static void _tx_to_virt_um(struct l1sched_ts *l1ts,
+ struct trx_dl_burst_req *br,
+ struct msgb *msg, bool is_voice_frame)
{
- const struct trx_chan_desc *chdesc = &trx_chan_desc[chan];
+ const struct trx_chan_desc *chdesc = &trx_chan_desc[br->chan];
+ const struct gsm_bts_trx *trx = l1ts->ts->trx;
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
- uint16_t arfcn = l1t->trx->arfcn; /* ARFCN of the tranceiver the message is send with */
+ uint16_t arfcn = trx->arfcn; /* ARFCN of the transceiver the message is send with */
uint8_t signal_dbm = 63; /* signal strength, 63 is best */
uint8_t snr = 63; /* signal noise ratio, 63 is best */
uint8_t *data = msgb_l2(msg); /* data to transmit (whole message without l1 header) */
@@ -76,177 +71,181 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
rsl_dec_chan_nr(chdesc->chan_nr, &rsl_chantype, &subslot, &timeslot);
/* the timeslot is not encoded in the chan_nr of the chdesc, and so has to be overwritten */
- timeslot = tn;
+ timeslot = br->tn;
/* in Osmocom, AGCH is only sent on ccch block 0. no idea why. this seems to cause false GSMTAP channel
* types for agch and pch. */
if (rsl_chantype == RSL_CHAN_PCH_AGCH &&
- l1sap_fn2ccch_block(fn) >= num_agch(l1t->trx, "PH-DATA-REQ"))
+ l1sap_fn2ccch_block(br->fn) >= num_agch(trx, "PH-DATA-REQ"))
gsmtap_chantype = GSMTAP_CHANNEL_PCH;
else
- gsmtap_chantype = chantype_rsl2gsmtap(rsl_chantype, chdesc->link_id); /* the logical channel type */
+ gsmtap_chantype = chantype_rsl2gsmtap2(rsl_chantype, chdesc->link_id, is_voice_frame); /* the logical channel type */
+
+ if (gsmtap_chantype == GSMTAP_CHANNEL_UNKNOWN) {
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Tx GSMTAP for RSL channel type 0x%02x: cannot send, this"
+ " channel type is unknown in GSMTAP\n", rsl_chantype);
+ msgb_free(msg);
+ return;
+ }
#if MODULO_HYPERFRAME
/* Restart fn after every superframe (26 * 51 frames) to simulate hyperframe overflow each 6 seconds. */
- fn %= 26 * 51;
+ br->fn %= 26 * 51;
#endif
- outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chantype, subslot, fn, signal_dbm, snr, data, data_len);
+ outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chantype, subslot, br->fn, signal_dbm, snr, data, data_len);
if (outmsg) {
- struct phy_instance *pinst = trx_phy_instance(l1t->trx);
- struct gsmtap_hdr *gh = (struct gsmtap_hdr *)msgb_data(outmsg);
+ struct phy_instance *pinst = trx_phy_instance(trx);
int rc;
rc = virt_um_write_msg(pinst->phy_link->u.virt.virt_um, outmsg);
if (rc < 0)
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
- "%s GSMTAP msg could not send to virtual Um\n", gsmtap_hdr_stringify(gh));
- else if (rc == 0)
- bts_shutdown(l1t->trx->bts, "VirtPHY write socket died\n");
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
+ "GSMTAP msg could not send to virtual Um: %s\n", strerror(-rc));
else
- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn,
- "%s Sending GSMTAP message to virtual Um\n", gsmtap_hdr_stringify(gh));
+ LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br,
+ "Sending GSMTAP message to virtual Um\n");
} else
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "GSMTAP msg could not be created!\n");
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "GSMTAP msg could not be created!\n");
/* free incoming message */
msgb_free(msg);
}
-/*
- * TX on downlink
- */
+static void tx_to_virt_um(struct l1sched_ts *l1ts,
+ struct trx_dl_burst_req *br,
+ struct msgb *msg)
+{
+ _tx_to_virt_um(l1ts, br, msg, false);
+}
+
-/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
-ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+static struct gsm_lchan *lchan_from_l1t(const struct l1sched_ts *l1ts,
+ const enum trx_chan_type chan)
{
- return NULL;
+ struct gsm_bts_trx_ts *ts = l1ts->ts;
+ uint8_t subslot = 0;
+
+ if (chan == TRXC_TCHH_1)
+ subslot = 1;
+
+ return &ts->lchan[subslot];
}
-ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+/* Determine the gsmtap_um_voice_type of a gsm_lchan */
+static int get_um_voice_type(const struct gsm_lchan *lchan)
{
- return NULL;
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (lchan->type == GSM_LCHAN_TCH_H)
+ return GSMTAP_UM_VOICE_HR;
+ else
+ return GSMTAP_UM_VOICE_FR;
+ case GSM48_CMODE_SPEECH_EFR:
+ return GSMTAP_UM_VOICE_EFR;
+ case GSM48_CMODE_SPEECH_AMR:
+ return GSMTAP_UM_VOICE_AMR;
+ default:
+ return -1;
+ }
}
-ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+static void tx_to_virt_um_voice_frame(struct l1sched_ts *l1ts,
+ struct trx_dl_burst_req *br,
+ struct msgb *msg)
{
- return NULL;
+ struct gsm_lchan *lchan = lchan_from_l1t(l1ts, br->chan);
+ int um_voice_type;
+
+ OSMO_ASSERT(lchan);
+ um_voice_type = get_um_voice_type(lchan);
+ if (um_voice_type < 0) {
+ LOGPLCHAN(lchan, DL1P, LOGL_ERROR, "Cannot determine Um voice type from lchan\n");
+ um_voice_type = 0xff;
+ }
+
+ /* the first byte indicates the type of voice codec (gsmtap_um_voice_type) */
+ msgb_pull_to_l2(msg);
+ msgb_push_u8(msg, um_voice_type);
+ msg->l2h = msg->data;
+ _tx_to_virt_um(l1ts, br, msg, true);
}
-ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+/*
+ * TX on downlink
+ */
+
+int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ return 0;
+}
+
+int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
+{
+ return 0;
+}
+
+int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
{
struct msgb *msg;
- if (bid > 0)
- return NULL;
+ if (br->bid > 0)
+ return 0;
/* get mac block from queue */
- msg = _sched_dequeue_prim(l1t, tn, fn, chan);
+ msg = _sched_dequeue_prim(l1ts, br);
if (!msg) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
- return NULL;
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
+ return -ENODEV;
}
/* check validity of message */
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! (len=%d)\n",
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim not 23 bytes, please FIX! (len=%d)\n",
msgb_l2len(msg));
/* free message */
msgb_free(msg);
- return NULL;
+ return -EINVAL;
}
/* transmit the msg received on dl from bsc to layer1 (virt Um) */
- tx_to_virt_um(l1t, tn, fn, chan, msg);
+ tx_to_virt_um(l1ts, br, msg);
- return NULL;
+ return 0;
}
-ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
{
struct msgb *msg = NULL; /* make GCC happy */
- if (bid > 0)
- return NULL;
+ if (br->bid > 0)
+ return 0;
/* get mac block from queue */
- msg = _sched_dequeue_prim(l1t, tn, fn, chan);
+ msg = _sched_dequeue_prim(l1ts, br);
if (!msg) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
- return NULL;
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
+ return -ENODEV;
}
- tx_to_virt_um(l1t, tn, fn, chan, msg);
+ tx_to_virt_um(l1ts, br, msg);
- return NULL;
+ return 0;
}
-static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,
- struct msgb **_msg_facch, int codec_mode_request)
+static void tx_tch_common(struct l1sched_ts *l1ts,
+ const struct trx_dl_burst_req *br,
+ struct msgb **_msg_tch, struct msgb **_msg_facch)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
uint8_t rsl_cmode = chan_state->rsl_cmode;
uint8_t tch_mode = chan_state->tch_mode;
struct osmo_phsap_prim *l1sap;
-#if 0
- /* handle loss detection of received TCH frames */
- if (rsl_cmode == RSL_CMOD_SPD_SPEECH
- && ++(chan_state->lost_frames) > 5) {
- uint8_t tch_data[GSM_FR_BYTES];
- int len;
-
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Missing TCH bursts detected, sending "
- "BFI for %s\n", trx_chan_desc[chan].name);
-
- /* indicate bad frame */
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR / HR */
- if (chan != TRXC_TCHF) { /* HR */
- tch_data[0] = 0x70; /* F = 0, FT = 111 */
- memset(tch_data + 1, 0, 14);
- len = 15;
- break;
- }
- memset(tch_data, 0, GSM_FR_BYTES);
- len = GSM_FR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
- if (chan != TRXC_TCHF)
- goto inval_mode1;
- memset(tch_data, 0, GSM_EFR_BYTES);
- len = GSM_EFR_BYTES;
- break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
- len = amr_compose_payload(tch_data,
- chan_state->codec[chan_state->dl_cmr],
- chan_state->codec[chan_state->dl_ft], 1);
- if (len < 2)
- break;
- memset(tch_data + 2, 0, len - 2);
- _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
- break;
- default:
-inval_mode1:
- LOGP(DL1P, LOGL_ERROR, "TCH mode invalid, please "
- "fix!\n");
- len = 0;
- }
- if (len)
- _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
- }
-#endif
/* get frame and unlink from queue */
- msg1 = _sched_dequeue_prim(l1t, tn, fn, chan);
- msg2 = _sched_dequeue_prim(l1t, tn, fn, chan);
+ msg1 = _sched_dequeue_prim(l1ts, br);
+ msg2 = _sched_dequeue_prim(l1ts, br);
if (msg1) {
l1sap = msgb_l1sap_prim(msg1);
if (l1sap->oph.primitive == PRIM_TCH) {
@@ -254,8 +253,8 @@ inval_mode1:
if (msg2) {
l1sap = msgb_l1sap_prim(msg2);
if (l1sap->oph.primitive == PRIM_TCH) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "TCH twice, please FIX! ");
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br,
+ "TCH twice, please FIX!\n");
msgb_free(msg2);
} else
msg_facch = msg2;
@@ -265,8 +264,8 @@ inval_mode1:
if (msg2) {
l1sap = msgb_l1sap_prim(msg2);
if (l1sap->oph.primitive != PRIM_TCH) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
- "FACCH twice, please FIX! ");
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br,
+ "FACCH twice, please FIX!\n");
msgb_free(msg2);
} else
msg_tch = msg2;
@@ -282,8 +281,8 @@ inval_mode1:
/* check validity of message */
if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! (len=%d)\n",
- msgb_l2len(msg_facch));
+ LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
+ msgb_l2len(msg_facch), GSM_MACBLOCK_LEN);
/* free message */
msgb_free(msg_facch);
msg_facch = NULL;
@@ -298,18 +297,18 @@ inval_mode1:
#endif
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, "
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, "
"because we are not in speech mode\n");
goto free_bad_msg;
}
switch (tch_mode) {
case GSM48_CMODE_SPEECH_V1: /* FR / HR */
- if (chan != TRXC_TCHF) { /* HR */
+ if (br->chan != TRXC_TCHF) { /* HR */
len = 15;
if (msgb_l2len(msg_tch) >= 1
&& (msg_tch->l2h[0] & 0xf0) != 0x00) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
"Transmitting 'bad HR frame'\n");
goto free_bad_msg;
}
@@ -318,76 +317,37 @@ inval_mode1:
len = GSM_FR_BYTES;
if (msgb_l2len(msg_tch) >= 1
&& (msg_tch->l2h[0] >> 4) != 0xd) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
"Transmitting 'bad FR frame'\n");
goto free_bad_msg;
}
break;
case GSM48_CMODE_SPEECH_EFR: /* EFR */
- if (chan != TRXC_TCHF)
+ if (br->chan != TRXC_TCHF)
goto inval_mode2;
len = GSM_EFR_BYTES;
if (msgb_l2len(msg_tch) >= 1
&& (msg_tch->l2h[0] >> 4) != 0xc) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
+ LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
"Transmitting 'bad EFR frame'\n");
goto free_bad_msg;
}
break;
case GSM48_CMODE_SPEECH_AMR: /* AMR */
-#if 0
- len = amr_decompose_payload(msg_tch->l2h,
- msgb_l2len(msg_tch), &cmr_codec, &ft_codec,
- &bfi);
- cmr = -1;
- ft = -1;
- for (i = 0; i < chan_state->codecs; i++) {
- if (chan_state->codec[i] == cmr_codec)
- cmr = i;
- if (chan_state->codec[i] == ft_codec)
- ft = i;
- }
- if (cmr >= 0) { /* new request */
- chan_state->dl_cmr = cmr;
- /* disable AMR loop */
- trx_loop_amr_set(chan_state, 0);
- } else {
- /* enable AMR loop */
- trx_loop_amr_set(chan_state, 1);
- }
- if (ft < 0) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
- "Codec (FT = %d) of RTP frame not in list. ", ft_codec);
- goto free_bad_msg;
- }
- if (codec_mode_request && chan_state->dl_ft != ft) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
- "Codec (FT = %d) of RTP cannot be changed now, but in "
- "next frame\n", ft_codec);
- goto free_bad_msg;
- }
- chan_state->dl_ft = ft;
- if (bfi) {
- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
- "Transmitting 'bad AMR frame'\n");
- goto free_bad_msg;
- }
-#else
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "AMR not supported!\n");
- goto free_bad_msg;
-#endif
+ /* TODO: check length for consistency */
+ goto send_frame;
break;
default:
inval_mode2:
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
goto free_bad_msg;
}
if (len < 0) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send invalid AMR payload\n");
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n");
goto free_bad_msg;
}
if (msgb_l2len(msg_tch) != len) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send payload with "
+ LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with "
"invalid length! (expecing %d, received %d)\n", len, msgb_l2len(msg_tch));
free_bad_msg:
/* free message */
@@ -402,72 +362,56 @@ send_frame:
*_msg_facch = msg_facch;
}
-ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
- if (bid > 0)
- return NULL;
+ if (br->bid > 0)
+ return 0;
- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
- (((fn + 4) % 26) >> 2) & 1);
+ tx_tch_common(l1ts, br, &msg_tch, &msg_facch);
/* no message at all */
if (!msg_tch && !msg_facch) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
- goto send_burst;
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
+ return -ENODEV;
}
if (msg_facch) {
- tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
+ tx_to_virt_um(l1ts, br, msg_facch);
msgb_free(msg_tch);
- } else
- tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
-
-send_burst:
+ } else if (msg_tch)
+ tx_to_virt_um_voice_frame(l1ts, br, msg_tch);
- return NULL;
+ return 0;
}
-ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
+int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
//uint8_t tch_mode = chan_state->tch_mode;
/* send burst, if we already got a frame */
- if (bid > 0)
- return NULL;
+ if (br->bid > 0)
+ return 0;
/* get TCH and/or FACCH */
- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
- (((fn + 4) % 26) >> 2) & 1);
-
- /* check for FACCH alignment */
- if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
- "even frames, please fix RTS!\n");
- msgb_free(msg_facch);
- msg_facch = NULL;
- }
+ tx_tch_common(l1ts, br, &msg_tch, &msg_facch);
/* no message at all */
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
- goto send_burst;
+ LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
+ return -ENODEV;
}
if (msg_facch) {
- tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
+ tx_to_virt_um(l1ts, br, msg_facch);
msgb_free(msg_tch);
} else if (msg_tch)
- tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
+ tx_to_virt_um_voice_frame(l1ts, br, msg_tch);
-send_burst:
- return NULL;
+ return 0;
}
@@ -479,38 +423,33 @@ send_burst:
* directly into the L1SAP, bypassing the TDMA multiplex logic oriented
* towards receiving bursts */
-int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
return 0;
}
/*! \brief a single burst was received by the PHY, process it */
-int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
return 0;
}
-int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
return 0;
}
-int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
return 0;
}
-int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
- uint8_t bid, const struct trx_ul_burst_ind *bi)
+int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
return 0;
}
-void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
+void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate)
{
}
@@ -519,7 +458,6 @@ void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int ac
***********************************************************************/
#define RTS_ADVANCE 5 /* about 20ms */
-#define FRAME_DURATION_uS 4615
static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
{
@@ -532,13 +470,11 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
/* advance the frame number? */
llist_for_each_entry(trx, &bts->trx_list, list) {
- struct phy_instance *pinst = trx_phy_instance(trx);
- struct l1sched_trx *l1t = &pinst->u.virt.sched;
- int tn;
- uint16_t nbits;
+ struct trx_dl_burst_req br = { .fn = fn };
/* do for each of the 8 timeslots */
- for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
+ for (br.tn = 0; br.tn < ARRAY_SIZE(trx->ts); br.tn++) {
+ struct l1sched_ts *l1ts = trx->ts[br.tn].priv;
/* Generate RTS indication to higher layers */
/* This will basically do 2 things (check l1_if:bts_model_l1sap_down):
* 1) Get pending messages from layer 2 (from the lapdm queue)
@@ -546,13 +482,13 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
* --> Handle and process non-transparent RSL-Messages (activate channel, )
* --> Forward transparent RSL-DATA-Messages to the ms by appending them to
* the l1-dl-queue */
- _sched_rts(l1t, tn, (fn + RTS_ADVANCE) % GSM_HYPERFRAME);
+ _sched_rts(l1ts, GSM_TDMA_FN_SUM(fn, RTS_ADVANCE));
/* schedule transmit backend functions */
/* Process data in the l1-dlqueue and forward it
* to MS */
/* the returned bits are not used here, the routines called will directly forward their
* bits to the virt Um */
- _sched_dl_burst(l1t, tn, fn, &nbits);
+ _sched_dl_burst(l1ts, &br);
}
}
@@ -562,8 +498,9 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
static void vbts_fn_timer_cb(void *data)
{
struct gsm_bts *bts = data;
+ struct bts_virt_priv *bts_virt = (struct bts_virt_priv *)bts->model_priv;
struct timeval tv_now;
- struct timeval *tv_clock = &bts->vbts.tv_clock;
+ struct timeval *tv_clock = &bts_virt->tv_clock;
int32_t elapsed_us;
gettimeofday(&tv_now, NULL);
@@ -574,41 +511,44 @@ static void vbts_fn_timer_cb(void *data)
+ (tv_now.tv_usec - tv_clock->tv_usec);
/* not so good somehow a lot of time passed between two timer callbacks */
- if (elapsed_us > 2 *FRAME_DURATION_uS)
+ if (elapsed_us > 2 *GSM_TDMA_FN_DURATION_uS)
LOGP(DL1P, LOGL_NOTICE, "vbts_fn_timer_cb after %d us\n", elapsed_us);
/* schedule the current frame/s (fn = frame number)
* this loop will be called at least once, but can also be executed
* multiple times if more than one frame duration (4615us) passed till the last callback */
- while (elapsed_us > FRAME_DURATION_uS / 2) {
+ while (elapsed_us > GSM_TDMA_FN_DURATION_uS / 2) {
const struct timeval tv_frame = {
.tv_sec = 0,
- .tv_usec = FRAME_DURATION_uS,
+ .tv_usec = GSM_TDMA_FN_DURATION_uS,
};
timeradd(tv_clock, &tv_frame, tv_clock);
/* increment the frame number in the BTS model instance */
- bts->vbts.last_fn = (bts->vbts.last_fn + 1) % GSM_HYPERFRAME;
- vbts_sched_fn(bts, bts->vbts.last_fn);
- elapsed_us -= FRAME_DURATION_uS;
+ vbts_sched_fn(bts, GSM_TDMA_FN_INC(bts_virt->last_fn));
+ elapsed_us -= GSM_TDMA_FN_DURATION_uS;
}
/* re-schedule the timer */
/* timer is set to frame duration - elapsed time to guarantee that this cb method will be
* periodically executed every 4.615ms */
- osmo_timer_schedule(&bts->vbts.fn_timer, 0, FRAME_DURATION_uS - elapsed_us);
+ osmo_timer_schedule(&bts_virt->fn_timer, 0, GSM_TDMA_FN_DURATION_uS - elapsed_us);
}
int vbts_sched_start(struct gsm_bts *bts)
{
+ struct bts_virt_priv *bts_virt = (struct bts_virt_priv *)bts->model_priv;
LOGP(DL1P, LOGL_NOTICE, "starting VBTS scheduler\n");
- memset(&bts->vbts.fn_timer, 0, sizeof(bts->vbts.fn_timer));
- bts->vbts.fn_timer.cb = vbts_fn_timer_cb;
- bts->vbts.fn_timer.data = bts;
+ if (!bts_virt)
+ return -EINVAL;
+
+ memset(&bts_virt->fn_timer, 0, sizeof(bts_virt->fn_timer));
+ bts_virt->fn_timer.cb = vbts_fn_timer_cb;
+ bts_virt->fn_timer.data = bts;
- gettimeofday(&bts->vbts.tv_clock, NULL);
+ gettimeofday(&bts_virt->tv_clock, NULL);
/* trigger the first timer after 4615us (a frame duration) */
- osmo_timer_schedule(&bts->vbts.fn_timer, 0, FRAME_DURATION_uS);
+ osmo_timer_schedule(&bts_virt->fn_timer, 0, GSM_TDMA_FN_DURATION_uS);
return 0;
}
diff --git a/src/osmo-bts-virtual/virtual_um.c b/src/osmo-bts-virtual/virtual_um.c
index fd0940f0..711e75d3 100644
--- a/src/osmo-bts-virtual/virtual_um.c
+++ b/src/osmo-bts-virtual/virtual_um.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -27,45 +27,31 @@
#include <osmocom/core/talloc.h>
#include "osmo_mcast_sock.h"
#include "virtual_um.h"
+
#include <unistd.h>
+#include <errno.h>
/**
- * Virtual UM interface file descriptor callback.
- * Should be called by select.c when the fd is ready for reading.
+ * Virtual UM interface file descriptor read callback.
*/
-static int virt_um_fd_cb(struct osmo_fd *ofd, unsigned int what)
+static void virt_um_read_cb(int rc, struct msgb *msg, void *data)
{
- struct virt_um_inst *vui = ofd->data;
-
- if (what & BSC_FD_READ) {
- struct msgb *msg = msgb_alloc(VIRT_UM_MSGB_SIZE, "Virtual UM Rx");
- int rc;
+ struct virt_um_inst *vui = data;
+ msg->l1h = msg->data;
- /* read message from fd into message buffer */
- rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), msgb_tailroom(msg));
- if (rc > 0) {
- msgb_put(msg, rc);
- msg->l1h = msgb_data(msg);
- /* call the l1 callback function for a received msg */
- vui->recv_cb(vui, msg);
- } else if (rc == 0) {
- vui->recv_cb(vui, NULL);
- osmo_fd_close(ofd);
- } else
- perror("Read from multicast socket");
-
- }
-
- return 0;
+ /* call the l1 callback function for a received msg */
+ vui->recv_cb(vui, msg);
}
struct virt_um_inst *virt_um_init(void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port,
- char *rx_mcast_group, uint16_t rx_mcast_port,
+ char *rx_mcast_group, uint16_t rx_mcast_port, int ttl, const char *dev_name,
void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg))
{
struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst);
+ int rc;
+
vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, tx_mcast_port,
- rx_mcast_group, rx_mcast_port, 1, virt_um_fd_cb, vui);
+ rx_mcast_group, rx_mcast_port, 1, virt_um_read_cb, vui);
if (!vui->mcast_sock) {
perror("Unable to create VirtualUm multicast socket");
talloc_free(vui);
@@ -73,8 +59,37 @@ struct virt_um_inst *virt_um_init(void *ctx, char *tx_mcast_group, uint16_t tx_m
}
vui->recv_cb = recv_cb;
+ /* -1 means default, i.e. no TTL explicitly configured in VTY */
+ if (ttl >= 0) {
+ int txfd = osmo_iofd_get_fd(vui->mcast_sock->tx_iofd);
+ rc = osmo_sock_mcast_ttl_set(txfd, ttl);
+ if (rc < 0) {
+ perror("Cannot set TTL of Virtual Um transmit socket");
+ goto out_close;
+ }
+ }
+
+ if (dev_name) {
+ int txfd = osmo_iofd_get_fd(vui->mcast_sock->tx_iofd);
+ rc = osmo_sock_mcast_iface_set(txfd, dev_name);
+ if (rc < 0) {
+ perror("Cannot bind multicast tx to given device");
+ goto out_close;
+ }
+ int rxfd = osmo_iofd_get_fd(vui->mcast_sock->rx_iofd);
+ rc = osmo_sock_mcast_iface_set(rxfd, dev_name);
+ if (rc < 0) {
+ perror("Cannot bind multicast rx to given device");
+ goto out_close;
+ }
+ }
+
return vui;
+out_close:
+ mcast_bidir_sock_close(vui->mcast_sock);
+ talloc_free(vui);
+ return NULL;
}
void virt_um_destroy(struct virt_um_inst *vui)
@@ -90,11 +105,11 @@ int virt_um_write_msg(struct virt_um_inst *vui, struct msgb *msg)
{
int rc;
- rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg),
- msgb_length(msg));
- if (rc < 0)
- perror("Writing to multicast socket");
- msgb_free(msg);
+ rc = mcast_bidir_sock_tx_msg(vui->mcast_sock, msg);
+ if (rc < 0) {
+ msgb_free(msg);
+ rc = -errno;
+ }
return rc;
}
diff --git a/src/osmo-bts-virtual/virtual_um.h b/src/osmo-bts-virtual/virtual_um.h
index ac098dd4..87cf03a5 100644
--- a/src/osmo-bts-virtual/virtual_um.h
+++ b/src/osmo-bts-virtual/virtual_um.h
@@ -23,7 +23,7 @@ struct virt_um_inst {
struct virt_um_inst *virt_um_init(
void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port,
- char *rx_mcast_group, uint16_t rx_mcast_port,
+ char *rx_mcast_group, uint16_t rx_mcast_port, int ttl, const char *dev_name,
void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg));
void virt_um_destroy(struct virt_um_inst *vui);
diff --git a/src/osmo-bts-virtual/virtualbts_vty.c b/src/osmo-bts-virtual/virtualbts_vty.c
index 323222b4..3933bd27 100644
--- a/src/osmo-bts-virtual/virtualbts_vty.c
+++ b/src/osmo-bts-virtual/virtualbts_vty.c
@@ -50,25 +50,26 @@
SHOW_STR \
TRX_STR
-static struct gsm_bts *vty_bts;
-
-void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
+void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts)
{
}
-void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
+void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx)
{
}
-void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
{
}
-void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
{
if (plink->u.virt.mcast_dev)
vty_out(vty, " virtual-um net-device %s%s",
plink->u.virt.mcast_dev, VTY_NEWLINE);
+ if (plink->u.virt.ttl != -1)
+ vty_out(vty, " virtual-um ttl %d%s",
+ plink->u.virt.ttl, VTY_NEWLINE);
if (strcmp(plink->u.virt.ms_mcast_group, DEFAULT_BTS_MCAST_GROUP))
vty_out(vty, " virtual-um ms-multicast-group %s%s",
plink->u.virt.ms_mcast_group, VTY_NEWLINE);
@@ -171,15 +172,31 @@ DEFUN(cfg_phy_mcast_dev, cfg_phy_mcast_dev_cmd,
return CMD_SUCCESS;
}
-int bts_model_vty_init(struct gsm_bts *bts)
+DEFUN(cfg_phy_mcast_ttl, cfg_phy_mcast_ttl_cmd,
+ "virtual-um ttl <0-255>",
+ VUM_STR "Configure the TTL for transmitted multicast GSMTAP packets\n")
{
- vty_bts = bts;
+ 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;
+ }
+
+ plink->u.virt.ttl = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+int bts_model_vty_init(void *ctx)
+{
install_element(PHY_NODE, &cfg_phy_ms_mcast_group_cmd);
install_element(PHY_NODE, &cfg_phy_ms_mcast_port_cmd);
install_element(PHY_NODE, &cfg_phy_bts_mcast_group_cmd);
install_element(PHY_NODE, &cfg_phy_bts_mcast_port_cmd);
install_element(PHY_NODE, &cfg_phy_mcast_dev_cmd);
+ install_element(PHY_NODE, &cfg_phy_mcast_ttl_cmd);
return 0;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1eb28d6f..8d175be8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = paging cipher agch misc handover tx_power power meas
+SUBDIRS = paging cipher agch misc handover tx_power power meas ta_control amr csd
if ENABLE_SYSMOBTS
SUBDIRS += sysmobts
@@ -22,12 +22,38 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
echo ' [$(PACKAGE_URL)])'; \
} >'$(srcdir)/package.m4'
-EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
+EXTRA_DIST = \
+ testsuite.at \
+ $(srcdir)/package.m4 \
+ $(TESTSUITE) \
+ osmo-bts.vty \
+ $(NULL)
TESTSUITE = $(srcdir)/testsuite
DISTCLEANFILES = atconfig
+if ENABLE_EXT_TESTS
+python-tests:
+ $(MAKE) vty-test
+else
+python-tests:
+ echo "Not running python-based tests (determined at configure-time)"
+endif
+
+# Run a specific test with: 'make vty-test VTY_TEST=foo.vty'
+VTY_TEST ?= *.vty
+
+# To update the VTY script from current application behavior,
+# pass -u to vty_script_runner.py by doing:
+# make vty-test U=-u
+vty-test: $(top_builddir)/src/osmo-bts-virtual/osmo-bts-virtual
+ osmo_verify_transcript_vty.py -v \
+ -n OsmoBTS -p 4241 \
+ -r "$(top_builddir)/src/osmo-bts-virtual/osmo-bts-virtual --vty-test -c $(top_srcdir)/doc/examples/virtual/osmo-bts-virtual.cfg" \
+ $(U) $(srcdir)/$(VTY_TEST)
+
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
+ $(MAKE) $(AM_MAKEFLAGS) python-tests
installcheck-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \
diff --git a/tests/agch/Makefile.am b/tests/agch/Makefile.am
index 0c4fce45..d05fc626 100644
--- a/tests/agch/Makefile.am
+++ b/tests/agch/Makefile.am
@@ -1,7 +1,26 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS)
-noinst_PROGRAMS = agch_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = agch_test
EXTRA_DIST = agch_test.ok
agch_test_SOURCES = agch_test.c $(srcdir)/../stubs.c
diff --git a/tests/agch/agch_test.c b/tests/agch/agch_test.c
index e6c56d97..07cf1d90 100644
--- a/tests/agch/agch_test.c
+++ b/tests/agch/agch_test.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -23,6 +23,7 @@
#include <osmocom/core/application.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
@@ -124,13 +125,13 @@ static void test_agch_queue(void)
for (round = 1; round <= num_rounds; round++) {
for (idx = 0; idx < num_ima_per_round; idx++) {
- msg = msgb_alloc(GSM_MACBLOCK_LEN, __FUNCTION__);
+ msg = msgb_alloc(GSM_MACBLOCK_LEN, __func__);
put_imm_ass(msg, ++count);
bts_agch_enqueue(bts, msg);
imm_ass_count++;
}
for (idx = 0; idx < num_rej_per_round; idx++) {
- msg = msgb_alloc(GSM_MACBLOCK_LEN, __FUNCTION__);
+ msg = msgb_alloc(GSM_MACBLOCK_LEN, __func__);
put_imm_ass_rej(msg, ++count, 10);
bts_agch_enqueue(bts, msg);
imm_ass_rej_count++;
@@ -158,7 +159,7 @@ static void test_agch_queue(void)
if (is_agch)
multiframes++;
- rc = bts_ccch_copy_msg(bts, out_buf, &g_time, is_agch);
+ rc = bts_ccch_copy_msg(bts, out_buf, &g_time, (is_agch) ? CCCH_MSGT_AGCH : CCCH_MSGT_PCH);
ima = (struct gsm48_imm_ass *)out_buf;
switch (ima->msg_type) {
case GSM48_MT_RR_IMM_ASS:
@@ -225,7 +226,8 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (bts_init(bts) < 0) {
fprintf(stderr, "unable to open bts\n");
exit(1);
diff --git a/tests/amr/Makefile.am b/tests/amr/Makefile.am
new file mode 100644
index 00000000..a857d179
--- /dev/null
+++ b/tests/amr/Makefile.am
@@ -0,0 +1,26 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = amr_test
+EXTRA_DIST = amr_test.ok amr_test.err
+
+amr_test_SOURCES = amr_test.c
+amr_test_LDADD = $(top_builddir)/src/common/libbts.a \
+ $(LDADD)
diff --git a/tests/amr/amr_test.c b/tests/amr/amr_test.c
new file mode 100644
index 00000000..07e8bf2c
--- /dev/null
+++ b/tests/amr/amr_test.c
@@ -0,0 +1,71 @@
+/* (C) 2021 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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 Affero 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 <osmo-bts/logging.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/amr.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+static void test_amr_parse_mr_conf(void)
+{
+ uint8_t mrc_enc[] = { 0x20, 0xa5, 0x0d, 0x46, 0x52, 0x54 };
+ struct amr_multirate_conf mrc = { 0 };
+ unsigned int i;
+
+ printf("amr_parse_mr_conf() <- %s\n", osmo_hexdump(&mrc_enc[0], sizeof(mrc_enc)));
+ OSMO_ASSERT(amr_parse_mr_conf(&mrc, &mrc_enc[0], sizeof(mrc_enc)) > 0);
+ printf("amr_parse_mr_conf() -> num_modes=%u\n", mrc.num_modes);
+ for (i = 0; i < mrc.num_modes; i++) {
+ printf(" Mode[%u] = %u/%u/%u\n",
+ i, mrc.mode[i].mode,
+ mrc.mode[i].threshold,
+ mrc.mode[i].hysteresis);
+ }
+
+ mrc_enc[1] = 0xff; /* all codec modes active */
+ printf("amr_parse_mr_conf() <- %s\n", osmo_hexdump(&mrc_enc[0], sizeof(mrc_enc)));
+ OSMO_ASSERT(amr_parse_mr_conf(&mrc, &mrc_enc[0], sizeof(mrc_enc)) == -EINVAL);
+
+ mrc_enc[0] = 0xff; /* unknown version */
+ printf("amr_parse_mr_conf() <- %s\n", osmo_hexdump(&mrc_enc[0], sizeof(mrc_enc)));
+ OSMO_ASSERT(amr_parse_mr_conf(&mrc, &mrc_enc[0], sizeof(mrc_enc)) == -EINVAL);
+
+ printf("amr_parse_mr_conf() <- %s\n", osmo_hexdump(&mrc_enc[0], 1)); /* short read */
+ OSMO_ASSERT(amr_parse_mr_conf(&mrc, &mrc_enc[0], 1) == -EINVAL);
+}
+
+int main(int argc, char **argv)
+{
+ osmo_init_logging2(NULL, &bts_log_info);
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 1);
+ log_set_print_level(osmo_stderr_target, 1);
+ log_set_use_color(osmo_stderr_target, 0);
+
+ test_amr_parse_mr_conf();
+ return EXIT_SUCCESS;
+}
diff --git a/tests/amr/amr_test.err b/tests/amr/amr_test.err
new file mode 100644
index 00000000..0b7bdaf4
--- /dev/null
+++ b/tests/amr/amr_test.err
@@ -0,0 +1,3 @@
+DRSL ERROR AMR Multirate with 8 modes len=6 not possible
+DRSL ERROR AMR Multirate Version 7 unknown
+DRSL ERROR AMR Multirate IE is too short (1)
diff --git a/tests/amr/amr_test.ok b/tests/amr/amr_test.ok
new file mode 100644
index 00000000..921e8b9e
--- /dev/null
+++ b/tests/amr/amr_test.ok
@@ -0,0 +1,9 @@
+amr_parse_mr_conf() <- 20 a5 0d 46 52 54
+amr_parse_mr_conf() -> num_modes=4
+ Mode[0] = 0/13/4
+ Mode[1] = 2/25/4
+ Mode[2] = 5/37/4
+ Mode[3] = 7/0/0
+amr_parse_mr_conf() <- 20 ff 0d 46 52 54
+amr_parse_mr_conf() <- ff ff 0d 46 52 54
+amr_parse_mr_conf() <- ff
diff --git a/tests/cipher/Makefile.am b/tests/cipher/Makefile.am
index 3c23718e..c33b05ef 100644
--- a/tests/cipher/Makefile.am
+++ b/tests/cipher/Makefile.am
@@ -1,7 +1,26 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS)
-noinst_PROGRAMS = cipher_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = cipher_test
EXTRA_DIST = cipher_test.ok
cipher_test_SOURCES = cipher_test.c $(srcdir)/../stubs.c
diff --git a/tests/cipher/cipher_test.c b/tests/cipher/cipher_test.c
index 9d78a880..8ac4018c 100644
--- a/tests/cipher/cipher_test.c
+++ b/tests/cipher/cipher_test.c
@@ -10,7 +10,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -18,6 +18,7 @@
*/
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/paging.h>
#include <osmo-bts/gsm_data.h>
@@ -50,14 +51,14 @@ static void test_cipher_parsing(void)
ASSERT_TRUE(bts_supports_cipher(bts, i) == 0);
}
- /* checking default A5/1 to A5/3 support */
- bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
+ /* checking default A5/1 to A5/4 support */
+ bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3) | CIPHER_A5(4);
ASSERT_TRUE(bts_supports_cipher(bts, 0x0) == -ENOTSUP);
ASSERT_TRUE(bts_supports_cipher(bts, 0x1) == 1); /* A5/0 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x2) == 1); /* A5/1 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x3) == 1); /* A5/2 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x4) == 1); /* A5/3 */
- ASSERT_TRUE(bts_supports_cipher(bts, 0x5) == 0); /* A5/4 */
+ ASSERT_TRUE(bts_supports_cipher(bts, 0x5) == 1); /* A5/4 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x6) == 0); /* A5/5 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x7) == 0); /* A5/6 */
ASSERT_TRUE(bts_supports_cipher(bts, 0x8) == 0); /* A5/7 */
@@ -71,7 +72,8 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (bts_init(bts) < 0) {
fprintf(stderr, "unable to open bts\n");
exit(1);
diff --git a/tests/csd/Makefile.am b/tests/csd/Makefile.am
new file mode 100644
index 00000000..2041dd7d
--- /dev/null
+++ b/tests/csd/Makefile.am
@@ -0,0 +1,25 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = csd_test
+EXTRA_DIST = csd_test.err
+
+csd_test_SOURCES = csd_test.c
+csd_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c
new file mode 100644
index 00000000..13a64199
--- /dev/null
+++ b/tests/csd/csd_test.c
@@ -0,0 +1,157 @@
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+ *
+ * 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 Affero 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 <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/isdn/v110.h>
+
+#include <osmo-bts/csd_v110.h>
+#include <osmo-bts/lchan.h>
+
+#define BBUF_MAX 290
+
+struct test_case {
+ const char *name;
+ enum gsm_chan_t lchan_type;
+ enum gsm48_chan_mode tch_mode;
+ enum lchan_csd_mode csd_mode;
+};
+
+static const struct test_case tests[] = {
+ {
+ .name = "TCH/F14.4",
+ .lchan_type = GSM_LCHAN_TCH_F,
+ .tch_mode = GSM48_CMODE_DATA_14k5,
+ .csd_mode = LCHAN_CSD_M_T_14400,
+ },
+ {
+ .name = "TCH/F9.6",
+ .lchan_type = GSM_LCHAN_TCH_F,
+ .tch_mode = GSM48_CMODE_DATA_12k0,
+ .csd_mode = LCHAN_CSD_M_T_9600,
+ },
+ {
+ .name = "TCH/F4.8",
+ .lchan_type = GSM_LCHAN_TCH_F,
+ .tch_mode = GSM48_CMODE_DATA_6k0,
+ .csd_mode = LCHAN_CSD_M_T_4800,
+ },
+ {
+ .name = "TCH/H4.8",
+ .lchan_type = GSM_LCHAN_TCH_H,
+ .tch_mode = GSM48_CMODE_DATA_6k0,
+ .csd_mode = LCHAN_CSD_M_T_4800,
+ },
+ {
+ .name = "TCH/F2.4",
+ .lchan_type = GSM_LCHAN_TCH_F,
+ .tch_mode = GSM48_CMODE_DATA_3k6,
+ .csd_mode = LCHAN_CSD_M_T_2400,
+ },
+ {
+ .name = "TCH/H2.4",
+ .lchan_type = GSM_LCHAN_TCH_H,
+ .tch_mode = GSM48_CMODE_DATA_3k6,
+ .csd_mode = LCHAN_CSD_M_T_600,
+ },
+};
+
+static void exec_test_case(const struct test_case *tc)
+{
+ const struct csd_v110_frame_desc *desc;
+ uint8_t rtp[RFC4040_RTP_PLEN] = { 0 };
+ ubit_t data_enc[BBUF_MAX];
+ ubit_t data_dec[BBUF_MAX];
+ int rc;
+
+ /* obtain a V.110 frame description for the given channel type/rate */
+ OSMO_ASSERT(tc->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc));
+ if (tc->lchan_type == GSM_LCHAN_TCH_F)
+ desc = &csd_v110_lchan_desc[tc->tch_mode].fr;
+ else
+ desc = &csd_v110_lchan_desc[tc->tch_mode].hr;
+
+ /* total number of bits carried by a radio interface block */
+ const unsigned int bit_num = desc->num_bits * desc->num_blocks;
+ if (bit_num == 0) {
+ fprintf(stderr, "[i] Skipping '%s' (not implemented)\n", tc->name);
+ return;
+ }
+
+ fprintf(stderr, "[i] Testing '%s' (bitnum=%u)\n", tc->name, bit_num);
+
+ struct gsm_lchan lchan = {
+ .type = tc->lchan_type,
+ .tch_mode = tc->tch_mode,
+ .csd_mode = tc->csd_mode,
+ };
+
+ /* populate the data_enc[] buffer with some bits */
+ OSMO_ASSERT(bit_num <= BBUF_MAX);
+ for (unsigned int i = 0; i < bit_num; i++)
+ data_enc[i] = i & 0x01;
+
+ /* encode an RTP frame and print it */
+ rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], bit_num);
+ fprintf(stderr, "[i] csd_v110_rtp_encode() returns %d\n", rc);
+ if (rc != RFC4040_RTP_PLEN)
+ return;
+ /* print the encoded RTP frame (16 bytes per row) */
+ for (unsigned int i = 0; i < sizeof(rtp) / 16; i++)
+ fprintf(stderr, " %s\n", osmo_hexdump(&rtp[i * 16], 16));
+
+ /* decode the encoded RTP frame */
+ rc = csd_v110_rtp_decode(&lchan, &data_dec[0], &rtp[0], sizeof(rtp));
+ fprintf(stderr, "[i] csd_v110_rtp_decode() returns %d\n", rc);
+ if (rc != bit_num)
+ return;
+ /* compare data_dec[] vs data_enc[] */
+ for (unsigned int i = 0; i < bit_num; i++) {
+ if (data_dec[i] == data_enc[i])
+ continue;
+ fprintf(stderr, "[!] Data mismatch @ %03u: D%u vs E%u\n",
+ i, data_dec[i], data_enc[i]);
+ }
+
+ fprintf(stderr, "[i] Testing '%s' (IDLE)\n", tc->name);
+
+ /* encode an idle RTP frame and print it */
+ rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], 0);
+ fprintf(stderr, "[i] csd_v110_rtp_encode() returns %d\n", rc);
+ if (rc != RFC4040_RTP_PLEN)
+ return;
+ /* print the encoded RTP frame (16 bytes per row) */
+ for (unsigned int i = 0; i < sizeof(rtp) / 16; i++)
+ fprintf(stderr, " %s\n", osmo_hexdump(&rtp[i * 16], 16));
+}
+
+int main(int argc, char **argv)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(tests); i++)
+ exec_test_case(&tests[i]);
+
+ return 0;
+}
diff --git a/tests/csd/csd_test.err b/tests/csd/csd_test.err
new file mode 100644
index 00000000..b8623247
--- /dev/null
+++ b/tests/csd/csd_test.err
@@ -0,0 +1,126 @@
+[i] Skipping 'TCH/F14.4' (not implemented)
+[i] Testing 'TCH/F9.6' (bitnum=240)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf
+ ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f
+ bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf
+ ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f
+ bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f
+ 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf
+ ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f
+ bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf
+ ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f
+ bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f
+[i] csd_v110_rtp_decode() returns 240
+[i] Testing 'TCH/F9.6' (IDLE)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[i] Testing 'TCH/F4.8' (bitnum=120)
+[i] csd_v110_rtp_encode() returns 160
+ 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f
+ ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f
+ ff ff 7f ff 7f ff 7f ff ff 7f ff ff 7f ff 7f ff
+ ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff
+ ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff
+ 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f
+ ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f
+ ff ff 7f ff 7f ff 7f ff ff 7f ff ff 7f ff 7f ff
+ ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff
+ ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff
+[i] csd_v110_rtp_decode() returns 120
+[i] Testing 'TCH/F4.8' (IDLE)
+[i] csd_v110_rtp_encode() returns 160
+ 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[i] Testing 'TCH/H4.8' (bitnum=240)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf
+ ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f
+ bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf
+ ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f
+ bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f
+ 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf
+ ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f
+ bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf
+ ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f
+ bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f
+[i] csd_v110_rtp_decode() returns 240
+[i] Testing 'TCH/H4.8' (IDLE)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[i] Testing 'TCH/F2.4' (bitnum=72)
+[i] csd_v110_rtp_encode() returns 160
+ 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff ff ff 7f 7f ff 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+ 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff ff ff 7f 7f ff 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+ ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff
+[i] csd_v110_rtp_decode() returns 72
+[i] Testing 'TCH/F2.4' (IDLE)
+[i] csd_v110_rtp_encode() returns 160
+ 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[i] Testing 'TCH/H2.4' (bitnum=144)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f
+ bf 7f bf 7f ff 3f 7f 7f bf 7f bf 7f bf 7f bf 7f
+ bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f
+ bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f ff 3f 7f 7f
+ bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f
+ 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f
+ bf 7f bf 7f ff 3f 7f 7f bf 7f bf 7f bf 7f bf 7f
+ bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f
+ bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f ff 3f 7f 7f
+ bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f
+[i] csd_v110_rtp_decode() returns 144
+[i] Testing 'TCH/H2.4' (IDLE)
+[i] csd_v110_rtp_encode() returns 160
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
diff --git a/tests/handover/Makefile.am b/tests/handover/Makefile.am
index 966ea469..789696e3 100644
--- a/tests/handover/Makefile.am
+++ b/tests/handover/Makefile.am
@@ -1,8 +1,25 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS)
-noinst_PROGRAMS = handover_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = handover_test
EXTRA_DIST = handover_test.ok
-handover_test_SOURCES = handover_test.c
+handover_test_SOURCES = handover_test.c $(srcdir)/../stubs.c
handover_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c
index c9799af7..f1235f53 100644
--- a/tests/handover/handover_test.c
+++ b/tests/handover/handover_test.c
@@ -28,6 +28,7 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/vty.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/pcu_if.h>
@@ -58,6 +59,7 @@ int main(int argc, char **argv)
{
void *tall_bts_ctx;
struct e1inp_line *line;
+ struct e1inp_ts *sign_ts;
struct gsm_lchan *lchan;
struct osmo_phsap_prim nl1sap;
struct msgb *msg;
@@ -70,7 +72,12 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
osmo_stderr_target->categories[DHO].loglevel = LOGL_DEBUG;
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm) {
+ fprintf(stderr, "Failed to create BTS Site Manager structure\n");
+ exit(1);
+ }
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (!bts) {
fprintf(stderr, "Failed to create BTS structure\n");
exit(1);
@@ -85,35 +92,31 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to alloc TRX structure\n");
exit(1);
}
- if (bts_trx_init(trx) < 0) {
- fprintf(stderr, "unable to init TRX\n");
- exit(1);
- }
libosmo_abis_init(NULL);
line = e1inp_line_create(0, "ipa");
OSMO_ASSERT(line);
-
- e1inp_ts_config_sign(&line->ts[E1INP_SIGN_RSL-1], line);
- trx->rsl_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_RSL-1], E1INP_SIGN_RSL, NULL, 0, 0);
- OSMO_ASSERT(trx->rsl_link);
- trx->rsl_link->trx = trx;
+ sign_ts = e1inp_line_ipa_rsl_ts(line, 0);
+ e1inp_ts_config_sign(sign_ts, line);
+ trx->bb_transc.rsl.link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, NULL, 0, 0);
+ OSMO_ASSERT(trx->bb_transc.rsl.link);
+ trx->bb_transc.rsl.link->trx = trx;
fprintf(stderr, "test 1: without timeout\n");
/* create two lchans for handover */
lchan = &trx->ts[1].lchan[0];
lchan->type = GSM_LCHAN_SDCCH;
- l1sap_chan_act(lchan->ts->trx, 0x09, NULL);
+ l1sap_chan_act(lchan->ts->trx, 0x09);
lchan = &trx->ts[2].lchan[0];
lchan->type = GSM_LCHAN_TCH_F;
lchan->ho.active = HANDOVER_ENABLED;
lchan->ho.ref = 23;
- l1sap_chan_act(lchan->ts->trx, 0x0a, NULL);
- OSMO_ASSERT(msgb_dequeue(&trx->rsl_link->tx_list));
- OSMO_ASSERT(msgb_dequeue(&trx->rsl_link->tx_list));
- OSMO_ASSERT(!msgb_dequeue(&trx->rsl_link->tx_list));
+ l1sap_chan_act(lchan->ts->trx, 0x0a);
+ OSMO_ASSERT(msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
+ OSMO_ASSERT(msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
+ OSMO_ASSERT(!msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
/* send access burst with wrong ref */
memset(&nl1sap, 0, sizeof(nl1sap));
@@ -126,7 +129,7 @@ int main(int argc, char **argv)
/* expect no action */
OSMO_ASSERT(modify_count == 0);
- OSMO_ASSERT(!msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(!msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
/* send access burst with correct ref */
nl1sap.u.rach_ind.ra = 23;
@@ -137,10 +140,10 @@ int main(int argc, char **argv)
expect_phys_info(&trx->ts[2].lchan[0].lapdm_ch.lapdm_dcch);
/* expect exactly one HO.DET */
- OSMO_ASSERT(msg = msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(msg = msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
rslh = msgb_l2(msg);
OSMO_ASSERT(rslh->c.msg_type == RSL_MT_HANDO_DET);
- OSMO_ASSERT(!msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(!msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
/* expect T3105 running */
OSMO_ASSERT(osmo_timer_pending(&trx->ts[2].lchan[0].ho.t3105))
@@ -168,10 +171,10 @@ int main(int argc, char **argv)
expect_phys_info(&trx->ts[2].lchan[0].lapdm_ch.lapdm_dcch);
/* expect exactly one HO.DET */
- OSMO_ASSERT(msg = msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(msg = msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
rslh = msgb_l2(msg);
OSMO_ASSERT(rslh->c.msg_type == RSL_MT_HANDO_DET);
- OSMO_ASSERT(!msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(!msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
for (i = 0; i < bts->ny1 - 1; i++) {
/* expect T3105 running */
@@ -193,10 +196,10 @@ int main(int argc, char **argv)
OSMO_ASSERT(!osmo_timer_pending(&trx->ts[2].lchan[0].ho.t3105))
/* expect exactly one CONN.FAIL */
- OSMO_ASSERT(msg = msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(msg = msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
rslh = msgb_l2(msg);
OSMO_ASSERT(rslh->c.msg_type == RSL_MT_CONN_FAIL);
- OSMO_ASSERT(!msgb_dequeue(&trx->rsl_link->tx_list));
+ OSMO_ASSERT(!msgb_dequeue(&trx->bb_transc.rsl.link->tx_list));
#if 0
while (!quit) {
@@ -268,18 +271,3 @@ done:
msgb_free(msg);
return rc;
}
-
-int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr, void *obj) { return 0; }
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg, struct tlv_parsed *new_attr, int obj_kind, void *obj) { return 0; }
-int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj) { return 0; }
-int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state) { return 0; }
-int bts_model_init(struct gsm_bts *bts) { return 0; }
-int bts_model_trx_init(struct gsm_bts_trx *trx) { return 0; }
-int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) { return 0; }
-int bts_model_trx_close(struct gsm_bts_trx *trx) { return 0; }
-void trx_get_hlayer1(void) {}
-int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) { return 0; }
-int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts) { return 0; }
-void bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan) { return; }
-int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { return 0; }
-int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { return 0; }
diff --git a/tests/meas/Makefile.am b/tests/meas/Makefile.am
index d8fa1182..cb014f26 100644
--- a/tests/meas/Makefile.am
+++ b/tests/meas/Makefile.am
@@ -1,9 +1,26 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS)
-noinst_PROGRAMS = meas_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = meas_test
noinst_HEADERS = sysmobts_fr_samples.h meas_testcases.h
-EXTRA_DIST = meas_test.ok
+EXTRA_DIST = meas_test.ok meas_test.err
-meas_test_SOURCES = meas_test.c
+meas_test_SOURCES = meas_test.c $(srcdir)/../stubs.c
meas_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
diff --git a/tests/meas/meas_test.c b/tests/meas/meas_test.c
index b2bf80e2..6936ed0e 100644
--- a/tests/meas/meas_test.c
+++ b/tests/meas/meas_test.c
@@ -8,6 +8,7 @@
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/measurement.h>
#include <osmo-bts/rsl.h>
@@ -84,11 +85,12 @@ static void test_meas_compute(const struct meas_testcase *mtc)
lchan = &trx->ts[mtc->ts].lchan[0];
lchan->ts->pchan = mtc->pchan;
+ lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
reset_lchan_meas(lchan);
/* feed uplink measurements into the code */
for (i = 0; i < mtc->ulm_count; i++) {
- lchan_new_ul_meas(lchan, (struct bts_ul_meas *) &mtc->ulm[i], fn);
+ lchan_new_ul_meas(lchan, &mtc->ulm[i], fn);
fn += 1;
}
@@ -306,7 +308,7 @@ static void test_is_meas_complete(void)
* received. The process must still go on when measurement indications (blocks)
* are lost or otherwise spaced out. Even the complete absence of the
* measurement indications from the SACCH which are used to detect the interval
- * end must not keep the interval from beeing processed. */
+ * end must not keep the interval from being processed. */
void test_lchan_meas_process_measurement(bool no_sacch, bool dropouts)
{
struct gsm_lchan *lchan = &trx->ts[2].lchan[0];
@@ -328,7 +330,7 @@ void test_lchan_meas_process_measurement(bool no_sacch, bool dropouts)
ulm.ber10k = 0;
ulm.ta_offs_256bits = 256;
- ulm.c_i = 0;
+ ulm.ci_cb = 0;
ulm.is_sub = 0;
ulm.inv_rssi = 90;
@@ -372,73 +374,27 @@ void test_lchan_meas_process_measurement(bool no_sacch, bool dropouts)
}
}
-static bool test_ts45008_83_is_sub_is_sacch(uint32_t fn)
-{
- if (fn % 104 == 12)
- return true;
- if (fn % 104 == 25)
- return true;
- if (fn % 104 == 38)
- return true;
- if (fn % 104 == 51)
- return true;
- if (fn % 104 == 64)
- return true;
- if (fn % 104 == 77)
- return true;
- if (fn % 104 == 90)
- return true;
- if (fn % 104 == 103)
- return true;
-
- return false;
-}
-
-static bool test_ts45008_83_is_sub_is_sub(uint32_t fn, uint8_t ss)
+static bool test_ts45008_83_is_sub_is_sub(const struct gsm_lchan *lchan, uint32_t fn)
{
fn = fn % 104;
- if (fn >= 52 && fn <= 59)
- return true;
-
- if (ss == 0) {
- if (fn == 0)
- return true;
- if (fn == 2)
- return true;
- if (fn == 4)
- return true;
- if (fn == 6)
- return true;
- if (fn == 52)
- return true;
- if (fn == 54)
- return true;
- if (fn == 56)
- return true;
- if (fn == 58)
- return true;
- } else if (ss == 1) {
- if (fn == 14)
+ switch (lchan->type) {
+ case GSM_LCHAN_TCH_F:
+ /* block {52, 53, 54, 55, 56, 57, 58, 59} */
+ return fn == 52;
+ case GSM_LCHAN_TCH_H:
+ if (fn == 0) /* H0 block { 0, 2, 4, 6} */
return true;
- if (fn == 16)
+ if (fn == 52) /* H0 block {52, 54, 56, 58} */
return true;
- if (fn == 18)
+ if (fn == 14) /* H1 block {14, 16, 18, 20} */
return true;
- if (fn == 20)
+ if (fn == 66) /* H1 block {66, 68, 70, 72} */
return true;
- if (fn == 66)
- return true;
- if (fn == 68)
- return true;
- if (fn == 70)
- return true;
- if (fn == 72)
- return true;
- } else
- OSMO_ASSERT(false);
-
- return false;
+ return false;
+ default:
+ return false;
+ }
}
static void test_ts45008_83_is_sub_single(uint8_t ts, uint8_t ss, bool fr)
@@ -463,29 +419,17 @@ static void test_ts45008_83_is_sub_single(uint8_t ts, uint8_t ss, bool fr)
lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
}
- printf(" TS=%u ", ts);
- printf("SS=%u", ss);
+ printf(" TS=%u SS=%u\n", ts, ss);
/* Walk trough the first 100 intervals and check for unexpected
* results (false positive and false negative) */
for (i = 0; i < 104 * 100; i++) {
- rc = ts45008_83_is_sub(lchan, i, false);
- if (rc) {
- if (!test_ts45008_83_is_sub_is_sacch(i)
- && !test_ts45008_83_is_sub_is_sub(i, ss)) {
- printf("==> Unexpected SUB frame at fn=%u", i);
- OSMO_ASSERT(false);
- }
- } else {
- if (test_ts45008_83_is_sub_is_sacch(i)
- && test_ts45008_83_is_sub_is_sub(i, ss)) {
- printf("==> Unexpected non-SUB frame at fn=%u",
- i);
- OSMO_ASSERT(false);
- }
+ rc = ts45008_83_is_sub(lchan, i);
+ if (rc != test_ts45008_83_is_sub_is_sub(lchan, i)) {
+ printf(" ==> ts45008_83_is_sub(fn=%u) yields %s, expected %s\n",
+ i, rc ? "true" : "false", !rc ? "true" : "false");
}
}
- printf("\n");
}
static void test_ts45008_83_is_sub(void)
@@ -512,9 +456,20 @@ int main(int argc, char **argv)
msgb_talloc_ctx_init(tall_bts_ctx, 0);
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
- osmo_stderr_target->categories[DMEAS].loglevel = LOGL_DEBUG;
-
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ log_set_log_level(osmo_stderr_target, LOGL_DEBUG);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_level(osmo_stderr_target, 1);
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_parse_category_mask(osmo_stderr_target, "DMEAS,1:");
+
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm) {
+ fprintf(stderr, "Failed to create BTS Site Manager structure\n");
+ exit(1);
+ }
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (!bts) {
fprintf(stderr, "Failed to create BTS structure\n");
exit(1);
@@ -529,10 +484,6 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to alloc TRX structure\n");
exit(1);
}
- if (bts_trx_init(trx) < 0) {
- fprintf(stderr, "unable to init TRX\n");
- exit(1);
- }
printf("\n");
printf("***********************\n");
@@ -588,88 +539,3 @@ int main(int argc, char **argv)
return 0;
}
-
-/* Stubs */
-void bts_model_abis_close(struct gsm_bts *bts)
-{
-}
-
-int bts_model_oml_estab(struct gsm_bts *bts)
-{
- return 0;
-}
-
-int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
-{
- return 0;
-}
-
-int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr,
- void *obj)
-{
- return 0;
-}
-
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg, struct tlv_parsed *new_attr, int obj_kind, void *obj)
-{
- return 0;
-}
-
-int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)
-{
- return 0;
-}
-
-int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state)
-{
- return 0;
-}
-
-int bts_model_init(struct gsm_bts *bts)
-{
- return 0;
-}
-
-int bts_model_trx_init(struct gsm_bts_trx *trx)
-{
- return 0;
-}
-
-int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
-{
- return 0;
-}
-
-int bts_model_trx_close(struct gsm_bts_trx *trx)
-{
- return 0;
-}
-
-void trx_get_hlayer1(void)
-{
-}
-
-int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
-{
- return 0;
-}
-
-int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
-{
- return 0;
-}
-
-void bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan)
-{
- return;
-}
-
-int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
-{
- return 0;
-}
-
-int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan)
-{
- return 0;
-}
diff --git a/tests/meas/meas_test.err b/tests/meas/meas_test.err
new file mode 100644
index 00000000..f5176f11
--- /dev/null
+++ b/tests/meas/meas_test.err
@@ -0,0 +1,8241 @@
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010958/08/12/44/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011062/08/12/46/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011166/08/12/48/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011270/08/12/50/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011374/08/12/01/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011478/08/12/03/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011491/08/25/16/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011582/08/12/05/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011595/08/25/18/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011686/08/12/07/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011699/08/25/20/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011790/08/12/09/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011803/08/25/22/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011894/08/12/11/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011907/08/25/24/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011998/09/12/13/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012011/09/25/26/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012102/09/12/15/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012115/09/25/28/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012206/09/12/17/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012219/09/25/30/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012310/09/12/19/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012323/09/25/32/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012414/09/12/21/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012427/09/25/34/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012518/09/12/23/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012531/09/25/36/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 012622/09/12/25/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012635/09/25/38/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005888/04/12/23/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005992/04/12/25/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006096/04/12/27/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006200/04/12/29/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006213/04/25/42/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006304/04/12/31/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006317/04/25/44/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006408/04/12/33/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006421/04/25/46/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006512/04/12/35/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006525/04/25/48/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006616/04/12/37/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006629/04/25/50/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006720/05/12/39/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006733/05/25/01/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006824/05/12/41/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006837/05/25/03/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006928/05/12/43/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006941/05/25/05/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007032/05/12/45/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007045/05/25/07/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007136/05/12/47/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007149/05/25/09/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007240/05/12/49/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007253/05/25/11/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007344/05/12/00/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007357/05/25/13/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007448/05/12/02/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007461/05/25/15/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007552/05/12/04/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007565/05/25/17/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007656/05/12/06/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007669/05/25/19/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007773/05/25/21/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007877/05/25/23/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007981/06/25/25/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008085/06/25/27/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008592/06/12/24/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008605/06/25/37/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008696/06/12/26/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008709/06/25/39/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008800/06/12/28/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008813/06/25/41/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008904/06/12/30/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008917/06/25/43/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009008/06/12/32/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009021/06/25/45/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009112/06/12/34/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009125/06/25/47/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009216/06/12/36/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009229/06/25/49/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009320/07/12/38/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009333/07/25/00/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009424/07/12/40/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009437/07/25/02/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009528/07/12/42/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009541/07/25/04/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009632/07/12/44/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009645/07/25/06/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008618/06/12/50/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008722/06/12/01/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008826/06/12/03/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008930/06/12/05/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008943/06/25/18/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009034/06/12/07/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009047/06/25/20/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009138/06/12/09/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009151/06/25/22/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009242/06/12/11/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009255/06/25/24/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009346/07/12/13/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009359/07/25/26/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009450/07/12/15/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009463/07/25/28/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009554/07/12/17/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009567/07/25/30/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009658/07/12/19/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009671/07/25/32/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009762/07/12/21/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009775/07/25/34/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009866/07/12/23/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009879/07/25/36/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009970/07/12/25/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009983/07/25/38/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010074/07/12/27/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010087/07/25/40/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010178/07/12/29/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010191/07/25/42/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010282/07/12/31/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010295/07/25/44/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010386/07/12/33/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010399/07/25/46/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010490/07/12/35/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010503/07/25/48/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010594/07/12/37/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010607/07/25/50/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010698/08/12/39/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010711/08/25/01/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010802/08/12/41/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010815/08/25/03/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010906/08/12/43/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010919/08/25/05/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011010/08/12/45/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011023/08/25/07/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011114/08/12/47/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011127/08/25/09/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011218/08/12/49/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011231/08/25/11/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011322/08/12/00/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011335/08/25/13/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011426/08/12/02/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011439/08/25/15/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011530/08/12/04/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011543/08/25/17/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011634/08/12/06/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011647/08/25/19/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011738/08/12/08/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011751/08/25/21/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011842/08/12/10/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011855/08/25/23/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011946/09/12/12/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011959/09/25/25/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 012050/09/12/14/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012063/09/25/27/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 012154/09/12/16/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012167/09/25/29/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 24 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(96.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008982/06/12/06/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009086/06/12/08/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009190/06/12/10/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009294/07/12/12/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009398/07/12/14/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009411/07/25/27/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009502/07/12/16/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009515/07/25/29/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009606/07/12/18/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009619/07/25/31/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009710/07/12/20/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009723/07/25/33/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009814/07/12/22/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009827/07/25/35/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009918/07/12/24/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009931/07/25/37/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010022/07/12/26/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010035/07/25/39/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010126/07/12/28/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010139/07/25/41/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010230/07/12/30/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010243/07/25/43/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010334/07/12/32/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010347/07/25/45/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010438/07/12/34/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010451/07/25/47/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010542/07/12/36/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010555/07/25/49/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010646/08/12/38/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010659/08/25/00/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010750/08/12/40/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010763/08/25/02/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010854/08/12/42/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010867/08/25/04/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010958/08/12/44/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010971/08/25/06/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011062/08/12/46/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 011075/08/25/08/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011166/08/12/48/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 011179/08/25/10/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011270/08/12/50/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 011283/08/25/12/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011374/08/12/01/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 011387/08/25/14/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011478/08/12/03/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=1) 011491/08/25/16/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 011582/08/12/05/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010022/07/12/26/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010035/07/25/39/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010126/07/12/28/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010139/07/25/41/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010230/07/12/30/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010243/07/25/43/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010334/07/12/32/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010347/07/25/45/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010438/07/12/34/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010451/07/25/47/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010542/07/12/36/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010555/07/25/49/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010646/08/12/38/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010659/08/25/00/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010750/08/12/40/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010763/08/25/02/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010854/08/12/42/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010867/08/25/04/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010958/08/12/44/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010971/08/25/06/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011062/08/12/46/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011075/08/25/08/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011166/08/12/48/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011179/08/25/10/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011270/08/12/50/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011283/08/25/12/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011374/08/12/01/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011387/08/25/14/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011478/08/12/03/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011491/08/25/16/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011582/08/12/05/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011595/08/25/18/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011686/08/12/07/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011699/08/25/20/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011790/08/12/09/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011803/08/25/22/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011894/08/12/11/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 011907/08/25/24/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 011998/09/12/13/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 012011/09/25/26/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=0) 012102/09/12/15/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=3,ss=1) 012115/09/25/28/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=3,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=3,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=3,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=3,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=3,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008592/06/12/24/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008605/06/25/37/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008696/06/12/26/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008709/06/25/39/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008800/06/12/28/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008813/06/25/41/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008904/06/12/30/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008917/06/25/43/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009008/06/12/32/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009021/06/25/45/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009112/06/12/34/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009125/06/25/47/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009216/06/12/36/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009229/06/25/49/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009320/07/12/38/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009333/07/25/00/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009424/07/12/40/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009437/07/25/02/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009528/07/12/42/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009541/07/25/04/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009632/07/12/44/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009645/07/25/06/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009736/07/12/46/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009749/07/25/08/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009840/07/12/48/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009853/07/25/10/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009944/07/12/50/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009957/07/25/12/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010048/07/12/01/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010061/07/25/14/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010152/07/12/03/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010165/07/25/16/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010256/07/12/05/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010269/07/25/18/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010360/07/12/07/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010373/07/25/20/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010464/07/12/09/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010477/07/25/22/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010568/07/12/11/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010581/07/25/24/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010672/08/12/13/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010685/08/25/26/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010776/08/12/15/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010789/08/25/28/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010880/08/12/17/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010893/08/25/30/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010984/08/12/19/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010997/08/25/32/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=4,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=4,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=4,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=4,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=4,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005264/03/12/11/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005368/04/12/13/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005472/04/12/15/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005576/04/12/17/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005680/04/12/19/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005693/04/25/32/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005784/04/12/21/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005797/04/25/34/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005888/04/12/23/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005901/04/25/36/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005992/04/12/25/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006005/04/25/38/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006096/04/12/27/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006109/04/25/40/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006200/04/12/29/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006213/04/25/42/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006304/04/12/31/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006317/04/25/44/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006408/04/12/33/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006421/04/25/46/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006512/04/12/35/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006525/04/25/48/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006616/04/12/37/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006629/04/25/50/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006720/05/12/39/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006733/05/25/01/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006824/05/12/41/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006837/05/25/03/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006928/05/12/43/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006941/05/25/05/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007032/05/12/45/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007045/05/25/07/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007136/05/12/47/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007149/05/25/09/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007240/05/12/49/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007253/05/25/11/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007344/05/12/00/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007357/05/25/13/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007448/05/12/02/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007461/05/25/15/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007552/05/12/04/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007565/05/25/17/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007656/05/12/06/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007669/05/25/19/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007773/05/25/21/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007877/05/25/23/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007981/06/25/25/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008085/06/25/27/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=5,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=5,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=5,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=5,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=5,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008098/06/12/40/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008202/06/12/42/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008306/06/12/44/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008410/06/12/46/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008423/06/25/08/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008514/06/12/48/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008527/06/25/10/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008618/06/12/50/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008631/06/25/12/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008722/06/12/01/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008735/06/25/14/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008826/06/12/03/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008839/06/25/16/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008930/06/12/05/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008943/06/25/18/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009034/06/12/07/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009047/06/25/20/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009138/06/12/09/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009151/06/25/22/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009242/06/12/11/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009255/06/25/24/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009346/07/12/13/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009359/07/25/26/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009450/07/12/15/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009463/07/25/28/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009554/07/12/17/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009567/07/25/30/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009658/07/12/19/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009671/07/25/32/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009762/07/12/21/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009775/07/25/34/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009866/07/12/23/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009879/07/25/36/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009970/07/12/25/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009983/07/25/38/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010074/07/12/27/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010087/07/25/40/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010178/07/12/29/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010191/07/25/42/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010282/07/12/31/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010295/07/25/44/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010386/07/12/33/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010399/07/25/46/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010490/07/12/35/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010503/07/25/48/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010594/07/12/37/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010607/07/25/50/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010698/08/12/39/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010711/08/25/01/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010802/08/12/41/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010815/08/25/03/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010906/08/12/43/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010919/08/25/05/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011010/08/12/45/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011023/08/25/07/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011114/08/12/47/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011127/08/25/09/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011218/08/12/49/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011231/08/25/11/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011322/08/12/00/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011335/08/25/13/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011426/08/12/02/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011439/08/25/15/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=0) 011530/08/12/04/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=6,ss=1) 011543/08/25/17/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=6,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=6,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=6,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=6,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=6,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011738/08/12/08/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011842/08/12/10/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 011946/09/12/12/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012050/09/12/14/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012063/09/25/27/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012154/09/12/16/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012167/09/25/29/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012258/09/12/18/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012271/09/25/31/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012362/09/12/20/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012375/09/25/33/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012466/09/12/22/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012479/09/25/35/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012570/09/12/24/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012583/09/25/37/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012674/09/12/26/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012687/09/25/39/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012778/09/12/28/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012791/09/25/41/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012882/09/12/30/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012895/09/25/43/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 012986/09/12/32/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 012999/09/25/45/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013090/09/12/34/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013103/09/25/47/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013194/09/12/36/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013207/09/25/49/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013298/10/12/38/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013311/10/25/00/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013402/10/12/40/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013415/10/25/02/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013506/10/12/42/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013519/10/25/04/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013610/10/12/44/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013623/10/25/06/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013714/10/12/46/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013727/10/25/08/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013818/10/12/48/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013831/10/25/10/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 013922/10/12/50/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 013935/10/25/12/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014026/10/12/01/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014039/10/25/14/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014130/10/12/03/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014143/10/25/16/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014234/10/12/05/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014247/10/25/18/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014338/10/12/07/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014351/10/25/20/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014442/10/12/09/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014455/10/25/22/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014546/10/12/11/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014559/10/25/24/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014650/11/12/13/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014663/11/25/26/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014754/11/12/15/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014767/11/25/28/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014858/11/12/17/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014871/11/25/30/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 014962/11/12/19/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 014975/11/25/32/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 015066/11/12/21/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 015079/11/25/34/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=0) 015170/11/12/23/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=0) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=0) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=0) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=0) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=7,ss=1) 015183/11/25/36/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received 1 UL measurements, expected 13
+DEBUG (bts=0,trx=1,ts=7,ss=1) Replaced 12 measurements with dummy values, from which 12 were SUB measurements
+DEBUG (bts=0,trx=1,ts=7,ss=1) Received UL measurements contain 0 SUB measurements, expected 13
+ERROR (bts=0,trx=1,ts=7,ss=1) Incorrect number of SUB measurements detected! (12 vs exp 13)
+INFO (bts=0,trx=1,ts=7,ss=1) Computed TA256( 0), BER-FULL(92.30%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=7,ss=1) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(12), num_ul_meas(13)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=-256, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 3 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 22 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 0), BER-FULL(88.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000004/00/04/04/04 adding a SUB measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000008/00/08/08/08 adding a SUB measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000011/00/11/11/11 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000016/00/16/16/16 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=17, fn_mod=16
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000017/00/17/17/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=18, fn_mod=17
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000018/00/18/18/18 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=19, fn_mod=18
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000019/00/19/19/19 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=20, fn_mod=19
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000020/00/20/20/20 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=21, fn_mod=20
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=258, ci_cB=10, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000022/00/22/22/22 adding a FULL measurement (ber10k=0, ta_offs=254, ci_cB=10, rssi=-90), num_ul_meas=23, fn_mod=22
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000023/00/23/23/23 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=24, fn_mod=23
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000024/00/24/24/24 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=10, rssi=-90), num_ul_meas=25, fn_mod=24
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=1,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 256), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-80), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-80), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-100), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=0, ci_cB=10, rssi=-100), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 5 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 20 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 0), BER-FULL(80.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 0 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 25 measurements with dummy values, from which 2 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 0 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 0), BER-FULL(100.00%), RSSI-FULL(-109dBm), C/I-FULL( 0 cB), BER-SUB(100.00%), RSSI-SUB(-109dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(1), RXLEV_SUB(1), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000002/00/02/02/02 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000013/00/13/13/13 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000016/00/16/16/16 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=17, fn_mod=16
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000017/00/17/17/17 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=18, fn_mod=17
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000018/00/18/18/18 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=19, fn_mod=18
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000019/00/19/19/19 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=20, fn_mod=19
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000020/00/20/20/20 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=21, fn_mod=20
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000022/00/22/22/22 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=23, fn_mod=22
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000023/00/23/23/23 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=24, fn_mod=23
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000024/00/24/24/24 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=25, fn_mod=24
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=26, fn_mod=25
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 26 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 1 excess UL measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=1,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000014/00/14/14/14 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000016/00/16/16/16 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=17, fn_mod=16
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000017/00/17/17/17 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=18, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000018/00/18/18/18 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=19, fn_mod=18
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000019/00/19/19/19 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=20, fn_mod=19
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000020/00/20/20/20 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=21, fn_mod=20
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000022/00/22/22/22 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=23, fn_mod=22
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000023/00/23/23/23 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=24, fn_mod=23
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000024/00/24/24/24 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=25, fn_mod=24
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 16 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 9 measurements with dummy values, from which 1 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 1 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL(36.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB(50.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000015/00/15/15/15 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 16 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 9 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL(36.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000014/00/14/14/14 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000016/00/16/16/16 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=17, fn_mod=16
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000017/00/17/17/17 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=18, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000018/00/18/18/18 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=19, fn_mod=18
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000019/00/19/19/19 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=20, fn_mod=19
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000020/00/20/20/20 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=21, fn_mod=20
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000022/00/22/22/22 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=23, fn_mod=22
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000023/00/23/23/23 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=24, fn_mod=23
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000024/00/24/24/24 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=25, fn_mod=24
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 5 SUB measurements, expected 3
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (5 vs exp 3)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(5), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 14 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 11 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 3
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL(44.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000002/00/02/02/02 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000003/00/03/03/03 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000007/00/07/07/07 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000012/00/12/12/12 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000015/00/15/15/15 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 16 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 9 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 5 SUB measurements, expected 3
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (5 vs exp 3)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 16384), BER-FULL(36.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(5), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000001/00/01/01/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000002/00/02/02/02 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000003/00/03/03/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=4, fn_mod=3
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=5, fn_mod=4
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000005/00/05/05/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=6, fn_mod=5
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000006/00/06/06/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=7, fn_mod=6
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000007/00/07/07/07 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=8, fn_mod=7
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=9, fn_mod=8
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000009/00/09/09/09 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=10, fn_mod=9
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000010/00/10/10/10 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=11, fn_mod=10
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000011/00/11/11/11 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=12, fn_mod=11
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000012/00/12/12/12 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=13, fn_mod=12
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000013/00/13/13/13 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=14, fn_mod=13
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000014/00/14/14/14 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=15, fn_mod=14
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000015/00/15/15/15 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=16, fn_mod=15
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000016/00/16/16/16 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=17, fn_mod=16
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000017/00/17/17/17 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=18, fn_mod=17
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000018/00/18/18/18 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=19, fn_mod=18
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000019/00/19/19/19 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=20, fn_mod=19
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000020/00/20/20/20 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=21, fn_mod=20
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000022/00/22/22/22 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=23, fn_mod=22
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000023/00/23/23/23 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=24, fn_mod=23
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000024/00/24/24/24 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=25, fn_mod=24
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=26, fn_mod=25
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000026/00/00/26/26 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=27, fn_mod=26
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000027/00/01/27/27 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=28, fn_mod=27
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000028/00/02/28/28 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=29, fn_mod=28
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000029/00/03/29/29 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=30, fn_mod=29
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000030/00/04/30/30 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=31, fn_mod=30
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000031/00/05/31/31 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=32, fn_mod=31
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000032/00/06/32/32 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=33, fn_mod=32
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000033/00/07/33/33 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=34, fn_mod=33
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000034/00/08/34/34 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=35, fn_mod=34
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000035/00/09/35/35 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=36, fn_mod=35
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000036/00/10/36/36 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=37, fn_mod=36
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000037/00/11/37/37 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=38, fn_mod=37
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000038/00/12/38/38 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=39, fn_mod=38
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000039/00/13/39/39 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=40, fn_mod=39
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000040/00/14/40/40 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=41, fn_mod=40
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000041/00/15/41/41 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=42, fn_mod=41
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000042/00/16/42/42 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=43, fn_mod=42
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000043/00/17/43/43 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=44, fn_mod=43
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000044/00/18/44/44 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=45, fn_mod=44
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000045/00/19/45/45 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=46, fn_mod=45
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000046/00/20/46/46 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=47, fn_mod=46
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000047/00/21/47/47 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=48, fn_mod=47
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000048/00/22/48/48 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=49, fn_mod=48
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000049/00/23/49/49 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=50, fn_mod=49
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000050/00/24/50/50 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=51, fn_mod=50
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000051/00/25/00/51 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=52, fn_mod=51
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000052/00/00/01/00 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=53, fn_mod=52
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000053/00/01/02/01 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=54, fn_mod=53
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000054/00/02/03/02 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=55, fn_mod=54
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000055/00/03/04/03 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=56, fn_mod=55
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000056/00/04/05/04 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=57, fn_mod=56
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000057/00/05/06/05 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=58, fn_mod=57
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000058/00/06/07/06 adding a FULL measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=59, fn_mod=58
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 59 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received 34 excess UL measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=1,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=1,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=1,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=1,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000000/00/00/00/00 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000001/00/01/01/01 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000002/00/02/02/02 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000088/00/10/37/36 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) Calculating measurement results for physical channel: CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) Received 3 UL measurements, expected 3
+DEBUG (bts=0,trx=1,ts=0,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=0,ss=0) Received UL measurements contain 3 SUB measurements, expected 3
+INFO (bts=0,trx=1,ts=0,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=0,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(3)
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000000/00/00/00/00 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000001/00/01/01/01 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=2, fn_mod=1
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000002/00/02/02/02 adding a SUB measurement (ber10k=0, ta_offs=16384, ci_cB=10, rssi=-90), num_ul_meas=3, fn_mod=2
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000066/00/14/15/14 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) Calculating measurement results for physical channel: SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) Received 3 UL measurements, expected 3
+DEBUG (bts=0,trx=1,ts=0,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=0,ss=0) Received UL measurements contain 3 SUB measurements, expected 3
+INFO (bts=0,trx=1,ts=0,ss=0) Computed TA256( 16384), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 10 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 10 cB)
+INFO (bts=0,trx=1,ts=0,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(3)
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000012/00/12/12/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000116/00/12/14/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000220/00/12/16/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000324/00/12/18/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000428/00/12/20/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000532/00/12/22/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000636/00/12/24/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000740/00/12/26/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000844/00/12/28/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000948/00/12/30/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001052/00/12/32/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001156/00/12/34/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001260/00/12/36/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001364/01/12/38/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001468/01/12/40/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001572/01/12/42/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001676/01/12/44/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001780/01/12/46/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001884/01/12/48/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001988/01/12/50/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002092/01/12/01/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002196/01/12/03/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002300/01/12/05/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002404/01/12/07/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002508/01/12/09/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002612/01/12/11/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002716/02/12/13/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002820/02/12/15/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002924/02/12/17/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003028/02/12/19/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003132/02/12/21/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003236/02/12/23/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003340/02/12/25/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003444/02/12/27/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003548/02/12/29/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003652/02/12/31/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003756/02/12/33/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003860/02/12/35/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003964/02/12/37/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004068/03/12/39/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004172/03/12/41/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004276/03/12/43/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004380/03/12/45/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004484/03/12/47/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004588/03/12/49/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004692/03/12/00/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004796/03/12/02/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004900/03/12/04/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005004/03/12/06/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005108/03/12/08/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005212/03/12/10/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005316/04/12/12/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005420/04/12/14/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005524/04/12/16/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005628/04/12/18/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005732/04/12/20/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005836/04/12/22/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005940/04/12/24/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006044/04/12/26/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006148/04/12/28/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006252/04/12/30/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006356/04/12/32/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006460/04/12/34/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006564/04/12/36/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006668/05/12/38/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006772/05/12/40/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006876/05/12/42/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006980/05/12/44/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007084/05/12/46/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007188/05/12/48/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007292/05/12/50/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007396/05/12/01/20 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007500/05/12/03/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007604/05/12/05/24 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007708/05/12/07/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007812/05/12/09/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007916/05/12/11/28 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008020/06/12/13/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008124/06/12/15/32 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008228/06/12/17/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008332/06/12/19/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008436/06/12/21/36 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008540/06/12/23/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008644/06/12/25/40 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008748/06/12/27/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008852/06/12/29/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008956/06/12/31/44 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009060/06/12/33/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009164/06/12/35/48 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009268/06/12/37/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009372/07/12/39/00 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009476/07/12/41/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009580/07/12/43/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009684/07/12/45/04 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009788/07/12/47/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009892/07/12/49/08 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009996/07/12/00/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010100/07/12/02/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010204/07/12/04/12 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010308/07/12/06/16 meas period end fn_mod:90, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000129/00/25/27/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000233/00/25/29/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000337/00/25/31/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000441/00/25/33/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000545/00/25/35/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000649/00/25/37/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000753/00/25/39/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000857/00/25/41/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000961/00/25/43/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001065/00/25/45/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001169/00/25/47/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001273/00/25/49/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001377/01/25/00/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001481/01/25/02/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001585/01/25/04/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001689/01/25/06/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001793/01/25/08/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001897/01/25/10/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002001/01/25/12/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002105/01/25/14/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002209/01/25/16/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002313/01/25/18/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002417/01/25/20/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002521/01/25/22/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002625/01/25/24/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002729/02/25/26/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002833/02/25/28/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002937/02/25/30/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003041/02/25/32/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003145/02/25/34/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003249/02/25/36/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003353/02/25/38/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003457/02/25/40/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003561/02/25/42/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003665/02/25/44/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003769/02/25/46/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003873/02/25/48/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003977/02/25/50/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004081/03/25/01/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004185/03/25/03/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004289/03/25/05/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004393/03/25/07/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004497/03/25/09/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004601/03/25/11/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004705/03/25/13/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004809/03/25/15/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004913/03/25/17/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005017/03/25/19/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005121/03/25/21/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005225/03/25/23/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005329/04/25/25/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005433/04/25/27/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005537/04/25/29/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005641/04/25/31/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005745/04/25/33/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005849/04/25/35/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005953/04/25/37/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006057/04/25/39/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006161/04/25/41/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006265/04/25/43/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006369/04/25/45/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006473/04/25/47/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006577/04/25/49/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006681/05/25/00/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006785/05/25/02/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006889/05/25/04/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006993/05/25/06/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007097/05/25/08/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007201/05/25/10/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007305/05/25/12/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007409/05/25/14/33 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007513/05/25/16/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007617/05/25/18/37 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007721/05/25/20/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007825/05/25/22/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007929/05/25/24/41 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008033/06/25/26/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008137/06/25/28/45 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008241/06/25/30/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008345/06/25/32/49 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008449/06/25/34/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008553/06/25/36/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008657/06/25/38/01 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008761/06/25/40/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008865/06/25/42/05 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008969/06/25/44/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009073/06/25/46/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009177/06/25/48/09 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009281/06/25/50/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009385/07/25/01/13 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009489/07/25/03/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009593/07/25/05/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009697/07/25/07/17 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009801/07/25/09/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009905/07/25/11/21 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010009/07/25/13/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010113/07/25/15/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010217/07/25/17/25 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010321/07/25/19/29 meas period end fn_mod:103, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000454/00/12/46/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000558/00/12/48/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000662/00/12/50/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000766/00/12/01/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000870/00/12/03/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000974/00/12/05/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001078/00/12/07/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001182/00/12/09/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001286/00/12/11/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001390/01/12/13/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001494/01/12/15/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001598/01/12/17/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001702/01/12/19/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001806/01/12/21/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001910/01/12/23/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002014/01/12/25/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002118/01/12/27/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002222/01/12/29/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002326/01/12/31/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002430/01/12/33/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002534/01/12/35/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002638/01/12/37/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002742/02/12/39/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002846/02/12/41/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002950/02/12/43/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003054/02/12/45/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003158/02/12/47/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003262/02/12/49/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003366/02/12/00/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003470/02/12/02/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003574/02/12/04/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003678/02/12/06/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003782/02/12/08/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003886/02/12/10/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003990/03/12/12/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004094/03/12/14/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004198/03/12/16/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004302/03/12/18/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004406/03/12/20/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004510/03/12/22/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004614/03/12/24/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004718/03/12/26/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004822/03/12/28/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004926/03/12/30/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005030/03/12/32/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005134/03/12/34/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005238/03/12/36/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005342/04/12/38/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005446/04/12/40/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005550/04/12/42/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005654/04/12/44/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005758/04/12/46/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005862/04/12/48/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005966/04/12/50/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006070/04/12/01/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006174/04/12/03/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006278/04/12/05/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006382/04/12/07/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006486/04/12/09/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006590/04/12/11/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006694/05/12/13/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006798/05/12/15/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006902/05/12/17/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007006/05/12/19/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007110/05/12/21/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007214/05/12/23/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007318/05/12/25/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007422/05/12/27/46 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007526/05/12/29/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007630/05/12/31/50 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007734/05/12/33/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007838/05/12/35/02 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007942/05/12/37/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008046/06/12/39/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008150/06/12/41/06 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008254/06/12/43/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008358/06/12/45/10 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008462/06/12/47/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008566/06/12/49/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008670/06/12/00/14 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008774/06/12/02/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008878/06/12/04/18 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008982/06/12/06/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009086/06/12/08/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009190/06/12/10/22 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009294/07/12/12/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009398/07/12/14/26 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009502/07/12/16/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009606/07/12/18/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009710/07/12/20/30 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009814/07/12/22/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009918/07/12/24/34 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010022/07/12/26/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010126/07/12/28/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010230/07/12/30/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010334/07/12/32/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000051/00/25/00/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000155/00/25/02/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000259/00/25/04/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000363/00/25/06/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000467/00/25/08/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000571/00/25/10/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000675/00/25/12/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000779/00/25/14/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000883/00/25/16/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000987/00/25/18/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001091/00/25/20/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001195/00/25/22/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001299/00/25/24/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001403/01/25/26/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001507/01/25/28/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001611/01/25/30/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001715/01/25/32/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001819/01/25/34/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001923/01/25/36/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002027/01/25/38/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002131/01/25/40/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002235/01/25/42/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002339/01/25/44/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002443/01/25/46/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002547/01/25/48/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002651/01/25/50/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002755/02/25/01/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002859/02/25/03/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002963/02/25/05/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003067/02/25/07/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003171/02/25/09/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003275/02/25/11/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003379/02/25/13/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003483/02/25/15/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003587/02/25/17/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003691/02/25/19/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003795/02/25/21/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003899/02/25/23/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004003/03/25/25/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004107/03/25/27/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004211/03/25/29/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004315/03/25/31/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004419/03/25/33/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004523/03/25/35/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004627/03/25/37/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004731/03/25/39/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004835/03/25/41/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004939/03/25/43/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005043/03/25/45/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005147/03/25/47/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005251/03/25/49/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005355/04/25/00/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005459/04/25/02/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005563/04/25/04/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005667/04/25/06/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005771/04/25/08/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005875/04/25/10/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005979/04/25/12/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006083/04/25/14/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006187/04/25/16/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006291/04/25/18/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006395/04/25/20/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006499/04/25/22/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006603/04/25/24/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006707/05/25/26/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006811/05/25/28/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006915/05/25/30/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007019/05/25/32/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007123/05/25/34/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007227/05/25/36/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007331/05/25/38/07 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007435/05/25/40/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007539/05/25/42/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007643/05/25/44/11 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007747/05/25/46/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007851/05/25/48/15 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007955/05/25/50/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008059/06/25/01/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008163/06/25/03/19 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008267/06/25/05/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008371/06/25/07/23 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008475/06/25/09/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008579/06/25/11/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008683/06/25/13/27 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008787/06/25/15/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008891/06/25/17/31 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008995/06/25/19/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009099/06/25/21/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009203/06/25/23/35 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009307/07/25/25/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009411/07/25/27/39 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009515/07/25/29/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009619/07/25/31/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009723/07/25/33/43 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009827/07/25/35/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009931/07/25/37/47 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010035/07/25/39/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010139/07/25/41/51 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010243/07/25/43/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010347/07/25/45/03 meas period end fn_mod:25, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000064/00/12/13/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000168/00/12/15/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000272/00/12/17/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000376/00/12/19/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000480/00/12/21/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000584/00/12/23/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000688/00/12/25/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000792/00/12/27/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000896/00/12/29/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001000/00/12/31/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001104/00/12/33/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001208/00/12/35/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001312/00/12/37/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001416/01/12/39/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001520/01/12/41/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001624/01/12/43/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001728/01/12/45/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001832/01/12/47/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001936/01/12/49/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002040/01/12/00/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002144/01/12/02/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002248/01/12/04/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002352/01/12/06/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002456/01/12/08/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002560/01/12/10/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002664/02/12/12/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002768/02/12/14/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002872/02/12/16/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002976/02/12/18/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003080/02/12/20/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003184/02/12/22/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003288/02/12/24/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003392/02/12/26/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003496/02/12/28/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003600/02/12/30/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003704/02/12/32/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003808/02/12/34/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003912/02/12/36/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004016/03/12/38/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004120/03/12/40/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004224/03/12/42/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004328/03/12/44/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004432/03/12/46/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004536/03/12/48/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004640/03/12/50/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004744/03/12/01/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004848/03/12/03/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004952/03/12/05/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005056/03/12/07/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005160/03/12/09/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005264/03/12/11/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005368/04/12/13/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005472/04/12/15/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005576/04/12/17/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005680/04/12/19/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005784/04/12/21/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005888/04/12/23/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005992/04/12/25/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006096/04/12/27/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006200/04/12/29/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006304/04/12/31/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006408/04/12/33/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006512/04/12/35/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006616/04/12/37/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006720/05/12/39/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006824/05/12/41/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006928/05/12/43/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007032/05/12/45/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007136/05/12/47/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007240/05/12/49/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007344/05/12/00/20 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007448/05/12/02/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007552/05/12/04/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007656/05/12/06/24 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008592/06/12/24/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008696/06/12/26/40 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008800/06/12/28/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008904/06/12/30/44 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009008/06/12/32/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009112/06/12/34/48 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009216/06/12/36/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009320/07/12/38/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009424/07/12/40/00 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009528/07/12/42/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009632/07/12/44/04 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009736/07/12/46/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009840/07/12/48/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009944/07/12/50/08 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010048/07/12/01/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010152/07/12/03/12 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010256/07/12/05/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010360/07/12/07/16 meas period end fn_mod:38, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000077/00/25/26/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000181/00/25/28/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000285/00/25/30/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000389/00/25/32/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000493/00/25/34/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000597/00/25/36/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000701/00/25/38/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000805/00/25/40/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000909/00/25/42/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001013/00/25/44/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001117/00/25/46/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001221/00/25/48/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001325/00/25/50/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001429/01/25/01/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001533/01/25/03/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001637/01/25/05/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001741/01/25/07/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001845/01/25/09/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001949/01/25/11/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002053/01/25/13/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002157/01/25/15/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002261/01/25/17/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002365/01/25/19/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002469/01/25/21/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002573/01/25/23/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002677/02/25/25/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002781/02/25/27/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002885/02/25/29/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002989/02/25/31/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003093/02/25/33/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003197/02/25/35/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003301/02/25/37/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003405/02/25/39/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003509/02/25/41/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003613/02/25/43/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003717/02/25/45/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003821/02/25/47/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003925/02/25/49/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004029/03/25/00/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004133/03/25/02/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004237/03/25/04/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004341/03/25/06/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004445/03/25/08/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004549/03/25/10/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004653/03/25/12/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004757/03/25/14/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004861/03/25/16/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004965/03/25/18/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005069/03/25/20/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005173/03/25/22/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005277/03/25/24/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005381/04/25/26/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005485/04/25/28/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005589/04/25/30/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005693/04/25/32/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005797/04/25/34/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005901/04/25/36/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006005/04/25/38/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006109/04/25/40/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006213/04/25/42/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006317/04/25/44/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006421/04/25/46/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006525/04/25/48/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006629/04/25/50/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006733/05/25/01/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006837/05/25/03/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006941/05/25/05/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007045/05/25/07/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007149/05/25/09/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007253/05/25/11/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007357/05/25/13/33 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007461/05/25/15/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007565/05/25/17/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007669/05/25/19/37 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007773/05/25/21/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007877/05/25/23/41 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007981/06/25/25/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008085/06/25/27/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008605/06/25/37/01 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008709/06/25/39/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008813/06/25/41/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008917/06/25/43/05 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009021/06/25/45/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009125/06/25/47/09 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009229/06/25/49/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009333/07/25/00/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009437/07/25/02/13 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009541/07/25/04/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009645/07/25/06/17 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009749/07/25/08/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009853/07/25/10/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009957/07/25/12/21 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010061/07/25/14/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010165/07/25/16/25 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010269/07/25/18/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010373/07/25/20/29 meas period end fn_mod:51, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000090/00/12/39/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000194/00/12/41/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000298/00/12/43/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000402/00/12/45/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000506/00/12/47/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000610/00/12/49/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000714/00/12/00/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000818/00/12/02/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000922/00/12/04/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001026/00/12/06/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001130/00/12/08/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001234/00/12/10/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001338/01/12/12/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001442/01/12/14/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001546/01/12/16/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001650/01/12/18/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001754/01/12/20/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001858/01/12/22/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001962/01/12/24/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002066/01/12/26/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002170/01/12/28/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002274/01/12/30/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002378/01/12/32/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002482/01/12/34/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002586/01/12/36/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002690/02/12/38/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002794/02/12/40/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002898/02/12/42/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003002/02/12/44/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003106/02/12/46/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003210/02/12/48/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003314/02/12/50/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003418/02/12/01/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003522/02/12/03/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003626/02/12/05/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003730/02/12/07/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003834/02/12/09/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003938/02/12/11/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004042/03/12/13/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004146/03/12/15/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004250/03/12/17/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004354/03/12/19/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004458/03/12/21/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004562/03/12/23/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004666/03/12/25/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004770/03/12/27/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004874/03/12/29/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004978/03/12/31/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005082/03/12/33/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005186/03/12/35/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005290/03/12/37/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005394/04/12/39/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005498/04/12/41/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005602/04/12/43/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005706/04/12/45/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005810/04/12/47/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005914/04/12/49/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006018/04/12/00/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006122/04/12/02/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006226/04/12/04/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006330/04/12/06/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006434/04/12/08/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006538/04/12/10/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006642/05/12/12/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006746/05/12/14/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006850/05/12/16/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006954/05/12/18/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007058/05/12/20/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007162/05/12/22/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007266/05/12/24/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007370/05/12/26/46 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007474/05/12/28/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007578/05/12/30/50 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007682/05/12/32/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007786/05/12/34/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007890/05/12/36/02 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007994/06/12/38/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008098/06/12/40/06 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008202/06/12/42/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008306/06/12/44/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008410/06/12/46/10 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008514/06/12/48/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008618/06/12/50/14 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008722/06/12/01/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008826/06/12/03/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008930/06/12/05/18 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009034/06/12/07/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009138/06/12/09/22 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009242/06/12/11/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009346/07/12/13/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009450/07/12/15/26 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009554/07/12/17/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009658/07/12/19/30 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009762/07/12/21/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009866/07/12/23/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009970/07/12/25/34 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010074/07/12/27/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010178/07/12/29/38 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010282/07/12/31/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010386/07/12/33/42 meas period end fn_mod:64, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000103/00/25/01/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000207/00/25/03/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000311/00/25/05/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000415/00/25/07/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000519/00/25/09/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000623/00/25/11/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000727/00/25/13/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000831/00/25/15/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000935/00/25/17/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001039/00/25/19/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001143/00/25/21/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001247/00/25/23/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001351/01/25/25/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001455/01/25/27/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001559/01/25/29/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001663/01/25/31/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001767/01/25/33/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001871/01/25/35/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001975/01/25/37/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002079/01/25/39/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002183/01/25/41/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002287/01/25/43/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002391/01/25/45/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002495/01/25/47/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002599/01/25/49/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002703/02/25/00/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002807/02/25/02/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002911/02/25/04/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003015/02/25/06/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003119/02/25/08/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003223/02/25/10/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003327/02/25/12/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003431/02/25/14/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003535/02/25/16/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003639/02/25/18/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003743/02/25/20/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003847/02/25/22/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003951/02/25/24/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004055/03/25/26/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004159/03/25/28/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004263/03/25/30/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004367/03/25/32/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004471/03/25/34/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004575/03/25/36/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004679/03/25/38/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004783/03/25/40/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004887/03/25/42/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004991/03/25/44/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005095/03/25/46/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005199/03/25/48/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005303/03/25/50/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005407/04/25/01/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005511/04/25/03/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005615/04/25/05/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005719/04/25/07/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005823/04/25/09/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005927/04/25/11/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006031/04/25/13/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006135/04/25/15/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006239/04/25/17/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006343/04/25/19/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006447/04/25/21/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006551/04/25/23/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006655/05/25/25/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006759/05/25/27/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006863/05/25/29/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006967/05/25/31/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007071/05/25/33/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007175/05/25/35/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007279/05/25/37/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007383/05/25/39/07 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007487/05/25/41/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007591/05/25/43/11 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007695/05/25/45/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007799/05/25/47/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007903/05/25/49/15 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008007/06/25/00/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008111/06/25/02/19 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008215/06/25/04/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008319/06/25/06/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008423/06/25/08/23 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008527/06/25/10/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008631/06/25/12/27 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008735/06/25/14/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008839/06/25/16/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008943/06/25/18/31 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009047/06/25/20/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009151/06/25/22/35 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009255/06/25/24/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009359/07/25/26/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009463/07/25/28/39 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009567/07/25/30/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009671/07/25/32/43 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009775/07/25/34/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009879/07/25/36/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009983/07/25/38/47 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010087/07/25/40/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010191/07/25/42/51 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010295/07/25/44/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010399/07/25/46/03 meas period end fn_mod:77, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000012/00/12/12/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000116/00/12/14/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000220/00/12/16/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000324/00/12/18/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000428/00/12/20/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000532/00/12/22/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000636/00/12/24/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000740/00/12/26/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000844/00/12/28/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000948/00/12/30/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001052/00/12/32/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001156/00/12/34/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001260/00/12/36/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001364/01/12/38/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001468/01/12/40/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001572/01/12/42/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001676/01/12/44/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001780/01/12/46/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001884/01/12/48/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001988/01/12/50/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002092/01/12/01/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002196/01/12/03/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002300/01/12/05/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002404/01/12/07/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002508/01/12/09/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002612/01/12/11/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002716/02/12/13/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002820/02/12/15/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002924/02/12/17/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003028/02/12/19/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003132/02/12/21/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003236/02/12/23/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003340/02/12/25/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003444/02/12/27/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003548/02/12/29/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003652/02/12/31/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003756/02/12/33/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003860/02/12/35/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003964/02/12/37/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004068/03/12/39/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004172/03/12/41/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004276/03/12/43/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004380/03/12/45/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004484/03/12/47/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004588/03/12/49/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004692/03/12/00/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004796/03/12/02/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004900/03/12/04/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005004/03/12/06/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005108/03/12/08/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005212/03/12/10/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005316/04/12/12/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005420/04/12/14/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005524/04/12/16/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005628/04/12/18/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005732/04/12/20/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005836/04/12/22/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005940/04/12/24/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006044/04/12/26/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006148/04/12/28/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006252/04/12/30/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006356/04/12/32/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006460/04/12/34/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006564/04/12/36/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006668/05/12/38/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006772/05/12/40/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006876/05/12/42/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006980/05/12/44/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007084/05/12/46/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007188/05/12/48/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007292/05/12/50/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007396/05/12/01/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007500/05/12/03/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007604/05/12/05/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007708/05/12/07/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007812/05/12/09/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007916/05/12/11/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008020/06/12/13/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008124/06/12/15/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008228/06/12/17/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008332/06/12/19/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008436/06/12/21/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008540/06/12/23/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008644/06/12/25/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008748/06/12/27/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008852/06/12/29/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008956/06/12/31/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009060/06/12/33/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009164/06/12/35/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009268/06/12/37/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009372/07/12/39/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009476/07/12/41/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009580/07/12/43/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009684/07/12/45/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009788/07/12/47/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009892/07/12/49/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009996/07/12/00/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010100/07/12/02/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010204/07/12/04/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010308/07/12/06/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000012/00/12/12/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000116/00/12/14/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000220/00/12/16/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000324/00/12/18/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000428/00/12/20/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000532/00/12/22/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000636/00/12/24/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000740/00/12/26/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000844/00/12/28/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 000948/00/12/30/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001052/00/12/32/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001156/00/12/34/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001260/00/12/36/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001364/01/12/38/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001468/01/12/40/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001572/01/12/42/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001676/01/12/44/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001780/01/12/46/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001884/01/12/48/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 001988/01/12/50/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002092/01/12/01/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002196/01/12/03/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002300/01/12/05/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002404/01/12/07/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002508/01/12/09/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002612/01/12/11/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002716/02/12/13/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002820/02/12/15/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 002924/02/12/17/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003028/02/12/19/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003132/02/12/21/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003236/02/12/23/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003340/02/12/25/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003444/02/12/27/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003548/02/12/29/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003652/02/12/31/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003756/02/12/33/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003860/02/12/35/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 003964/02/12/37/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004068/03/12/39/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004172/03/12/41/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004276/03/12/43/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004380/03/12/45/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004484/03/12/47/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004588/03/12/49/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004692/03/12/00/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004796/03/12/02/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 004900/03/12/04/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005004/03/12/06/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005108/03/12/08/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005212/03/12/10/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005316/04/12/12/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005420/04/12/14/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005524/04/12/16/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005628/04/12/18/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005732/04/12/20/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005836/04/12/22/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 005940/04/12/24/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006044/04/12/26/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006148/04/12/28/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006252/04/12/30/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006356/04/12/32/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006460/04/12/34/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006564/04/12/36/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006668/05/12/38/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006772/05/12/40/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006876/05/12/42/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 006980/05/12/44/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007084/05/12/46/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007188/05/12/48/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007292/05/12/50/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007396/05/12/01/20 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007500/05/12/03/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007604/05/12/05/24 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007708/05/12/07/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007812/05/12/09/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 007916/05/12/11/28 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008020/06/12/13/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008124/06/12/15/32 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008228/06/12/17/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008332/06/12/19/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008436/06/12/21/36 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008540/06/12/23/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008644/06/12/25/40 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008748/06/12/27/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008852/06/12/29/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 008956/06/12/31/44 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009060/06/12/33/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009164/06/12/35/48 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009268/06/12/37/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009372/07/12/39/00 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009476/07/12/41/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009580/07/12/43/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009684/07/12/45/04 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009788/07/12/47/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009892/07/12/49/08 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 009996/07/12/00/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010100/07/12/02/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010204/07/12/04/12 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=0) 010308/07/12/06/16 meas period end fn_mod:90, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000129/00/25/27/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000233/00/25/29/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000337/00/25/31/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000441/00/25/33/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000545/00/25/35/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000649/00/25/37/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000753/00/25/39/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000857/00/25/41/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000961/00/25/43/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001065/00/25/45/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001169/00/25/47/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001273/00/25/49/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001377/01/25/00/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001481/01/25/02/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001585/01/25/04/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001689/01/25/06/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001793/01/25/08/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001897/01/25/10/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002001/01/25/12/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002105/01/25/14/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002209/01/25/16/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002313/01/25/18/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002417/01/25/20/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002521/01/25/22/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002625/01/25/24/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002729/02/25/26/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002833/02/25/28/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002937/02/25/30/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003041/02/25/32/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003145/02/25/34/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003249/02/25/36/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003353/02/25/38/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003457/02/25/40/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003561/02/25/42/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003665/02/25/44/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003769/02/25/46/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003873/02/25/48/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003977/02/25/50/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004081/03/25/01/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004185/03/25/03/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004289/03/25/05/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004393/03/25/07/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004497/03/25/09/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004601/03/25/11/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004705/03/25/13/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004809/03/25/15/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004913/03/25/17/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005017/03/25/19/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005121/03/25/21/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005225/03/25/23/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005329/04/25/25/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005433/04/25/27/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005537/04/25/29/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005641/04/25/31/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005745/04/25/33/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005849/04/25/35/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005953/04/25/37/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006057/04/25/39/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006161/04/25/41/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006265/04/25/43/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006369/04/25/45/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006473/04/25/47/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006577/04/25/49/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006681/05/25/00/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006785/05/25/02/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006889/05/25/04/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006993/05/25/06/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007097/05/25/08/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007201/05/25/10/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007305/05/25/12/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007409/05/25/14/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007513/05/25/16/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007617/05/25/18/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007721/05/25/20/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007825/05/25/22/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007929/05/25/24/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008033/06/25/26/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008137/06/25/28/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008241/06/25/30/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008345/06/25/32/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008449/06/25/34/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008553/06/25/36/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008657/06/25/38/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008761/06/25/40/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008865/06/25/42/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008969/06/25/44/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009073/06/25/46/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009177/06/25/48/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009281/06/25/50/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009385/07/25/01/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009489/07/25/03/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009593/07/25/05/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009697/07/25/07/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009801/07/25/09/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009905/07/25/11/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010009/07/25/13/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010113/07/25/15/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010217/07/25/17/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010321/07/25/19/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000025/00/25/25/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000129/00/25/27/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000233/00/25/29/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000337/00/25/31/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000441/00/25/33/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000545/00/25/35/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000649/00/25/37/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000753/00/25/39/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000857/00/25/41/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 000961/00/25/43/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001065/00/25/45/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001169/00/25/47/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001273/00/25/49/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001377/01/25/00/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001481/01/25/02/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001585/01/25/04/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001689/01/25/06/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001793/01/25/08/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 001897/01/25/10/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002001/01/25/12/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002105/01/25/14/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002209/01/25/16/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002313/01/25/18/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002417/01/25/20/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002521/01/25/22/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002625/01/25/24/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002729/02/25/26/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002833/02/25/28/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 002937/02/25/30/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003041/02/25/32/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003145/02/25/34/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003249/02/25/36/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003353/02/25/38/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003457/02/25/40/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003561/02/25/42/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003665/02/25/44/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003769/02/25/46/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003873/02/25/48/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 003977/02/25/50/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004081/03/25/01/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004185/03/25/03/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004289/03/25/05/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004393/03/25/07/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004497/03/25/09/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004601/03/25/11/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004705/03/25/13/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004809/03/25/15/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 004913/03/25/17/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005017/03/25/19/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005121/03/25/21/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005225/03/25/23/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005329/04/25/25/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005433/04/25/27/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005537/04/25/29/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005641/04/25/31/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005745/04/25/33/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005849/04/25/35/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 005953/04/25/37/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006057/04/25/39/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006161/04/25/41/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006265/04/25/43/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006369/04/25/45/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006473/04/25/47/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006577/04/25/49/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006681/05/25/00/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006785/05/25/02/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006889/05/25/04/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 006993/05/25/06/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007097/05/25/08/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007201/05/25/10/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007305/05/25/12/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007409/05/25/14/33 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007513/05/25/16/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007617/05/25/18/37 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007721/05/25/20/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007825/05/25/22/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 007929/05/25/24/41 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008033/06/25/26/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008137/06/25/28/45 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008241/06/25/30/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008345/06/25/32/49 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008449/06/25/34/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008553/06/25/36/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008657/06/25/38/01 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008761/06/25/40/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008865/06/25/42/05 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 008969/06/25/44/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009073/06/25/46/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009177/06/25/48/09 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009281/06/25/50/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009385/07/25/01/13 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009489/07/25/03/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009593/07/25/05/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009697/07/25/07/17 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009801/07/25/09/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 009905/07/25/11/21 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 010009/07/25/13/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 010113/07/25/15/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 010217/07/25/17/25 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=1,ss=1) 010321/07/25/19/29 meas period end fn_mod:103, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000454/00/12/46/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000558/00/12/48/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000662/00/12/50/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000766/00/12/01/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000870/00/12/03/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000974/00/12/05/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001078/00/12/07/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001182/00/12/09/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001286/00/12/11/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001390/01/12/13/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001494/01/12/15/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001598/01/12/17/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001702/01/12/19/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001806/01/12/21/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 001910/01/12/23/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002014/01/12/25/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002118/01/12/27/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002222/01/12/29/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002326/01/12/31/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002430/01/12/33/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002534/01/12/35/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002638/01/12/37/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002742/02/12/39/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002846/02/12/41/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 002950/02/12/43/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003054/02/12/45/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003158/02/12/47/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003262/02/12/49/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003366/02/12/00/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003470/02/12/02/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003574/02/12/04/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003678/02/12/06/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003782/02/12/08/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003886/02/12/10/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 003990/03/12/12/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004094/03/12/14/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004198/03/12/16/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004302/03/12/18/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004406/03/12/20/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004510/03/12/22/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004614/03/12/24/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004718/03/12/26/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004822/03/12/28/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 004926/03/12/30/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005030/03/12/32/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005134/03/12/34/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005238/03/12/36/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005342/04/12/38/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005446/04/12/40/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005550/04/12/42/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005654/04/12/44/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005758/04/12/46/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005862/04/12/48/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 005966/04/12/50/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006070/04/12/01/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006174/04/12/03/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006278/04/12/05/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006382/04/12/07/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006486/04/12/09/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006590/04/12/11/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006694/05/12/13/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006798/05/12/15/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 006902/05/12/17/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007006/05/12/19/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007110/05/12/21/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007214/05/12/23/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007318/05/12/25/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007422/05/12/27/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007526/05/12/29/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007630/05/12/31/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007734/05/12/33/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007838/05/12/35/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 007942/05/12/37/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008046/06/12/39/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008150/06/12/41/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008254/06/12/43/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008358/06/12/45/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008462/06/12/47/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008566/06/12/49/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008670/06/12/00/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008774/06/12/02/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008878/06/12/04/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 008982/06/12/06/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009086/06/12/08/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009190/06/12/10/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009294/07/12/12/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009398/07/12/14/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009502/07/12/16/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009606/07/12/18/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009710/07/12/20/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009814/07/12/22/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 009918/07/12/24/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010022/07/12/26/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010126/07/12/28/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010230/07/12/30/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=0) 010334/07/12/32/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000142/00/12/40/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000246/00/12/42/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000350/00/12/44/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000454/00/12/46/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000558/00/12/48/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000662/00/12/50/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000766/00/12/01/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000870/00/12/03/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 000974/00/12/05/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001078/00/12/07/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001182/00/12/09/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001286/00/12/11/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001390/01/12/13/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001494/01/12/15/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001598/01/12/17/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001702/01/12/19/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001806/01/12/21/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 001910/01/12/23/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002014/01/12/25/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002118/01/12/27/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002222/01/12/29/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002326/01/12/31/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002430/01/12/33/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002534/01/12/35/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002638/01/12/37/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002742/02/12/39/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002846/02/12/41/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 002950/02/12/43/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003054/02/12/45/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003158/02/12/47/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003262/02/12/49/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003366/02/12/00/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003470/02/12/02/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003574/02/12/04/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003678/02/12/06/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003782/02/12/08/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003886/02/12/10/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 003990/03/12/12/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004094/03/12/14/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004198/03/12/16/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004302/03/12/18/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004406/03/12/20/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004510/03/12/22/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004614/03/12/24/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004718/03/12/26/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004822/03/12/28/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 004926/03/12/30/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005030/03/12/32/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005134/03/12/34/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005238/03/12/36/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005342/04/12/38/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005446/04/12/40/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005550/04/12/42/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005654/04/12/44/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005758/04/12/46/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005862/04/12/48/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 005966/04/12/50/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006070/04/12/01/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006174/04/12/03/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006278/04/12/05/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006382/04/12/07/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006486/04/12/09/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006590/04/12/11/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006694/05/12/13/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006798/05/12/15/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 006902/05/12/17/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007006/05/12/19/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007110/05/12/21/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007214/05/12/23/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007318/05/12/25/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007422/05/12/27/46 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007526/05/12/29/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007630/05/12/31/50 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007734/05/12/33/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007838/05/12/35/02 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 007942/05/12/37/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008046/06/12/39/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008150/06/12/41/06 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008254/06/12/43/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008358/06/12/45/10 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008462/06/12/47/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008566/06/12/49/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008670/06/12/00/14 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008774/06/12/02/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008878/06/12/04/18 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 008982/06/12/06/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009086/06/12/08/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009190/06/12/10/22 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009294/07/12/12/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009398/07/12/14/26 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009502/07/12/16/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009606/07/12/18/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009710/07/12/20/30 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009814/07/12/22/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 009918/07/12/24/34 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010022/07/12/26/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010126/07/12/28/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010230/07/12/30/38 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=0) 010334/07/12/32/42 meas period end fn_mod:12, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000051/00/25/00/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000155/00/25/02/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000259/00/25/04/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000363/00/25/06/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000467/00/25/08/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000571/00/25/10/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000675/00/25/12/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000779/00/25/14/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000883/00/25/16/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 000987/00/25/18/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001091/00/25/20/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001195/00/25/22/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001299/00/25/24/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001403/01/25/26/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001507/01/25/28/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001611/01/25/30/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001715/01/25/32/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001819/01/25/34/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 001923/01/25/36/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002027/01/25/38/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002131/01/25/40/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002235/01/25/42/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002339/01/25/44/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002443/01/25/46/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002547/01/25/48/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002651/01/25/50/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002755/02/25/01/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002859/02/25/03/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 002963/02/25/05/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003067/02/25/07/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003171/02/25/09/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003275/02/25/11/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003379/02/25/13/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003483/02/25/15/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003587/02/25/17/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003691/02/25/19/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003795/02/25/21/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 003899/02/25/23/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004003/03/25/25/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004107/03/25/27/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004211/03/25/29/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004315/03/25/31/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004419/03/25/33/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004523/03/25/35/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004627/03/25/37/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004731/03/25/39/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004835/03/25/41/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 004939/03/25/43/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005043/03/25/45/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005147/03/25/47/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005251/03/25/49/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005355/04/25/00/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005459/04/25/02/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005563/04/25/04/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005667/04/25/06/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005771/04/25/08/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005875/04/25/10/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 005979/04/25/12/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006083/04/25/14/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006187/04/25/16/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006291/04/25/18/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006395/04/25/20/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006499/04/25/22/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006603/04/25/24/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006707/05/25/26/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006811/05/25/28/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 006915/05/25/30/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007019/05/25/32/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007123/05/25/34/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007227/05/25/36/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007331/05/25/38/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007435/05/25/40/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007539/05/25/42/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007643/05/25/44/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007747/05/25/46/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007851/05/25/48/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 007955/05/25/50/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008059/06/25/01/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008163/06/25/03/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008267/06/25/05/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008371/06/25/07/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008475/06/25/09/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008579/06/25/11/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008683/06/25/13/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008787/06/25/15/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008891/06/25/17/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 008995/06/25/19/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009099/06/25/21/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009203/06/25/23/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009307/07/25/25/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009411/07/25/27/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009515/07/25/29/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009619/07/25/31/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009723/07/25/33/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009827/07/25/35/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 009931/07/25/37/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010035/07/25/39/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010139/07/25/41/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010243/07/25/43/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=2,ss=1) 010347/07/25/45/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000051/00/25/00/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000155/00/25/02/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000259/00/25/04/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000363/00/25/06/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000467/00/25/08/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000571/00/25/10/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000675/00/25/12/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000779/00/25/14/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000883/00/25/16/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 000987/00/25/18/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001091/00/25/20/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001195/00/25/22/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001299/00/25/24/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001403/01/25/26/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001507/01/25/28/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001611/01/25/30/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001715/01/25/32/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001819/01/25/34/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 001923/01/25/36/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002027/01/25/38/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002131/01/25/40/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002235/01/25/42/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002339/01/25/44/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002443/01/25/46/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002547/01/25/48/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002651/01/25/50/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002755/02/25/01/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002859/02/25/03/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 002963/02/25/05/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003067/02/25/07/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003171/02/25/09/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003275/02/25/11/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003379/02/25/13/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003483/02/25/15/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003587/02/25/17/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003691/02/25/19/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003795/02/25/21/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 003899/02/25/23/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004003/03/25/25/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004107/03/25/27/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004211/03/25/29/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004315/03/25/31/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004419/03/25/33/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004523/03/25/35/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004627/03/25/37/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004731/03/25/39/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004835/03/25/41/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 004939/03/25/43/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005043/03/25/45/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005147/03/25/47/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005251/03/25/49/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005355/04/25/00/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005459/04/25/02/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005563/04/25/04/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005667/04/25/06/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005771/04/25/08/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005875/04/25/10/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 005979/04/25/12/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006083/04/25/14/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006187/04/25/16/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006291/04/25/18/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006395/04/25/20/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006499/04/25/22/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006603/04/25/24/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006707/05/25/26/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006811/05/25/28/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 006915/05/25/30/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007019/05/25/32/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007123/05/25/34/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007227/05/25/36/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007331/05/25/38/07 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007435/05/25/40/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007539/05/25/42/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007643/05/25/44/11 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007747/05/25/46/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007851/05/25/48/15 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 007955/05/25/50/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008059/06/25/01/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008163/06/25/03/19 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008267/06/25/05/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008371/06/25/07/23 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008475/06/25/09/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008579/06/25/11/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008683/06/25/13/27 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008787/06/25/15/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008891/06/25/17/31 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 008995/06/25/19/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009099/06/25/21/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009203/06/25/23/35 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009307/07/25/25/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009411/07/25/27/39 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009515/07/25/29/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009619/07/25/31/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009723/07/25/33/43 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009827/07/25/35/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 009931/07/25/37/47 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010035/07/25/39/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010139/07/25/41/51 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010243/07/25/43/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=3,ss=1) 010347/07/25/45/03 meas period end fn_mod:25, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000064/00/12/13/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000168/00/12/15/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000272/00/12/17/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000376/00/12/19/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000480/00/12/21/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000584/00/12/23/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000688/00/12/25/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000792/00/12/27/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 000896/00/12/29/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001000/00/12/31/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001104/00/12/33/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001208/00/12/35/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001312/00/12/37/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001416/01/12/39/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001520/01/12/41/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001624/01/12/43/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001728/01/12/45/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001832/01/12/47/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 001936/01/12/49/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002040/01/12/00/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002144/01/12/02/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002248/01/12/04/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002352/01/12/06/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002456/01/12/08/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002560/01/12/10/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002664/02/12/12/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002768/02/12/14/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002872/02/12/16/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 002976/02/12/18/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003080/02/12/20/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003184/02/12/22/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003288/02/12/24/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003392/02/12/26/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003496/02/12/28/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003600/02/12/30/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003704/02/12/32/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003808/02/12/34/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 003912/02/12/36/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004016/03/12/38/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004120/03/12/40/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004224/03/12/42/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004328/03/12/44/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004432/03/12/46/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004536/03/12/48/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004640/03/12/50/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004744/03/12/01/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004848/03/12/03/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 004952/03/12/05/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005056/03/12/07/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005160/03/12/09/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005264/03/12/11/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005368/04/12/13/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005472/04/12/15/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005576/04/12/17/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005680/04/12/19/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005784/04/12/21/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005888/04/12/23/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 005992/04/12/25/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006096/04/12/27/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006200/04/12/29/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006304/04/12/31/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006408/04/12/33/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006512/04/12/35/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006616/04/12/37/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006720/05/12/39/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006824/05/12/41/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 006928/05/12/43/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007032/05/12/45/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007136/05/12/47/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007240/05/12/49/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007344/05/12/00/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007448/05/12/02/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007552/05/12/04/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007656/05/12/06/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008592/06/12/24/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008696/06/12/26/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008800/06/12/28/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 008904/06/12/30/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009008/06/12/32/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009112/06/12/34/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009216/06/12/36/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009320/07/12/38/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009424/07/12/40/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009528/07/12/42/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009632/07/12/44/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009736/07/12/46/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009840/07/12/48/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 009944/07/12/50/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010048/07/12/01/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010152/07/12/03/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010256/07/12/05/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=0) 010360/07/12/07/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000064/00/12/13/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000168/00/12/15/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000272/00/12/17/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000376/00/12/19/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000480/00/12/21/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000584/00/12/23/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000688/00/12/25/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000792/00/12/27/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 000896/00/12/29/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001000/00/12/31/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001104/00/12/33/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001208/00/12/35/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001312/00/12/37/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001416/01/12/39/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001520/01/12/41/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001624/01/12/43/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001728/01/12/45/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001832/01/12/47/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 001936/01/12/49/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002040/01/12/00/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002144/01/12/02/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002248/01/12/04/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002352/01/12/06/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002456/01/12/08/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002560/01/12/10/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002664/02/12/12/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002768/02/12/14/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002872/02/12/16/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 002976/02/12/18/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003080/02/12/20/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003184/02/12/22/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003288/02/12/24/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003392/02/12/26/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003496/02/12/28/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003600/02/12/30/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003704/02/12/32/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003808/02/12/34/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 003912/02/12/36/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004016/03/12/38/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004120/03/12/40/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004224/03/12/42/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004328/03/12/44/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004432/03/12/46/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004536/03/12/48/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004640/03/12/50/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004744/03/12/01/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004848/03/12/03/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 004952/03/12/05/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005056/03/12/07/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005160/03/12/09/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005264/03/12/11/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005368/04/12/13/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005472/04/12/15/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005576/04/12/17/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005680/04/12/19/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005784/04/12/21/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005888/04/12/23/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 005992/04/12/25/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006096/04/12/27/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006200/04/12/29/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006304/04/12/31/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006408/04/12/33/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006512/04/12/35/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006616/04/12/37/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006720/05/12/39/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006824/05/12/41/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 006928/05/12/43/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007032/05/12/45/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007136/05/12/47/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007240/05/12/49/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007344/05/12/00/20 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007448/05/12/02/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007552/05/12/04/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007656/05/12/06/24 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007760/05/12/08/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007864/05/12/10/28 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 007968/06/12/12/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008072/06/12/14/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008176/06/12/16/32 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008280/06/12/18/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008384/06/12/20/36 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008488/06/12/22/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008592/06/12/24/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008696/06/12/26/40 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008800/06/12/28/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 008904/06/12/30/44 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009008/06/12/32/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009112/06/12/34/48 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009216/06/12/36/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009320/07/12/38/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009424/07/12/40/00 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009528/07/12/42/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009632/07/12/44/04 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009736/07/12/46/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009840/07/12/48/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 009944/07/12/50/08 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010048/07/12/01/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010152/07/12/03/12 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010256/07/12/05/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=0) 010360/07/12/07/16 meas period end fn_mod:38, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000077/00/25/26/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000181/00/25/28/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000285/00/25/30/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000389/00/25/32/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000493/00/25/34/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000597/00/25/36/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000701/00/25/38/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000805/00/25/40/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 000909/00/25/42/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001013/00/25/44/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001117/00/25/46/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001221/00/25/48/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001325/00/25/50/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001429/01/25/01/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001533/01/25/03/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001637/01/25/05/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001741/01/25/07/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001845/01/25/09/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 001949/01/25/11/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002053/01/25/13/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002157/01/25/15/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002261/01/25/17/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002365/01/25/19/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002469/01/25/21/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002573/01/25/23/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002677/02/25/25/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002781/02/25/27/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002885/02/25/29/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 002989/02/25/31/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003093/02/25/33/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003197/02/25/35/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003301/02/25/37/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003405/02/25/39/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003509/02/25/41/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003613/02/25/43/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003717/02/25/45/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003821/02/25/47/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 003925/02/25/49/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004029/03/25/00/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004133/03/25/02/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004237/03/25/04/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004341/03/25/06/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004445/03/25/08/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004549/03/25/10/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004653/03/25/12/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004757/03/25/14/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004861/03/25/16/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 004965/03/25/18/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005069/03/25/20/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005173/03/25/22/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005277/03/25/24/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005381/04/25/26/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005485/04/25/28/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005589/04/25/30/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005693/04/25/32/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005797/04/25/34/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 005901/04/25/36/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006005/04/25/38/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006109/04/25/40/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006213/04/25/42/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006317/04/25/44/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006421/04/25/46/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006525/04/25/48/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006629/04/25/50/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006733/05/25/01/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006837/05/25/03/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 006941/05/25/05/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007045/05/25/07/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007149/05/25/09/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007253/05/25/11/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007357/05/25/13/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007461/05/25/15/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007565/05/25/17/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007669/05/25/19/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007773/05/25/21/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007877/05/25/23/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 007981/06/25/25/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008085/06/25/27/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008605/06/25/37/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008709/06/25/39/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008813/06/25/41/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 008917/06/25/43/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009021/06/25/45/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009125/06/25/47/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009229/06/25/49/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009333/07/25/00/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009437/07/25/02/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009541/07/25/04/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009645/07/25/06/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009749/07/25/08/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009853/07/25/10/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 009957/07/25/12/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010061/07/25/14/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010165/07/25/16/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010269/07/25/18/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=4,ss=1) 010373/07/25/20/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000077/00/25/26/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000181/00/25/28/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000285/00/25/30/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000389/00/25/32/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000493/00/25/34/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000597/00/25/36/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000701/00/25/38/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000805/00/25/40/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 000909/00/25/42/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001013/00/25/44/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001117/00/25/46/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001221/00/25/48/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001325/00/25/50/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001429/01/25/01/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001533/01/25/03/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001637/01/25/05/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001741/01/25/07/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001845/01/25/09/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 001949/01/25/11/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002053/01/25/13/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002157/01/25/15/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002261/01/25/17/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002365/01/25/19/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002469/01/25/21/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002573/01/25/23/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002677/02/25/25/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002781/02/25/27/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002885/02/25/29/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 002989/02/25/31/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003093/02/25/33/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003197/02/25/35/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003301/02/25/37/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003405/02/25/39/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003509/02/25/41/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003613/02/25/43/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003717/02/25/45/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003821/02/25/47/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 003925/02/25/49/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004029/03/25/00/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004133/03/25/02/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004237/03/25/04/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004341/03/25/06/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004445/03/25/08/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004549/03/25/10/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004653/03/25/12/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004757/03/25/14/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004861/03/25/16/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 004965/03/25/18/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005069/03/25/20/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005173/03/25/22/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005277/03/25/24/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005381/04/25/26/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005485/04/25/28/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005589/04/25/30/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005693/04/25/32/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005797/04/25/34/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 005901/04/25/36/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006005/04/25/38/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006109/04/25/40/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006213/04/25/42/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006317/04/25/44/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006421/04/25/46/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006525/04/25/48/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006629/04/25/50/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006733/05/25/01/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006837/05/25/03/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 006941/05/25/05/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007045/05/25/07/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007149/05/25/09/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007253/05/25/11/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007357/05/25/13/33 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007461/05/25/15/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007565/05/25/17/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007669/05/25/19/37 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007773/05/25/21/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007877/05/25/23/41 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 007981/06/25/25/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008085/06/25/27/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008189/06/25/29/45 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008293/06/25/31/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008397/06/25/33/49 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008501/06/25/35/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008605/06/25/37/01 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008709/06/25/39/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008813/06/25/41/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 008917/06/25/43/05 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009021/06/25/45/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009125/06/25/47/09 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009229/06/25/49/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009333/07/25/00/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009437/07/25/02/13 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009541/07/25/04/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009645/07/25/06/17 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009749/07/25/08/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009853/07/25/10/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 009957/07/25/12/21 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 010061/07/25/14/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 010165/07/25/16/25 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 010269/07/25/18/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=5,ss=1) 010373/07/25/20/29 meas period end fn_mod:51, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000090/00/12/39/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000194/00/12/41/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000298/00/12/43/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000402/00/12/45/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000506/00/12/47/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000610/00/12/49/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000714/00/12/00/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000818/00/12/02/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 000922/00/12/04/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001026/00/12/06/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001130/00/12/08/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001234/00/12/10/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001338/01/12/12/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001442/01/12/14/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001546/01/12/16/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001650/01/12/18/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001754/01/12/20/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001858/01/12/22/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 001962/01/12/24/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002066/01/12/26/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002170/01/12/28/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002274/01/12/30/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002378/01/12/32/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002482/01/12/34/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002586/01/12/36/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002690/02/12/38/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002794/02/12/40/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 002898/02/12/42/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003002/02/12/44/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003106/02/12/46/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003210/02/12/48/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003314/02/12/50/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003418/02/12/01/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003522/02/12/03/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003626/02/12/05/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003730/02/12/07/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003834/02/12/09/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 003938/02/12/11/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004042/03/12/13/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004146/03/12/15/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004250/03/12/17/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004354/03/12/19/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004458/03/12/21/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004562/03/12/23/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004666/03/12/25/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004770/03/12/27/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004874/03/12/29/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 004978/03/12/31/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005082/03/12/33/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005186/03/12/35/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005290/03/12/37/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005394/04/12/39/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005498/04/12/41/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005602/04/12/43/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005706/04/12/45/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005810/04/12/47/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 005914/04/12/49/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006018/04/12/00/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006122/04/12/02/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006226/04/12/04/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006330/04/12/06/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006434/04/12/08/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006538/04/12/10/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006642/05/12/12/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006746/05/12/14/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006850/05/12/16/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 006954/05/12/18/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007058/05/12/20/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007162/05/12/22/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007266/05/12/24/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007370/05/12/26/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007474/05/12/28/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007578/05/12/30/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007682/05/12/32/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007786/05/12/34/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007890/05/12/36/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 007994/06/12/38/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008098/06/12/40/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008202/06/12/42/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008306/06/12/44/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008410/06/12/46/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008514/06/12/48/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008618/06/12/50/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008722/06/12/01/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008826/06/12/03/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 008930/06/12/05/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009034/06/12/07/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009138/06/12/09/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009242/06/12/11/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009346/07/12/13/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009450/07/12/15/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009554/07/12/17/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009658/07/12/19/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009762/07/12/21/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009866/07/12/23/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 009970/07/12/25/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010074/07/12/27/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010178/07/12/29/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010282/07/12/31/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=0) 010386/07/12/33/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000090/00/12/39/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000194/00/12/41/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000298/00/12/43/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000402/00/12/45/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000506/00/12/47/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000610/00/12/49/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000714/00/12/00/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000818/00/12/02/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 000922/00/12/04/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001026/00/12/06/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001130/00/12/08/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001234/00/12/10/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001338/01/12/12/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001442/01/12/14/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001546/01/12/16/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001650/01/12/18/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001754/01/12/20/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001858/01/12/22/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 001962/01/12/24/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002066/01/12/26/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002170/01/12/28/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002274/01/12/30/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002378/01/12/32/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002482/01/12/34/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002586/01/12/36/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002690/02/12/38/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002794/02/12/40/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 002898/02/12/42/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003002/02/12/44/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003106/02/12/46/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003210/02/12/48/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003314/02/12/50/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003418/02/12/01/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003522/02/12/03/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003626/02/12/05/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003730/02/12/07/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003834/02/12/09/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 003938/02/12/11/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004042/03/12/13/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004146/03/12/15/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004250/03/12/17/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004354/03/12/19/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004458/03/12/21/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004562/03/12/23/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004666/03/12/25/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004770/03/12/27/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004874/03/12/29/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 004978/03/12/31/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005082/03/12/33/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005186/03/12/35/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005290/03/12/37/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005394/04/12/39/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005498/04/12/41/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005602/04/12/43/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005706/04/12/45/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005810/04/12/47/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 005914/04/12/49/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006018/04/12/00/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006122/04/12/02/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006226/04/12/04/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006330/04/12/06/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006434/04/12/08/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006538/04/12/10/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006642/05/12/12/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006746/05/12/14/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006850/05/12/16/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 006954/05/12/18/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007058/05/12/20/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007162/05/12/22/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007266/05/12/24/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007370/05/12/26/46 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007474/05/12/28/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007578/05/12/30/50 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007682/05/12/32/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007786/05/12/34/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007890/05/12/36/02 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 007994/06/12/38/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008098/06/12/40/06 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008202/06/12/42/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008306/06/12/44/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008410/06/12/46/10 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008514/06/12/48/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008618/06/12/50/14 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008722/06/12/01/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008826/06/12/03/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 008930/06/12/05/18 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009034/06/12/07/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009138/06/12/09/22 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009242/06/12/11/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009346/07/12/13/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009450/07/12/15/26 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009554/07/12/17/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009658/07/12/19/30 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009762/07/12/21/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009866/07/12/23/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 009970/07/12/25/34 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010074/07/12/27/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010178/07/12/29/38 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010282/07/12/31/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=0) 010386/07/12/33/42 meas period end fn_mod:64, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000103/00/25/01/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000207/00/25/03/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000311/00/25/05/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000415/00/25/07/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000519/00/25/09/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000623/00/25/11/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000727/00/25/13/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000831/00/25/15/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 000935/00/25/17/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001039/00/25/19/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001143/00/25/21/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001247/00/25/23/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001351/01/25/25/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001455/01/25/27/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001559/01/25/29/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001663/01/25/31/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001767/01/25/33/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001871/01/25/35/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 001975/01/25/37/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002079/01/25/39/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002183/01/25/41/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002287/01/25/43/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002391/01/25/45/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002495/01/25/47/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002599/01/25/49/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002703/02/25/00/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002807/02/25/02/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 002911/02/25/04/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003015/02/25/06/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003119/02/25/08/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003223/02/25/10/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003327/02/25/12/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003431/02/25/14/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003535/02/25/16/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003639/02/25/18/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003743/02/25/20/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003847/02/25/22/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 003951/02/25/24/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004055/03/25/26/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004159/03/25/28/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004263/03/25/30/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004367/03/25/32/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004471/03/25/34/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004575/03/25/36/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004679/03/25/38/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004783/03/25/40/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004887/03/25/42/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 004991/03/25/44/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005095/03/25/46/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005199/03/25/48/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005303/03/25/50/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005407/04/25/01/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005511/04/25/03/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005615/04/25/05/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005719/04/25/07/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005823/04/25/09/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 005927/04/25/11/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006031/04/25/13/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006135/04/25/15/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006239/04/25/17/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006343/04/25/19/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006447/04/25/21/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006551/04/25/23/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006655/05/25/25/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006759/05/25/27/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006863/05/25/29/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 006967/05/25/31/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007071/05/25/33/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007175/05/25/35/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007279/05/25/37/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007383/05/25/39/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007487/05/25/41/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007591/05/25/43/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007695/05/25/45/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007799/05/25/47/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 007903/05/25/49/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008007/06/25/00/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008111/06/25/02/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008215/06/25/04/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008319/06/25/06/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008423/06/25/08/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008527/06/25/10/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008631/06/25/12/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008735/06/25/14/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008839/06/25/16/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 008943/06/25/18/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009047/06/25/20/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009151/06/25/22/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009255/06/25/24/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009359/07/25/26/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009463/07/25/28/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009567/07/25/30/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009671/07/25/32/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009775/07/25/34/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009879/07/25/36/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 009983/07/25/38/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010087/07/25/40/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010191/07/25/42/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010295/07/25/44/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=6,ss=1) 010399/07/25/46/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000103/00/25/01/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000207/00/25/03/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000311/00/25/05/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000415/00/25/07/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000519/00/25/09/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000623/00/25/11/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000727/00/25/13/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000831/00/25/15/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 000935/00/25/17/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001039/00/25/19/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001143/00/25/21/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001247/00/25/23/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001351/01/25/25/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001455/01/25/27/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001559/01/25/29/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001663/01/25/31/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001767/01/25/33/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001871/01/25/35/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 001975/01/25/37/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002079/01/25/39/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002183/01/25/41/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002287/01/25/43/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002391/01/25/45/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002495/01/25/47/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002599/01/25/49/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002703/02/25/00/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002807/02/25/02/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 002911/02/25/04/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003015/02/25/06/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003119/02/25/08/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003223/02/25/10/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003327/02/25/12/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003431/02/25/14/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003535/02/25/16/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003639/02/25/18/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003743/02/25/20/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003847/02/25/22/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 003951/02/25/24/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004055/03/25/26/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004159/03/25/28/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004263/03/25/30/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004367/03/25/32/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004471/03/25/34/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004575/03/25/36/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004679/03/25/38/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004783/03/25/40/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004887/03/25/42/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 004991/03/25/44/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005095/03/25/46/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005199/03/25/48/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005303/03/25/50/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005407/04/25/01/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005511/04/25/03/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005615/04/25/05/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005719/04/25/07/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005823/04/25/09/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 005927/04/25/11/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006031/04/25/13/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006135/04/25/15/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006239/04/25/17/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006343/04/25/19/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006447/04/25/21/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006551/04/25/23/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006655/05/25/25/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006759/05/25/27/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006863/05/25/29/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 006967/05/25/31/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007071/05/25/33/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007175/05/25/35/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007279/05/25/37/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007383/05/25/39/07 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007487/05/25/41/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007591/05/25/43/11 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007695/05/25/45/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007799/05/25/47/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 007903/05/25/49/15 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008007/06/25/00/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008111/06/25/02/19 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008215/06/25/04/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008319/06/25/06/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008423/06/25/08/23 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008527/06/25/10/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008631/06/25/12/27 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008735/06/25/14/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008839/06/25/16/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 008943/06/25/18/31 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009047/06/25/20/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009151/06/25/22/35 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009255/06/25/24/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009359/07/25/26/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009463/07/25/28/39 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009567/07/25/30/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009671/07/25/32/43 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009775/07/25/34/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009879/07/25/36/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 009983/07/25/38/47 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 010087/07/25/40/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 010191/07/25/42/51 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 010295/07/25/44/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=7,ss=1) 010399/07/25/46/03 meas period end fn_mod:77, status:1, pchan:TCH/H
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000066/00/14/15/14 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000168/00/12/15/12 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000270/00/10/15/14 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000372/00/08/15/12 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000474/00/06/15/10 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000576/00/04/15/12 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000678/00/02/15/10 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000780/00/00/15/12 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000882/00/24/15/10 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000984/00/22/15/08 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001086/00/20/15/10 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001188/00/18/15/08 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001290/00/16/15/10 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001392/01/14/15/08 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001494/01/12/15/06 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001596/01/10/15/08 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001698/01/08/15/06 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001800/01/06/15/08 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001902/01/04/15/06 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002004/01/02/15/04 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002106/01/00/15/06 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002208/01/24/15/04 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002310/01/22/15/06 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002412/01/20/15/04 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002514/01/18/15/02 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002616/01/16/15/04 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002718/02/14/15/02 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002820/02/12/15/04 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002922/02/10/15/02 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003024/02/08/15/00 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003126/02/06/15/02 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003228/02/04/15/00 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003330/02/02/15/02 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003432/02/00/15/00 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003534/02/24/15/50 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003636/02/22/15/00 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003738/02/20/15/50 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003840/02/18/15/00 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003942/02/16/15/50 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004044/03/14/15/48 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004146/03/12/15/50 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004248/03/10/15/48 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004350/03/08/15/46 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004452/03/06/15/48 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004554/03/04/15/46 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004656/03/02/15/48 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004758/03/00/15/46 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004860/03/24/15/44 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004962/03/22/15/46 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005064/03/20/15/44 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005166/03/18/15/46 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005268/03/16/15/44 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005370/04/14/15/42 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005472/04/12/15/44 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005574/04/10/15/42 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005676/04/08/15/44 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005778/04/06/15/42 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005880/04/04/15/40 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005982/04/02/15/42 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006084/04/00/15/40 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006186/04/24/15/42 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006288/04/22/15/40 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006390/04/20/15/38 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006492/04/18/15/40 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006594/04/16/15/38 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006696/05/14/15/40 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006798/05/12/15/38 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006900/05/10/15/36 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007002/05/08/15/38 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007104/05/06/15/36 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007206/05/04/15/38 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007308/05/02/15/36 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007410/05/00/15/34 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007512/05/24/15/36 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007614/05/22/15/34 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007716/05/20/15/36 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007818/05/18/15/34 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007920/05/16/15/32 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008022/06/14/15/34 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008124/06/12/15/32 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008226/06/10/15/34 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008328/06/08/15/32 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008430/06/06/15/30 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008532/06/04/15/32 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008634/06/02/15/30 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008736/06/00/15/32 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008838/06/24/15/30 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008940/06/22/15/28 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009042/06/20/15/30 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009144/06/18/15/28 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009246/06/16/15/30 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009348/07/14/15/28 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009450/07/12/15/26 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009552/07/10/15/28 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009654/07/08/15/26 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009756/07/06/15/28 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009858/07/04/15/26 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009960/07/02/15/24 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010062/07/00/15/26 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010164/07/24/15/24 meas period end fn_mod:66, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000070/00/18/19/18 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000172/00/16/19/16 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000274/00/14/19/18 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000376/00/12/19/16 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000478/00/10/19/14 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000580/00/08/19/16 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000682/00/06/19/14 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000784/00/04/19/16 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000886/00/02/19/14 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000988/00/00/19/12 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001090/00/24/19/14 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001192/00/22/19/12 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001294/00/20/19/14 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001396/01/18/19/12 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001498/01/16/19/10 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001600/01/14/19/12 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001702/01/12/19/10 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001804/01/10/19/12 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001906/01/08/19/10 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002008/01/06/19/08 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002110/01/04/19/10 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002212/01/02/19/08 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002314/01/00/19/10 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002416/01/24/19/08 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002518/01/22/19/06 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002620/01/20/19/08 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002722/02/18/19/06 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002824/02/16/19/08 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002926/02/14/19/06 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003028/02/12/19/04 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003130/02/10/19/06 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003232/02/08/19/04 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003334/02/06/19/06 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003436/02/04/19/04 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003538/02/02/19/02 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003640/02/00/19/04 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003742/02/24/19/02 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003844/02/22/19/04 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003946/02/20/19/02 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004048/03/18/19/00 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004150/03/16/19/02 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004252/03/14/19/00 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004354/03/12/19/02 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004456/03/10/19/00 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004558/03/08/19/50 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004660/03/06/19/00 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004762/03/04/19/50 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004864/03/02/19/00 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004966/03/00/19/50 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005068/03/24/19/48 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005170/03/22/19/50 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005272/03/20/19/48 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005374/04/18/19/46 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005476/04/16/19/48 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005578/04/14/19/46 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005680/04/12/19/48 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005782/04/10/19/46 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005884/04/08/19/44 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005986/04/06/19/46 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006088/04/04/19/44 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006190/04/02/19/46 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006292/04/00/19/44 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006394/04/24/19/42 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006496/04/22/19/44 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006598/04/20/19/42 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006700/05/18/19/44 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006802/05/16/19/42 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006904/05/14/19/40 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007006/05/12/19/42 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007108/05/10/19/40 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007210/05/08/19/42 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007312/05/06/19/40 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007414/05/04/19/38 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007516/05/02/19/40 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007618/05/00/19/38 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007720/05/24/19/40 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007822/05/22/19/38 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007924/05/20/19/36 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008026/06/18/19/38 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008128/06/16/19/36 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008230/06/14/19/38 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008332/06/12/19/36 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008434/06/10/19/34 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008536/06/08/19/36 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008638/06/06/19/34 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008740/06/04/19/36 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008842/06/02/19/34 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008944/06/00/19/32 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009046/06/24/19/34 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009148/06/22/19/32 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009250/06/20/19/34 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009352/07/18/19/32 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009454/07/16/19/30 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009556/07/14/19/32 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009658/07/12/19/30 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009760/07/10/19/32 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009862/07/08/19/30 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009964/07/06/19/28 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010066/07/04/19/30 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010168/07/02/19/28 meas period end fn_mod:70, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000074/00/22/23/22 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000176/00/20/23/20 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000278/00/18/23/22 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000380/00/16/23/20 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000482/00/14/23/18 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000584/00/12/23/20 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000686/00/10/23/18 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000788/00/08/23/20 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000890/00/06/23/18 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000992/00/04/23/16 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001094/00/02/23/18 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001196/00/00/23/16 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001298/00/24/23/18 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001400/01/22/23/16 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001502/01/20/23/14 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001604/01/18/23/16 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001706/01/16/23/14 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001808/01/14/23/16 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001910/01/12/23/14 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002012/01/10/23/12 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002114/01/08/23/14 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002216/01/06/23/12 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002318/01/04/23/14 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002420/01/02/23/12 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002522/01/00/23/10 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002624/01/24/23/12 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002726/02/22/23/10 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002828/02/20/23/12 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002930/02/18/23/10 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003032/02/16/23/08 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003134/02/14/23/10 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003236/02/12/23/08 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003338/02/10/23/10 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003440/02/08/23/08 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003542/02/06/23/06 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003644/02/04/23/08 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003746/02/02/23/06 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003848/02/00/23/08 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003950/02/24/23/06 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004052/03/22/23/04 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004154/03/20/23/06 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004256/03/18/23/04 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004358/03/16/23/06 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004460/03/14/23/04 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004562/03/12/23/02 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004664/03/10/23/04 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004766/03/08/23/02 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004868/03/06/23/04 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004970/03/04/23/02 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005072/03/02/23/00 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005174/03/00/23/02 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005276/03/24/23/00 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005378/04/22/23/02 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005480/04/20/23/00 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005582/04/18/23/50 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005684/04/16/23/00 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005786/04/14/23/50 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005888/04/12/23/00 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005990/04/10/23/50 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006092/04/08/23/48 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006194/04/06/23/50 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006296/04/04/23/48 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006398/04/02/23/46 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006500/04/00/23/48 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006602/04/24/23/46 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006704/05/22/23/48 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006806/05/20/23/46 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006908/05/18/23/44 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007010/05/16/23/46 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007112/05/14/23/44 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007214/05/12/23/46 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007316/05/10/23/44 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007418/05/08/23/42 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007520/05/06/23/44 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007622/05/04/23/42 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007724/05/02/23/44 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007826/05/00/23/42 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007928/05/24/23/40 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008030/06/22/23/42 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008132/06/20/23/40 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008234/06/18/23/42 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008336/06/16/23/40 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008438/06/14/23/38 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008540/06/12/23/40 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008642/06/10/23/38 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008744/06/08/23/40 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008846/06/06/23/38 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008948/06/04/23/36 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009050/06/02/23/38 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009152/06/00/23/36 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009254/06/24/23/38 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009356/07/22/23/36 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009458/07/20/23/34 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009560/07/18/23/36 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009662/07/16/23/34 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009764/07/14/23/36 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009866/07/12/23/34 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009968/07/10/23/32 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 010070/07/08/23/34 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=2) 010172/07/06/23/32 meas period end fn_mod:74, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000078/00/00/27/26 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000180/00/24/27/24 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000282/00/22/27/26 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000384/00/20/27/24 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000486/00/18/27/22 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000588/00/16/27/24 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000690/00/14/27/22 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000792/00/12/27/24 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000894/00/10/27/22 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000996/00/08/27/20 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001098/00/06/27/22 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001200/00/04/27/20 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001302/00/02/27/22 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001404/01/00/27/20 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001506/01/24/27/18 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001608/01/22/27/20 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001710/01/20/27/18 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001812/01/18/27/20 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001914/01/16/27/18 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002016/01/14/27/16 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002118/01/12/27/18 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002220/01/10/27/16 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002322/01/08/27/18 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002424/01/06/27/16 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002526/01/04/27/14 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002628/01/02/27/16 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002730/02/00/27/14 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002832/02/24/27/16 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002934/02/22/27/14 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003036/02/20/27/12 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003138/02/18/27/14 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003240/02/16/27/12 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003342/02/14/27/14 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003444/02/12/27/12 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003546/02/10/27/10 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003648/02/08/27/12 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003750/02/06/27/10 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003852/02/04/27/12 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003954/02/02/27/10 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004056/03/00/27/08 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004158/03/24/27/10 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004260/03/22/27/08 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004362/03/20/27/10 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004464/03/18/27/08 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004566/03/16/27/06 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004668/03/14/27/08 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004770/03/12/27/06 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004872/03/10/27/08 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004974/03/08/27/06 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005076/03/06/27/04 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005178/03/04/27/06 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005280/03/02/27/04 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005382/04/00/27/06 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005484/04/24/27/04 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005586/04/22/27/02 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005688/04/20/27/04 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005790/04/18/27/02 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005892/04/16/27/04 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005994/04/14/27/02 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006096/04/12/27/00 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006198/04/10/27/02 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006300/04/08/27/00 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006402/04/06/27/02 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006504/04/04/27/00 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006606/04/02/27/50 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006708/05/00/27/00 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006810/05/24/27/50 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006912/05/22/27/00 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007014/05/20/27/50 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007116/05/18/27/48 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007218/05/16/27/50 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007320/05/14/27/48 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007422/05/12/27/46 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007524/05/10/27/48 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007626/05/08/27/46 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007728/05/06/27/48 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007830/05/04/27/46 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007932/05/02/27/44 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008034/06/00/27/46 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008136/06/24/27/44 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008238/06/22/27/46 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008340/06/20/27/44 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008442/06/18/27/42 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008544/06/16/27/44 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008646/06/14/27/42 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008748/06/12/27/44 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008850/06/10/27/42 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008952/06/08/27/40 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009054/06/06/27/42 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009156/06/04/27/40 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009258/06/02/27/42 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009360/07/00/27/40 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009462/07/24/27/38 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009564/07/22/27/40 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009666/07/20/27/38 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009768/07/18/27/40 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009870/07/16/27/38 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009972/07/14/27/36 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 010074/07/12/27/38 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=3) 010176/07/10/27/36 meas period end fn_mod:78, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000098/00/20/47/46 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000200/00/18/47/44 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000302/00/16/47/46 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000404/00/14/47/44 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000506/00/12/47/42 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000608/00/10/47/44 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000710/00/08/47/42 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000812/00/06/47/44 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 000914/00/04/47/42 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001016/00/02/47/40 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001118/00/00/47/42 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001220/00/24/47/40 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001322/00/22/47/42 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001424/01/20/47/40 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001526/01/18/47/38 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001628/01/16/47/40 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001730/01/14/47/38 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001832/01/12/47/40 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 001934/01/10/47/38 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002036/01/08/47/36 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002138/01/06/47/38 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002240/01/04/47/36 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002342/01/02/47/38 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002444/01/00/47/36 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002546/01/24/47/34 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002648/01/22/47/36 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002750/02/20/47/34 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002852/02/18/47/36 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 002954/02/16/47/34 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003056/02/14/47/32 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003158/02/12/47/34 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003260/02/10/47/32 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003362/02/08/47/34 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003464/02/06/47/32 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003566/02/04/47/30 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003668/02/02/47/32 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003770/02/00/47/30 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003872/02/24/47/32 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 003974/02/22/47/30 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004076/03/20/47/28 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004178/03/18/47/30 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004280/03/16/47/28 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004382/03/14/47/30 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004484/03/12/47/28 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004586/03/10/47/26 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004688/03/08/47/28 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004790/03/06/47/26 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004892/03/04/47/28 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 004994/03/02/47/26 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005096/03/00/47/24 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005198/03/24/47/26 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005300/03/22/47/24 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005402/04/20/47/26 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005504/04/18/47/24 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005606/04/16/47/22 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005708/04/14/47/24 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005810/04/12/47/22 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 005912/04/10/47/24 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006014/04/08/47/22 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006116/04/06/47/20 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006218/04/04/47/22 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006320/04/02/47/20 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006422/04/00/47/22 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006524/04/24/47/20 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006626/04/22/47/18 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006728/05/20/47/20 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006830/05/18/47/18 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 006932/05/16/47/20 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007034/05/14/47/18 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007136/05/12/47/16 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007238/05/10/47/18 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007340/05/08/47/16 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007442/05/06/47/18 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007544/05/04/47/16 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007646/05/02/47/14 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007748/05/00/47/16 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007850/05/24/47/14 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 007952/05/22/47/16 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008054/06/20/47/14 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008156/06/18/47/12 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008258/06/16/47/14 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008360/06/14/47/12 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008462/06/12/47/14 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008564/06/10/47/12 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008666/06/08/47/10 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008768/06/06/47/12 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008870/06/04/47/10 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 008972/06/02/47/12 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009074/06/00/47/10 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009176/06/24/47/08 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009278/06/22/47/10 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009380/07/20/47/08 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009482/07/18/47/10 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009584/07/16/47/08 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009686/07/14/47/06 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009788/07/12/47/08 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009890/07/10/47/06 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 009992/07/08/47/08 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 010094/07/06/47/06 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=4) 010196/07/04/47/04 meas period end fn_mod:98, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000000/00/00/00/00 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000102/00/24/00/50 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000204/00/22/00/48 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000306/00/20/00/50 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000408/00/18/00/48 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000510/00/16/00/46 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000612/00/14/00/48 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000714/00/12/00/46 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000816/00/10/00/48 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 000918/00/08/00/46 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001020/00/06/00/44 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001122/00/04/00/46 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001224/00/02/00/44 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001326/01/00/00/46 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001428/01/24/00/44 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001530/01/22/00/42 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001632/01/20/00/44 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001734/01/18/00/42 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001836/01/16/00/44 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 001938/01/14/00/42 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002040/01/12/00/40 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002142/01/10/00/42 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002244/01/08/00/40 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002346/01/06/00/42 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002448/01/04/00/40 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002550/01/02/00/38 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002652/02/00/00/40 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002754/02/24/00/38 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002856/02/22/00/40 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 002958/02/20/00/38 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003060/02/18/00/36 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003162/02/16/00/38 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003264/02/14/00/36 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003366/02/12/00/38 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003468/02/10/00/36 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003570/02/08/00/34 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003672/02/06/00/36 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003774/02/04/00/34 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003876/02/02/00/36 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 003978/03/00/00/34 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004080/03/24/00/32 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004182/03/22/00/34 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004284/03/20/00/32 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004386/03/18/00/34 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004488/03/16/00/32 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004590/03/14/00/30 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004692/03/12/00/32 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004794/03/10/00/30 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004896/03/08/00/32 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 004998/03/06/00/30 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005100/03/04/00/28 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005202/03/02/00/30 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005304/04/00/00/28 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005406/04/24/00/30 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005508/04/22/00/28 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005610/04/20/00/26 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005712/04/18/00/28 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005814/04/16/00/26 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 005916/04/14/00/28 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006018/04/12/00/26 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006120/04/10/00/24 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006222/04/08/00/26 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006324/04/06/00/24 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006426/04/04/00/26 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006528/04/02/00/24 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006630/05/00/00/22 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006732/05/24/00/24 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006834/05/22/00/22 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 006936/05/20/00/24 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007038/05/18/00/22 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007140/05/16/00/20 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007242/05/14/00/22 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007344/05/12/00/20 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007446/05/10/00/22 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007548/05/08/00/20 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007650/05/06/00/18 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007752/05/04/00/20 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007854/05/02/00/18 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 007956/06/00/00/20 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008058/06/24/00/18 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008160/06/22/00/16 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008262/06/20/00/18 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008364/06/18/00/16 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008466/06/16/00/18 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008568/06/14/00/16 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008670/06/12/00/14 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008772/06/10/00/16 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008874/06/08/00/14 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 008976/06/06/00/16 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009078/06/04/00/14 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009180/06/02/00/12 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009282/07/00/00/14 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009384/07/24/00/12 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009486/07/22/00/14 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009588/07/20/00/12 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009690/07/18/00/10 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009792/07/16/00/12 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009894/07/14/00/10 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 009996/07/12/00/12 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=5) 010098/07/10/00/10 meas period end fn_mod:0, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000004/00/04/04/04 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000106/00/02/04/02 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000208/00/00/04/00 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000310/00/24/04/02 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000412/00/22/04/00 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000514/00/20/04/02 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000616/00/18/04/00 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000718/00/16/04/50 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000820/00/14/04/00 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 000922/00/12/04/50 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001024/00/10/04/00 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001126/00/08/04/50 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001228/00/06/04/48 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001330/01/04/04/50 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001432/01/02/04/48 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001534/01/00/04/46 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001636/01/24/04/48 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001738/01/22/04/46 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001840/01/20/04/48 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 001942/01/18/04/46 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002044/01/16/04/44 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002146/01/14/04/46 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002248/01/12/04/44 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002350/01/10/04/46 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002452/01/08/04/44 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002554/01/06/04/42 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002656/02/04/04/44 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002758/02/02/04/42 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002860/02/00/04/44 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 002962/02/24/04/42 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003064/02/22/04/40 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003166/02/20/04/42 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003268/02/18/04/40 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003370/02/16/04/42 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003472/02/14/04/40 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003574/02/12/04/38 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003676/02/10/04/40 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003778/02/08/04/38 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003880/02/06/04/40 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 003982/03/04/04/38 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004084/03/02/04/36 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004186/03/00/04/38 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004288/03/24/04/36 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004390/03/22/04/38 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004492/03/20/04/36 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004594/03/18/04/34 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004696/03/16/04/36 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004798/03/14/04/34 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 004900/03/12/04/36 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005002/03/10/04/34 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005104/03/08/04/32 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005206/03/06/04/34 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005308/04/04/04/32 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005410/04/02/04/34 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005512/04/00/04/32 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005614/04/24/04/30 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005716/04/22/04/32 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005818/04/20/04/30 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 005920/04/18/04/32 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006022/04/16/04/30 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006124/04/14/04/28 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006226/04/12/04/30 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006328/04/10/04/28 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006430/04/08/04/30 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006532/04/06/04/28 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006634/05/04/04/26 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006736/05/02/04/28 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006838/05/00/04/26 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 006940/05/24/04/28 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007042/05/22/04/26 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007144/05/20/04/24 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007246/05/18/04/26 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007348/05/16/04/24 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007450/05/14/04/26 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007552/05/12/04/24 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007654/05/10/04/22 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007756/05/08/04/24 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007858/05/06/04/22 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 007960/06/04/04/24 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008062/06/02/04/22 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008164/06/00/04/20 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008266/06/24/04/22 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008368/06/22/04/20 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008470/06/20/04/22 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008572/06/18/04/20 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008674/06/16/04/18 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008776/06/14/04/20 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008878/06/12/04/18 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 008980/06/10/04/20 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009082/06/08/04/18 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009184/06/06/04/16 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009286/07/04/04/18 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009388/07/02/04/16 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009490/07/00/04/18 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009592/07/24/04/16 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009694/07/22/04/14 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009796/07/20/04/16 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 009898/07/18/04/14 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 010000/07/16/04/16 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=6) 010102/07/14/04/14 meas period end fn_mod:4, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000008/00/08/08/08 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000110/00/06/08/06 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000212/00/04/08/04 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000314/00/02/08/06 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000416/00/00/08/04 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000518/00/24/08/06 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000620/00/22/08/04 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000722/00/20/08/02 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000824/00/18/08/04 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 000926/00/16/08/02 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001028/00/14/08/04 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001130/00/12/08/02 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001232/00/10/08/00 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001334/01/08/08/02 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001436/01/06/08/00 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001538/01/04/08/02 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001640/01/02/08/00 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001742/01/00/08/50 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001844/01/24/08/00 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 001946/01/22/08/50 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002048/01/20/08/00 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002150/01/18/08/50 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002252/01/16/08/48 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002354/01/14/08/50 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002456/01/12/08/48 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002558/01/10/08/46 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002660/02/08/08/48 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002762/02/06/08/46 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002864/02/04/08/48 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 002966/02/02/08/46 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003068/02/00/08/44 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003170/02/24/08/46 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003272/02/22/08/44 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003374/02/20/08/46 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003476/02/18/08/44 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003578/02/16/08/42 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003680/02/14/08/44 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003782/02/12/08/42 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003884/02/10/08/44 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 003986/03/08/08/42 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004088/03/06/08/40 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004190/03/04/08/42 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004292/03/02/08/40 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004394/03/00/08/42 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004496/03/24/08/40 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004598/03/22/08/38 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004700/03/20/08/40 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004802/03/18/08/38 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 004904/03/16/08/40 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005006/03/14/08/38 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005108/03/12/08/36 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005210/03/10/08/38 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005312/04/08/08/36 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005414/04/06/08/38 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005516/04/04/08/36 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005618/04/02/08/34 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005720/04/00/08/36 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005822/04/24/08/34 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 005924/04/22/08/36 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006026/04/20/08/34 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006128/04/18/08/32 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006230/04/16/08/34 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006332/04/14/08/32 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006434/04/12/08/34 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006536/04/10/08/32 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006638/05/08/08/30 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006740/05/06/08/32 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006842/05/04/08/30 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 006944/05/02/08/32 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007046/05/00/08/30 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007148/05/24/08/28 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007250/05/22/08/30 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007352/05/20/08/28 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007454/05/18/08/30 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007556/05/16/08/28 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007658/05/14/08/26 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007760/05/12/08/28 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007862/05/10/08/26 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 007964/06/08/08/28 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008066/06/06/08/26 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008168/06/04/08/24 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008270/06/02/08/26 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008372/06/00/08/24 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008474/06/24/08/26 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008576/06/22/08/24 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008678/06/20/08/22 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008780/06/18/08/24 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008882/06/16/08/22 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 008984/06/14/08/24 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009086/06/12/08/22 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009188/06/10/08/20 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009290/07/08/08/22 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009392/07/06/08/20 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009494/07/04/08/22 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009596/07/02/08/20 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009698/07/00/08/18 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009800/07/24/08/20 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 009902/07/22/08/18 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 010004/07/20/08/20 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=7) 010106/07/18/08/18 meas period end fn_mod:8, status:1, pchan:SDCCH8
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000088/00/10/37/36 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000190/00/08/37/34 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000292/00/06/37/36 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000394/00/04/37/34 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000496/00/02/37/32 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000598/00/00/37/34 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000700/00/24/37/32 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000802/00/22/37/34 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 000904/00/20/37/32 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001006/00/18/37/30 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001108/00/16/37/32 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001210/00/14/37/30 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001312/00/12/37/32 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001414/01/10/37/30 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001516/01/08/37/28 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001618/01/06/37/30 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001720/01/04/37/28 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001822/01/02/37/30 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 001924/01/00/37/28 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002026/01/24/37/26 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002128/01/22/37/28 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002230/01/20/37/26 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002332/01/18/37/28 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002434/01/16/37/26 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002536/01/14/37/24 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002638/01/12/37/26 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002740/02/10/37/24 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002842/02/08/37/26 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 002944/02/06/37/24 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003046/02/04/37/22 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003148/02/02/37/24 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003250/02/00/37/22 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003352/02/24/37/24 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003454/02/22/37/22 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003556/02/20/37/20 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003658/02/18/37/22 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003760/02/16/37/20 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003862/02/14/37/22 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 003964/02/12/37/20 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004066/03/10/37/18 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004168/03/08/37/20 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004270/03/06/37/18 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004372/03/04/37/20 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004474/03/02/37/18 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004576/03/00/37/16 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004678/03/24/37/18 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004780/03/22/37/16 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004882/03/20/37/18 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 004984/03/18/37/16 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005086/03/16/37/14 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005188/03/14/37/16 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005290/03/12/37/14 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005392/04/10/37/16 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005494/04/08/37/14 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005596/04/06/37/12 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005698/04/04/37/14 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005800/04/02/37/12 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 005902/04/00/37/14 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006004/04/24/37/12 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006106/04/22/37/10 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006208/04/20/37/12 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006310/04/18/37/10 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006412/04/16/37/12 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006514/04/14/37/10 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006616/04/12/37/08 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006718/05/10/37/10 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006820/05/08/37/08 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 006922/05/06/37/10 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007024/05/04/37/08 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007126/05/02/37/06 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007228/05/00/37/08 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007330/05/24/37/06 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007432/05/22/37/08 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007534/05/20/37/06 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007636/05/18/37/04 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007738/05/16/37/06 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007840/05/14/37/04 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 007942/05/12/37/06 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008044/06/10/37/04 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008146/06/08/37/02 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008248/06/06/37/04 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008350/06/04/37/02 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008452/06/02/37/04 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008554/06/00/37/02 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008656/06/24/37/00 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008758/06/22/37/02 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008860/06/20/37/00 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 008962/06/18/37/02 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009064/06/16/37/00 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009166/06/14/37/50 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009268/06/12/37/00 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009370/07/10/37/50 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009472/07/08/37/00 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009574/07/06/37/50 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009676/07/04/37/48 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009778/07/02/37/50 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009880/07/00/37/48 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 009982/07/24/37/46 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010084/07/22/37/48 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=0) 010186/07/20/37/46 meas period end fn_mod:88, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000092/00/14/41/40 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000194/00/12/41/38 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000296/00/10/41/40 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000398/00/08/41/38 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000500/00/06/41/36 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000602/00/04/41/38 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000704/00/02/41/36 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000806/00/00/41/38 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 000908/00/24/41/36 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001010/00/22/41/34 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001112/00/20/41/36 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001214/00/18/41/34 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001316/00/16/41/36 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001418/01/14/41/34 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001520/01/12/41/32 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001622/01/10/41/34 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001724/01/08/41/32 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001826/01/06/41/34 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 001928/01/04/41/32 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002030/01/02/41/30 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002132/01/00/41/32 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002234/01/24/41/30 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002336/01/22/41/32 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002438/01/20/41/30 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002540/01/18/41/28 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002642/01/16/41/30 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002744/02/14/41/28 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002846/02/12/41/30 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 002948/02/10/41/28 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003050/02/08/41/26 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003152/02/06/41/28 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003254/02/04/41/26 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003356/02/02/41/28 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003458/02/00/41/26 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003560/02/24/41/24 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003662/02/22/41/26 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003764/02/20/41/24 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003866/02/18/41/26 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 003968/02/16/41/24 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004070/03/14/41/22 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004172/03/12/41/24 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004274/03/10/41/22 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004376/03/08/41/24 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004478/03/06/41/22 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004580/03/04/41/20 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004682/03/02/41/22 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004784/03/00/41/20 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004886/03/24/41/22 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 004988/03/22/41/20 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005090/03/20/41/18 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005192/03/18/41/20 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005294/03/16/41/18 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005396/04/14/41/20 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005498/04/12/41/18 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005600/04/10/41/16 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005702/04/08/41/18 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005804/04/06/41/16 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 005906/04/04/41/18 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006008/04/02/41/16 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006110/04/00/41/14 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006212/04/24/41/16 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006314/04/22/41/14 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006416/04/20/41/16 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006518/04/18/41/14 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006620/04/16/41/12 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006722/05/14/41/14 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006824/05/12/41/12 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 006926/05/10/41/14 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007028/05/08/41/12 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007130/05/06/41/10 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007232/05/04/41/12 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007334/05/02/41/10 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007436/05/00/41/12 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007538/05/24/41/10 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007640/05/22/41/08 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007742/05/20/41/10 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007844/05/18/41/08 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 007946/05/16/41/10 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008048/06/14/41/08 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008150/06/12/41/06 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008252/06/10/41/08 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008354/06/08/41/06 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008456/06/06/41/08 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008558/06/04/41/06 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008660/06/02/41/04 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008762/06/00/41/06 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008864/06/24/41/04 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 008966/06/22/41/06 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009068/06/20/41/04 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009170/06/18/41/02 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009272/06/16/41/04 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009374/07/14/41/02 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009476/07/12/41/04 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009578/07/10/41/02 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009680/07/08/41/00 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009782/07/06/41/02 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009884/07/04/41/00 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 009986/07/02/41/02 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010088/07/00/41/00 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=1) 010190/07/24/41/50 meas period end fn_mod:92, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000006/00/06/06/06 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000108/00/04/06/04 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000210/00/02/06/02 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000312/00/00/06/04 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000414/00/24/06/02 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000516/00/22/06/04 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000618/00/20/06/02 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000720/00/18/06/00 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000822/00/16/06/02 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 000924/00/14/06/00 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001026/00/12/06/02 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001128/00/10/06/00 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001230/00/08/06/50 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001332/01/06/06/00 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001434/01/04/06/50 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001536/01/02/06/00 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001638/01/00/06/50 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001740/01/24/06/48 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001842/01/22/06/50 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 001944/01/20/06/48 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002046/01/18/06/46 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002148/01/16/06/48 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002250/01/14/06/46 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002352/01/12/06/48 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002454/01/10/06/46 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002556/01/08/06/44 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002658/02/06/06/46 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002760/02/04/06/44 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002862/02/02/06/46 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 002964/02/00/06/44 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003066/02/24/06/42 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003168/02/22/06/44 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003270/02/20/06/42 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003372/02/18/06/44 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003474/02/16/06/42 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003576/02/14/06/40 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003678/02/12/06/42 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003780/02/10/06/40 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003882/02/08/06/42 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 003984/03/06/06/40 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004086/03/04/06/38 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004188/03/02/06/40 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004290/03/00/06/38 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004392/03/24/06/40 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004494/03/22/06/38 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004596/03/20/06/36 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004698/03/18/06/38 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004800/03/16/06/36 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 004902/03/14/06/38 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005004/03/12/06/36 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005106/03/10/06/34 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005208/03/08/06/36 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005310/04/06/06/34 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005412/04/04/06/36 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005514/04/02/06/34 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005616/04/00/06/32 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005718/04/24/06/34 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005820/04/22/06/32 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 005922/04/20/06/34 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006024/04/18/06/32 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006126/04/16/06/30 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006228/04/14/06/32 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006330/04/12/06/30 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006432/04/10/06/32 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006534/04/08/06/30 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006636/05/06/06/28 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006738/05/04/06/30 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006840/05/02/06/28 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 006942/05/00/06/30 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007044/05/24/06/28 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007146/05/22/06/26 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007248/05/20/06/28 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007350/05/18/06/26 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007452/05/16/06/28 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007554/05/14/06/26 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007656/05/12/06/24 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007758/05/10/06/26 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007860/05/08/06/24 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 007962/06/06/06/26 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008064/06/04/06/24 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008166/06/02/06/22 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008268/06/00/06/24 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008370/06/24/06/22 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008472/06/22/06/24 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008574/06/20/06/22 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008676/06/18/06/20 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008778/06/16/06/22 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008880/06/14/06/20 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 008982/06/12/06/22 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009084/06/10/06/20 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009186/06/08/06/18 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009288/07/06/06/20 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009390/07/04/06/18 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009492/07/02/06/20 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009594/07/00/06/18 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009696/07/24/06/16 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009798/07/22/06/18 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 009900/07/20/06/16 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 010002/07/18/06/18 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=2) 010104/07/16/06/16 meas period end fn_mod:6, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000010/00/10/10/10 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000112/00/08/10/08 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000214/00/06/10/06 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000316/00/04/10/08 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000418/00/02/10/06 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000520/00/00/10/08 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000622/00/24/10/06 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000724/00/22/10/04 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000826/00/20/10/06 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 000928/00/18/10/04 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001030/00/16/10/06 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001132/00/14/10/04 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001234/00/12/10/02 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001336/01/10/10/04 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001438/01/08/10/02 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001540/01/06/10/04 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001642/01/04/10/02 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001744/01/02/10/00 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001846/01/00/10/02 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 001948/01/24/10/00 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002050/01/22/10/02 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002152/01/20/10/00 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002254/01/18/10/50 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002356/01/16/10/00 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002458/01/14/10/50 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002560/01/12/10/00 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002662/02/10/10/50 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002764/02/08/10/48 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002866/02/06/10/50 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 002968/02/04/10/48 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003070/02/02/10/46 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003172/02/00/10/48 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003274/02/24/10/46 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003376/02/22/10/48 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003478/02/20/10/46 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003580/02/18/10/44 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003682/02/16/10/46 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003784/02/14/10/44 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003886/02/12/10/46 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 003988/03/10/10/44 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004090/03/08/10/42 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004192/03/06/10/44 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004294/03/04/10/42 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004396/03/02/10/44 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004498/03/00/10/42 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004600/03/24/10/40 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004702/03/22/10/42 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004804/03/20/10/40 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 004906/03/18/10/42 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005008/03/16/10/40 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005110/03/14/10/38 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005212/03/12/10/40 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005314/04/10/10/38 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005416/04/08/10/40 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005518/04/06/10/38 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005620/04/04/10/36 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005722/04/02/10/38 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005824/04/00/10/36 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 005926/04/24/10/38 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006028/04/22/10/36 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006130/04/20/10/34 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006232/04/18/10/36 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006334/04/16/10/34 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006436/04/14/10/36 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006538/04/12/10/34 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006640/05/10/10/32 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006742/05/08/10/34 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006844/05/06/10/32 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 006946/05/04/10/34 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007048/05/02/10/32 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007150/05/00/10/30 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007252/05/24/10/32 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007354/05/22/10/30 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007456/05/20/10/32 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007558/05/18/10/30 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007660/05/16/10/28 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007762/05/14/10/30 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007864/05/12/10/28 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 007966/06/10/10/30 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008068/06/08/10/28 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008170/06/06/10/26 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008272/06/04/10/28 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008374/06/02/10/26 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008476/06/00/10/28 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008578/06/24/10/26 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008680/06/22/10/24 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008782/06/20/10/26 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008884/06/18/10/24 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 008986/06/16/10/26 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009088/06/14/10/24 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009190/06/12/10/22 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009292/07/10/10/24 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009394/07/08/10/22 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009496/07/06/10/24 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009598/07/04/10/22 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009700/07/02/10/20 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009802/07/00/10/22 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 009904/07/24/10/20 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 010006/07/22/10/22 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=0,ss=3) 010108/07/20/10/20 meas period end fn_mod:10, status:1, pchan:CCCH+SDCCH4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000017/00/17/17/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000026/00/00/26/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000030/00/04/30/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000034/00/08/34/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 10 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 15 measurements with dummy values, from which 1 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 1 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL(60.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB(50.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000039/00/13/39/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000043/00/17/43/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000047/00/21/47/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000052/00/00/01/00 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000056/00/04/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000060/00/08/09/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000065/00/13/14/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000069/00/17/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000073/00/21/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000078/00/00/27/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000082/00/04/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000086/00/08/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000091/00/13/40/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000095/00/17/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000099/00/21/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000104/00/00/02/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000108/00/04/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000112/00/08/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000117/00/13/15/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000121/00/17/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=20, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000125/00/21/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=21, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000130/00/00/28/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=22, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000134/00/04/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=23, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000138/00/08/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=24, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=25, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000143/00/13/41/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000147/00/17/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000151/00/21/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000156/00/00/03/00 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000160/00/04/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000164/00/08/11/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000169/00/13/16/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000173/00/17/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000177/00/21/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000182/00/00/29/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000186/00/04/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000190/00/08/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000195/00/13/42/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000199/00/17/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000203/00/21/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000208/00/00/04/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000212/00/04/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000216/00/08/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000221/00/13/17/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000225/00/17/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=20, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000229/00/21/25/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=21, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000234/00/00/30/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=22, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000238/00/04/34/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=23, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000242/00/08/38/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=24, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=25, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000247/00/13/43/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000251/00/17/47/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000255/00/21/00/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000260/00/00/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000264/00/04/09/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000268/00/08/13/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000273/00/13/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000277/00/17/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000281/00/21/26/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000286/00/00/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000290/00/04/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000294/00/08/39/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000299/00/13/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000303/00/17/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000307/00/21/01/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000312/00/00/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000316/00/04/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000320/00/08/14/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000325/00/13/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000329/00/17/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=20, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000333/00/21/27/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=21, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000338/00/00/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=22, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000342/00/04/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=23, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000346/00/08/40/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=24, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=25, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 25 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 0 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 3 SUB measurements, expected 2
+ERROR (bts=0,trx=1,ts=2,ss=0) Incorrect number of SUB measurements detected! (3 vs exp 2)
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL( 0.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(0), RXQUAL_SUB(0), num_meas_sub(3), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000351/00/13/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000355/00/17/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000359/00/21/02/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000364/00/00/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000368/00/04/11/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000372/00/08/15/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000377/00/13/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000381/00/17/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000385/00/21/28/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000390/00/00/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000394/00/04/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000398/00/08/41/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000403/00/13/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000407/00/17/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000411/00/21/03/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000416/00/00/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000420/00/04/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000424/00/08/16/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000429/00/13/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000000/00/00/00/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000017/00/17/17/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000026/00/00/26/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000030/00/04/30/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000034/00/08/34/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000039/00/13/39/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000043/00/17/43/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000047/00/21/47/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000052/00/00/01/00 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000056/00/04/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000060/00/08/09/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000065/00/13/14/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000069/00/17/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000073/00/21/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000078/00/00/27/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000082/00/04/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=20, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000086/00/08/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=21, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000091/00/13/40/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=22, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000095/00/17/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=23, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000099/00/21/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=24, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000104/00/00/02/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=25, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000108/00/04/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=26, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000112/00/08/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=27, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000117/00/13/15/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=28, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000121/00/17/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=29, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000125/00/21/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=30, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000130/00/00/28/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=31, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000134/00/04/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=32, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000138/00/08/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=33, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000143/00/13/41/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=34, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000147/00/17/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=35, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000151/00/21/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=36, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000156/00/00/03/00 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=37, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000160/00/04/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=38, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000164/00/08/11/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=39, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000169/00/13/16/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=40, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000173/00/17/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=41, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000177/00/21/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=42, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000182/00/00/29/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=43, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000186/00/04/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=44, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000190/00/08/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=45, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000195/00/13/42/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=46, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000199/00/17/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=47, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000203/00/21/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=48, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000208/00/00/04/00 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=49, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000212/00/04/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=50, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000216/00/08/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=51, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000221/00/13/17/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=52, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000225/00/17/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=53, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000229/00/21/25/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=54, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000234/00/00/30/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=55, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000238/00/04/34/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=56, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000242/00/08/38/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=57, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000247/00/13/43/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=58, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000251/00/17/47/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=59, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000255/00/21/00/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=60, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000260/00/00/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=61, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000264/00/04/09/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=62, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000268/00/08/13/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=63, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000273/00/13/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=64, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000277/00/17/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=65, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000281/00/21/26/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=66, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000286/00/00/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=67, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000290/00/04/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=68, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000294/00/08/39/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=69, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000299/00/13/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=70, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000303/00/17/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=71, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000307/00/21/01/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=72, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000312/00/00/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=73, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000316/00/04/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=74, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000320/00/08/14/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=75, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000325/00/13/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=76, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000329/00/17/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=77, fn_mod=17
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000333/00/21/27/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=78, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000338/00/00/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=79, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000342/00/04/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=80, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000346/00/08/40/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=81, fn_mod=34
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000351/00/13/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=82, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000355/00/17/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=83, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000359/00/21/02/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=84, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000364/00/00/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=85, fn_mod=52
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000368/00/04/11/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=86, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000372/00/08/15/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=87, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000377/00/13/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=88, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000381/00/17/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=89, fn_mod=69
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000385/00/21/28/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=90, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000390/00/00/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=91, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000394/00/04/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=92, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000398/00/08/41/38 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=93, fn_mod=86
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000403/00/13/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=94, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000407/00/17/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=95, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000411/00/21/03/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=96, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000416/00/00/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=97, fn_mod=0
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000420/00/04/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=98, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000424/00/08/16/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=99, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000429/00/13/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=100, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000026/00/00/26/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000030/00/04/30/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000038/00/12/38/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 7 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 18 measurements with dummy values, from which 1 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 1 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL(72.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB(50.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(7), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000039/00/13/39/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000043/00/17/43/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000047/00/21/47/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000056/00/04/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000060/00/08/09/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000065/00/13/14/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000073/00/21/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000078/00/00/27/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000082/00/04/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000091/00/13/40/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000095/00/17/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000099/00/21/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000108/00/04/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000112/00/08/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000117/00/13/15/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000125/00/21/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000130/00/00/28/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000134/00/04/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000142/00/12/40/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 19 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 6 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 2 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL(24.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000143/00/13/41/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000147/00/17/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000151/00/21/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000160/00/04/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000164/00/08/11/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000169/00/13/16/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000177/00/21/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000182/00/00/29/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000186/00/04/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000195/00/13/42/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000199/00/17/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000203/00/21/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000212/00/04/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000216/00/08/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000221/00/13/17/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000229/00/21/25/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000234/00/00/30/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000238/00/04/34/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000246/00/12/42/38 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 19 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 6 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 2 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL(24.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000247/00/13/43/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000251/00/17/47/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000255/00/21/00/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000264/00/04/09/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000268/00/08/13/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000273/00/13/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000281/00/21/26/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000286/00/00/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000290/00/04/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000299/00/13/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000303/00/17/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000307/00/21/01/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000316/00/04/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000320/00/08/14/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000325/00/13/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000333/00/21/27/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000338/00/00/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000342/00/04/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=38
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000350/00/12/44/42 meas period end fn_mod:12, status:1, pchan:TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Calculating measurement results for physical channel: TCH/F
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received 19 UL measurements, expected 25
+DEBUG (bts=0,trx=1,ts=2,ss=0) Replaced 6 measurements with dummy values, from which 0 were SUB measurements
+DEBUG (bts=0,trx=1,ts=2,ss=0) Received UL measurements contain 2 SUB measurements, expected 2
+INFO (bts=0,trx=1,ts=2,ss=0) Computed TA256( 256), BER-FULL(24.00%), RSSI-FULL(- 90dBm), C/I-FULL( 0 cB), BER-SUB( 0.00%), RSSI-SUB(- 90dBm), C/I-SUB( 0 cB)
+INFO (bts=0,trx=1,ts=2,ss=0) UL MEAS RXLEV_FULL(20), RXLEV_SUB(20), RXQUAL_FULL(7), RXQUAL_SUB(0), num_meas_sub(2), num_ul_meas(25)
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000351/00/13/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000355/00/17/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000359/00/21/02/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000368/00/04/11/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000372/00/08/15/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000377/00/13/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000385/00/21/28/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000390/00/00/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000394/00/04/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000403/00/13/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000407/00/17/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000411/00/21/03/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000420/00/04/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000424/00/08/16/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000429/00/13/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000004/00/04/04/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=1, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000008/00/08/08/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=2, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000013/00/13/13/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=3, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000021/00/21/21/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=4, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000026/00/00/26/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=5, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000030/00/04/30/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=6, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000039/00/13/39/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=7, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000043/00/17/43/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=8, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000047/00/21/47/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=9, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000056/00/04/05/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=10, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000060/00/08/09/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=11, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000065/00/13/14/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=12, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000073/00/21/22/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=13, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000078/00/00/27/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=14, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000082/00/04/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=15, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000091/00/13/40/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=16, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000095/00/17/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=17, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000099/00/21/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=18, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000108/00/04/06/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=19, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000112/00/08/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=20, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000117/00/13/15/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=21, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000125/00/21/23/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=22, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000130/00/00/28/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=23, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000134/00/04/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=24, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000143/00/13/41/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=25, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000147/00/17/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=26, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000151/00/21/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=27, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000160/00/04/07/04 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=28, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000164/00/08/11/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=29, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000169/00/13/16/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=30, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000177/00/21/24/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=31, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000182/00/00/29/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=32, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000186/00/04/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=33, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000195/00/13/42/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=34, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000199/00/17/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=35, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000203/00/21/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=36, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000212/00/04/08/04 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=37, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000216/00/08/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=38, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000221/00/13/17/13 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=39, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000229/00/21/25/21 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=40, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000234/00/00/30/26 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=41, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000238/00/04/34/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=42, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000247/00/13/43/39 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=43, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000251/00/17/47/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=44, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000255/00/21/00/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=45, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000264/00/04/09/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=46, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000268/00/08/13/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=47, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000273/00/13/18/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=48, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000281/00/21/26/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=49, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000286/00/00/31/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=50, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000290/00/04/35/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=51, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000299/00/13/44/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=52, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000303/00/17/48/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=53, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000307/00/21/01/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=54, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000316/00/04/10/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=55, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000320/00/08/14/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=56, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000325/00/13/19/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=57, fn_mod=13
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000333/00/21/27/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=58, fn_mod=21
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000338/00/00/32/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=59, fn_mod=26
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000342/00/04/36/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=60, fn_mod=30
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000351/00/13/45/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=61, fn_mod=39
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000355/00/17/49/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=62, fn_mod=43
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000359/00/21/02/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=63, fn_mod=47
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000368/00/04/11/08 adding a SUB measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=64, fn_mod=56
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000372/00/08/15/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=65, fn_mod=60
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000377/00/13/20/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=66, fn_mod=65
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000385/00/21/28/25 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=67, fn_mod=73
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000390/00/00/33/30 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=68, fn_mod=78
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000394/00/04/37/34 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=69, fn_mod=82
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000403/00/13/46/43 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=70, fn_mod=91
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000407/00/17/50/47 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=71, fn_mod=95
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000411/00/21/03/51 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=72, fn_mod=99
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000420/00/04/12/08 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=73, fn_mod=4
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000424/00/08/16/12 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=74, fn_mod=8
+DEBUG (bts=0,trx=1,ts=2,ss=0) 000429/00/13/21/17 adding a FULL measurement (ber10k=0, ta_offs=256, ci_cB=0, rssi=-90), num_ul_meas=75, fn_mod=13
diff --git a/tests/meas/meas_test.ok b/tests/meas/meas_test.ok
index e62bb42f..559a8e6c 100644
--- a/tests/meas/meas_test.ok
+++ b/tests/meas/meas_test.ok
@@ -585,8 +585,8 @@ meas.ext.toa256_min | 0 | 0
meas.ext.toa256_max | 0 | 0
meas.ms_toa256 | 0 | 0
meas.ext.toa256_std_dev | 0 | 0
-meas.ul_res.full.rx_lev | 63 | 63
-meas.ul_res.full.rx_qual | 3 | 3
+meas.ul_res.full.rx_lev | 1 | 1
+meas.ul_res.full.rx_qual | 7 | 7
===========================================================
diff --git a/tests/meas/meas_testcases.h b/tests/meas/meas_testcases.h
index fefa34f7..1263ac35 100644
--- a/tests/meas/meas_testcases.h
+++ b/tests/meas/meas_testcases.h
@@ -1,5 +1,5 @@
#define ULM(ber, ta, sub, neg_rssi) \
- { .ber10k = (ber), .ta_offs_256bits = (ta), .c_i = 1.0, .is_sub = sub, .inv_rssi = (neg_rssi) }
+ { .ber10k = (ber), .ta_offs_256bits = (ta), .ci_cb = 10, .is_sub = sub, .inv_rssi = (neg_rssi) }
struct meas_testcase {
const char *name;
@@ -131,8 +131,8 @@ static const struct meas_testcase mtc4 = {
.pchan = GSM_PCHAN_TCH_F,
.res = {
.success = 1,
- .rx_lev_full = 63,
- .rx_qual_full = 3,
+ .rx_lev_full = 1,
+ .rx_qual_full = 7,
.toa256_mean = 0,
.toa256_max = 0,
.toa256_min = 0,
diff --git a/tests/misc/Makefile.am b/tests/misc/Makefile.am
index f232c493..8b8beda7 100644
--- a/tests/misc/Makefile.am
+++ b/tests/misc/Makefile.am
@@ -1,9 +1,24 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) $(LIBOSMOTRAU_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) \
- $(LIBOSMOABIS_LIBS) $(LIBOSMOTRAU_LIBS)
-noinst_PROGRAMS = misc_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = misc_test
EXTRA_DIST = misc_test.ok
misc_test_SOURCES = misc_test.c $(srcdir)/../stubs.c
diff --git a/tests/misc/misc_test.c b/tests/misc/misc_test.c
index c4d3a595..bbf75579 100644
--- a/tests/misc/misc_test.c
+++ b/tests/misc/misc_test.c
@@ -13,7 +13,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -21,6 +21,7 @@
*/
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/msg_utils.h>
#include <osmo-bts/logging.h>
@@ -162,25 +163,50 @@ static void test_sacch_get(void)
static void test_bts_supports_cm(void)
{
+ struct rsl_ie_chan_mode cm;
struct gsm_bts *bts;
- bts = gsm_bts_alloc(ctx, 0);
-
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_V1);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR);
- gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_H_AMR);
-
- OSMO_ASSERT(bts_supports_cm
- (bts, GSM_PCHAN_TCH_F, GSM48_CMODE_SPEECH_V1) == 1);
- OSMO_ASSERT(bts_supports_cm
- (bts, GSM_PCHAN_TCH_H, GSM48_CMODE_SPEECH_V1) == 1);
- OSMO_ASSERT(bts_supports_cm
- (bts, GSM_PCHAN_TCH_F, GSM48_CMODE_SPEECH_EFR) == 0);
- OSMO_ASSERT(bts_supports_cm
- (bts, GSM_PCHAN_TCH_F, GSM48_CMODE_SPEECH_AMR) == 1);
- OSMO_ASSERT(bts_supports_cm
- (bts, GSM_PCHAN_TCH_H, GSM48_CMODE_SPEECH_AMR) == 1);
+ g_bts_sm = gsm_bts_sm_alloc(ctx);
+ bts = gsm_bts_alloc(g_bts_sm, 0);
+
+ /* Signalling shall be supported regardless of the features */
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Bm,
+ .spd_ind = RSL_CMOD_SPD_SIGN };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/F */
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Lm,
+ .spd_ind = RSL_CMOD_SPD_SIGN };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/H */
+
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_F_AMR);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR);
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Bm,
+ .spd_ind = RSL_CMOD_SPD_SPEECH,
+ .chan_rate = RSL_CMOD_SP_GSM1 };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/FS */
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Lm,
+ .spd_ind = RSL_CMOD_SPD_SPEECH,
+ .chan_rate = RSL_CMOD_SP_GSM1 };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/HS */
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Bm,
+ .spd_ind = RSL_CMOD_SPD_SPEECH,
+ .chan_rate = RSL_CMOD_SP_GSM2 };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == false); /* TCH/EFS */
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Bm,
+ .spd_ind = RSL_CMOD_SPD_SPEECH,
+ .chan_rate = RSL_CMOD_SP_GSM3 };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/AFS */
+
+ cm = (struct rsl_ie_chan_mode) { .chan_rt = RSL_CMOD_CRT_TCH_Lm,
+ .spd_ind = RSL_CMOD_SPD_SPEECH,
+ .chan_rate = RSL_CMOD_SP_GSM3 };
+ OSMO_ASSERT(bts_supports_cm(bts, &cm) == true); /* TCH/AHS */
talloc_free(bts);
}
diff --git a/tests/osmo-bts.vty b/tests/osmo-bts.vty
new file mode 100644
index 00000000..a51ad63f
--- /dev/null
+++ b/tests/osmo-bts.vty
@@ -0,0 +1,323 @@
+OsmoBTS> list
+...
+ show bts [<0-255>]
+ show trx [<0-255>] [<0-255>]
+ show timeslot [<0-255>] [<0-255>] [<0-7>]
+ show lchan [<0-255>] [<0-255>] [<0-7>] [<0-7>]
+ show lchan summary [<0-255>] [<0-255>] [<0-7>] [<0-7>]
+ show bts <0-255> gprs
+...
+ show timer [(bts|abis)] [TNNNN]
+ show e1_driver
+ show e1_line [<0-255>] [stats]
+ show e1_timeslot [<0-255>] [<0-31>]
+...
+OsmoBTS> ?
+...
+ show Show running system information
+...
+
+OsmoBTS> show ?
+...
+ bts Display information about a BTS
+ trx Display information about a TRX
+ timeslot Display information about a TS
+ lchan Display information about a logical channel
+ timer Show timers
+ e1_driver Display information about available E1 drivers
+ e1_line Display information about a E1 line
+ e1_timeslot Display information about a E1 timeslot
+...
+OsmoBTS> show bts ?
+ [<0-255>] BTS Number
+ <0-255> BTS Number
+OsmoBTS> show bts 0 ?
+ gprs GPRS/EGPRS configuration
+ <cr>
+OsmoBTS> show trx ?
+ [<0-255>] BTS Number
+OsmoBTS> show trx 0 ?
+ [<0-255>] TRX Number
+OsmoBTS> show timeslot ?
+ [<0-255>] BTS Number
+OsmoBTS> show timeslot 0 ?
+ [<0-255>] TRX Number
+OsmoBTS> show timeslot 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS> show lchan ?
+ [<0-255>] BTS Number
+ summary Short summary
+OsmoBTS> show lchan 0 ?
+ [<0-255>] TRX Number
+OsmoBTS> show lchan 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS> show lchan 0 0 0 ?
+ [<0-7>] Logical Channel Number
+OsmoBTS> show lchan summary ?
+ [<0-255>] BTS Number
+OsmoBTS> show lchan summary 0 ?
+ [<0-255>] TRX Number
+OsmoBTS> show lchan summary 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS> show lchan summary 0 0 0 ?
+ [<0-7>] Logical Channel Number
+
+OsmoBTS> show timer ?
+ [bts] BTS process timers
+ [abis] Abis (RSL) related timers
+OsmoBTS> show timer
+bts: X1 = 300 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+bts: X2 = 3 s Time after which osmo-bts exits if requesting transceivers to stop during shut down process does not finish (s) (default: 3 s)
+abis: X15 = 0 ms Time to wait between Channel Activation and dispatching a cached early Immediate Assignment (default: 0 ms)
+OsmoBTS> show timer bts ?
+ [TNNNN] T- or X-timer-number -- 3GPP compliant timer number of the format '1234' or 'T1234' or 't1234'; Osmocom-specific timer number of the format: 'X1234' or 'x1234'.
+OsmoBTS> show timer bts
+bts: X1 = 300 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+bts: X2 = 3 s Time after which osmo-bts exits if requesting transceivers to stop during shut down process does not finish (s) (default: 3 s)
+OsmoBTS> show timer bts X1
+bts: X1 = 300 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+OsmoBTS> show timer bts X2
+bts: X2 = 3 s Time after which osmo-bts exits if requesting transceivers to stop during shut down process does not finish (s) (default: 3 s)
+OsmoBTS> show timer abis ?
+ [TNNNN] T- or X-timer-number -- 3GPP compliant timer number of the format '1234' or 'T1234' or 't1234'; Osmocom-specific timer number of the format: 'X1234' or 'x1234'.
+OsmoBTS> show timer abis X15
+abis: X15 = 0 ms Time to wait between Channel Activation and dispatching a cached early Immediate Assignment (default: 0 ms)
+
+OsmoBTS> show e1_driver ?
+ <cr>
+OsmoBTS> show e1_line ?
+ [<0-255>] E1 Line Number
+OsmoBTS> show e1_line 0 ?
+ [stats] Include statistics
+OsmoBTS> show e1_timeslot ?
+ [<0-255>] E1 Line Number
+OsmoBTS> show e1_timeslot 0 ?
+ [<0-31>] E1 Timeslot Number
+
+OsmoBTS> enable
+OsmoBTS# list
+...
+ show bts [<0-255>]
+ show trx [<0-255>] [<0-255>]
+ show timeslot [<0-255>] [<0-255>] [<0-7>]
+ show lchan [<0-255>] [<0-255>] [<0-7>] [<0-7>]
+ show lchan summary [<0-255>] [<0-255>] [<0-7>] [<0-7>]
+ show bts <0-255> gprs
+...
+ show timer [(bts|abis)] [TNNNN]
+ bts <0-0> trx <0-255> ts <0-7> (lchan|shadow-lchan) <0-7> rtp jitter-buffer <0-10000>
+ test send-failure-event-report <0-255>
+ bts <0-0> c0-power-red <0-6>
+ show e1_driver
+ show e1_line [<0-255>] [stats]
+ show e1_timeslot [<0-255>] [<0-31>]
+...
+
+OsmoBTS# ?
+...
+ show Show running system information
+...
+
+OsmoBTS# show ?
+...
+ bts Display information about a BTS
+ trx Display information about a TRX
+ timeslot Display information about a TS
+ lchan Display information about a logical channel
+ timer Show timers
+ e1_driver Display information about available E1 drivers
+ e1_line Display information about a E1 line
+ e1_timeslot Display information about a E1 timeslot
+...
+OsmoBTS# show bts ?
+ [<0-255>] BTS Number
+ <0-255> BTS Number
+OsmoBTS# show bts 0 ?
+ gprs GPRS/EGPRS configuration
+ <cr>
+OsmoBTS# show trx ?
+ [<0-255>] BTS Number
+OsmoBTS# show trx 0 ?
+ [<0-255>] TRX Number
+OsmoBTS# show timeslot ?
+ [<0-255>] BTS Number
+OsmoBTS# show timeslot 0 ?
+ [<0-255>] TRX Number
+OsmoBTS# show timeslot 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS# show lchan ?
+ [<0-255>] BTS Number
+ summary Short summary
+OsmoBTS# show lchan 0 ?
+ [<0-255>] TRX Number
+OsmoBTS# show lchan 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS# show lchan 0 0 0 ?
+ [<0-7>] Logical Channel Number
+OsmoBTS# show lchan summary ?
+ [<0-255>] BTS Number
+OsmoBTS# show lchan summary 0 ?
+ [<0-255>] TRX Number
+OsmoBTS# show lchan summary 0 0 ?
+ [<0-7>] Timeslot Number
+OsmoBTS# show lchan summary 0 0 0 ?
+ [<0-7>] Logical Channel Number
+OsmoBTS# show e1_driver ?
+ <cr>
+OsmoBTS# show e1_line ?
+ [<0-255>] E1 Line Number
+OsmoBTS# show e1_line 0 ?
+ [stats] Include statistics
+OsmoBTS# show e1_timeslot ?
+ [<0-255>] E1 Line Number
+OsmoBTS# show e1_timeslot 0 ?
+ [<0-31>] E1 Timeslot Number
+
+OsmoBTS# configure terminal
+OsmoBTS(config)# list
+...
+ bts BTS_NR
+...
+ timer [(bts|abis)] [TNNNN] [(<0-2147483647>|default)]
+ phy <0-255>
+ e1_input
+...
+OsmoBTS(config)# ?
+...
+ bts Select a BTS to configure
+...
+ timer Configure or show timers
+ phy Select a PHY to configure
+ e1_input Configure E1/T1/J1 TDM input
+...
+OsmoBTS(config)# bts ?
+ BTS_NR BTS Number
+OsmoBTS(config)# phy ?
+ <0-255> PHY number
+
+OsmoBTS(config)# timer ?
+ [bts] BTS process timers
+ [abis] Abis (RSL) related timers
+OsmoBTS(config)# timer bts ?
+ [TNNNN] T- or X-timer-number -- 3GPP compliant timer number of the format '1234' or 'T1234' or 't1234'; Osmocom-specific timer number of the format: 'X1234' or 'x1234'.
+OsmoBTS(config)# timer bts X1
+bts: X1 = 300 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+OsmoBTS(config)# timer bts X2
+bts: X2 = 3 s Time after which osmo-bts exits if requesting transceivers to stop during shut down process does not finish (s) (default: 3 s)
+OsmoBTS(config)# timer bts X1 ?
+ [<0-2147483647>] New timer value
+ [default] Set to default timer value
+OsmoBTS(config)# timer bts X1 123
+OsmoBTS(config)# timer bts X1
+bts: X1 = 123 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+OsmoBTS(config)# timer bts X1 default
+OsmoBTS(config)# timer bts X1
+bts: X1 = 300 s Time after which osmo-bts exits if regular ramp down during shut down process does not finish (s) (default: 300 s)
+
+OsmoBTS(config)# timer abis X15
+abis: X15 = 0 ms Time to wait between Channel Activation and dispatching a cached early Immediate Assignment (default: 0 ms)
+OsmoBTS(config)# timer abis X15 123
+OsmoBTS(config)# timer abis X15
+abis: X15 = 123 ms Time to wait between Channel Activation and dispatching a cached early Immediate Assignment (default: 0 ms)
+OsmoBTS(config)# timer abis X15 default
+OsmoBTS(config)# timer abis X15
+abis: X15 = 0 ms Time to wait between Channel Activation and dispatching a cached early Immediate Assignment (default: 0 ms)
+
+OsmoBTS(config)# bts 0
+OsmoBTS(bts)# list
+...
+ ipa unit-id <0-65534> <0-255>
+ oml remote-ip A.B.C.D
+ no oml remote-ip A.B.C.D
+ rtp jitter-buffer <0-10000> [adaptive]
+ rtp port-range <1-65534> <1-65534>
+ rtp ip-dscp <0-63>
+ rtp socket-priority <0-255>
+ rtp continuous-streaming
+ no rtp continuous-streaming
+ rtp internal-uplink-ecu
+ no rtp internal-uplink-ecu
+ rtp hr-format (rfc5993|ts101318)
+ band (450|GSM450|480|GSM480|750|GSM750|810|GSM810|850|GSM850|900|GSM900|1800|DCS1800|1900|PCS1900)
+ description .TEXT
+ no description
+ paging queue-size <1-1024>
+ paging lifetime <0-60>
+ agch-queue-mgmt default
+ agch-queue-mgmt threshold <0-100> low <0-100> high <0-100000>
+ min-qual-rach <-100-100>
+ min-qual-norm <-100-100>
+ max-ber10k-rach <0-10000>
+ pcu-socket PATH
+ pcu-socket-wqueue-length <1-2147483647>
+ supp-meas-info toa256
+ no supp-meas-info toa256
+ smscb queue-max-length <1-60>
+ smscb queue-target-length <1-30>
+ smscb queue-hysteresis <0-30>
+ gsmtap-remote-host [HOSTNAME]
+ no gsmtap-remote-host
+ gsmtap-local-host HOSTNAME
+ no gsmtap-local-host
+ gsmtap-sapi (enable-all|disable-all)
+ gsmtap-sapi (bcch|ccch|rach|agch|pch|sdcch|tch/f|tch/h|pacch|pdtch|ptcch|cbch|sacch)
+ no gsmtap-sapi (bcch|ccch|rach|agch|pch|sdcch|tch/f|tch/h|pacch|pdtch|ptcch|cbch|sacch)
+ gsmtap-rlp [skip-null]
+ no gsmtap-rlp
+ osmux
+ trx <0-254>
+...
+OsmoBTS(bts)# ?
+...
+ ipa ip.access RSL commands
+ oml OML Parameters
+ no Negate a command or set its defaults
+ rtp RTP parameters
+ band Set the frequency band of this BTS
+ description Save human-readable description of the object
+ paging Paging related parameters
+ agch-queue-mgmt AGCH queue mgmt
+ min-qual-rach Set the minimum link quality level of Access Bursts to be accepted
+ min-qual-norm Set the minimum link quality level of Normal Bursts to be accepted
+ max-ber10k-rach Set the maximum BER for valid RACH requests
+ pcu-socket Configure the PCU socket file/path name
+ pcu-socket-wqueue-length Configure the PCU socket queue length
+ supp-meas-info Configure the RSL Supplementary Measurement Info
+ smscb SMSCB (SMS Cell Broadcast) / CBCH configuration
+ gsmtap-remote-host Enable GSMTAP Um logging (see also 'gsmtap-sapi')
+ gsmtap-local-host Enable local bind for GSMTAP Um logging (see also 'gsmtap-sapi')
+ gsmtap-sapi Enable/disable sending of UL/DL messages over GSMTAP
+ gsmtap-rlp Enable generation of GSMTAP frames for RLP (non-transparent CSD)
+ osmux Configure Osmux
+ trx Select a TRX to configure
+...
+OsmoBTS(bts)# trx 0
+OsmoBTS(trx)# list
+...
+ user-gain <-100000-100000> (dB|mdB)
+ power-ramp max-initial <-10000-100000> (dBm|mdBm)
+ power-ramp step-size <1-100000> (dB|mdB)
+ power-ramp step-interval <1-100>
+ ms-power-control (dsp|osmo)
+ ta-control interval <0-31>
+ phy <0-255> instance <0-255>
+...
+OsmoBTS(trx)# ?
+...
+ user-gain Inform BTS about additional, user-provided gain or attenuation at TRX output
+ power-ramp Power-Ramp settings
+ ms-power-control Mobile Station Power Level Control
+ ta-control Timing Advance Control Parameters
+ phy Configure PHY Link+Instance for this TRX
+...
+OsmoBTS(trx)# exit
+OsmoBTS(bts)# osmux
+OsmoBTS(osmux)# ?
+...
+ use Configure Osmux usage
+ local-ip IP information
+ local-port Osmux port
+ batch-factor Batching factor
+ batch-size Batch size
+ dummy-padding Dummy padding
+
diff --git a/tests/paging/Makefile.am b/tests/paging/Makefile.am
index 74d98265..06cc35e1 100644
--- a/tests/paging/Makefile.am
+++ b/tests/paging/Makefile.am
@@ -1,7 +1,26 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS)
-noinst_PROGRAMS = paging_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+
+check_PROGRAMS = paging_test
EXTRA_DIST = paging_test.ok
paging_test_SOURCES = paging_test.c $(srcdir)/../stubs.c
diff --git a/tests/paging/paging_test.c b/tests/paging/paging_test.c
index af8accc5..1676a107 100644
--- a/tests/paging/paging_test.c
+++ b/tests/paging/paging_test.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -22,10 +22,12 @@
#include <osmocom/core/application.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/paging.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/notification.h>
#include <unistd.h>
@@ -133,6 +135,7 @@ static struct gsm_bts_trx *test_is_ccch_for_agch_setup(uint8_t bs_ag_blks_res)
si3.control_channel_desc.bs_ag_blks_res = bs_ag_blks_res;
trx.bts = &bts;
bts.si_valid |= 0x8;
+ bts.asci.pos_nch = -1;
memcpy(&bts.si_buf[SYSINFO_TYPE_3][0], &si3, sizeof(si3));
return &trx;
}
@@ -142,7 +145,7 @@ static struct gsm_bts_trx *test_is_ccch_for_agch_setup(uint8_t bs_ag_blks_res)
* Table 5 of 9 must occur. */
static void test_is_ccch_for_agch(void)
{
- int is_ag_res;
+ enum ccch_msgt ccch;
int fn;
uint8_t bs_ag_blks_res;
struct gsm_bts_trx *trx;
@@ -170,13 +173,174 @@ static void test_is_ccch_for_agch(void)
/* Try allo possible settings for bs_ag_blks_res */
for (bs_ag_blks_res = 0; bs_ag_blks_res <= 7; bs_ag_blks_res++) {
trx = test_is_ccch_for_agch_setup(bs_ag_blks_res);
- is_ag_res = is_ccch_for_agch(trx, fn);
- printf(" %u", is_ag_res);
+ ccch = get_ccch_msgt(trx, fn);
+ printf(" %u", (ccch == CCCH_MSGT_AGCH));
}
printf("\n");
}
}
+static void test_paging_rest_octets1(void)
+{
+ uint8_t out_buf[17];
+ struct p1_rest_octets p1ro = {};
+ struct asci_notification notif = {};
+
+ struct bitvec bv = {
+ .data_len = sizeof(out_buf),
+ .data = out_buf,
+ };
+
+ /* no rest */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ append_p1_rest_octets(&bv, &p1ro, NULL);
+ ASSERT_TRUE(out_buf[0] == 0x2b);
+
+ /* add NLN */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p1ro.nln_pch.present = true;
+ p1ro.nln_pch.nln = 3;
+ p1ro.nln_pch.nln_status = 1;
+ append_p1_rest_octets(&bv, &p1ro, NULL);
+ ASSERT_TRUE(out_buf[0] == 0xfb); /* H 1 11 1 */
+ p1ro.nln_pch.present = 0;
+
+ /* add group callref */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ notif.group_call_ref[0] = 0x12;
+ notif.group_call_ref[1] = 0x34;
+ notif.group_call_ref[2] = 0x56;
+ notif.group_call_ref[3] = 0x78;
+ notif.group_call_ref[4] = 0x90;
+ notif.chan_desc.present = true;
+ notif.chan_desc.len = 3;
+ notif.chan_desc.value[0] = 0x20;
+ notif.chan_desc.value[1] = 0x40;
+ notif.chan_desc.value[2] = 0x80;
+ append_p1_rest_octets(&bv, &p1ro, &notif);
+ ASSERT_TRUE(out_buf[0] == 0x31); /* L L L H 0x123456789 */
+ ASSERT_TRUE(out_buf[1] == 0x23);
+ ASSERT_TRUE(out_buf[2] == 0x45);
+ ASSERT_TRUE(out_buf[3] == 0x67);
+ ASSERT_TRUE(out_buf[4] == 0x89);
+ ASSERT_TRUE(out_buf[5] == 0x90); /* H 0x204080 0 */
+ ASSERT_TRUE(out_buf[6] == 0x20);
+ ASSERT_TRUE(out_buf[7] == 0x40);
+ ASSERT_TRUE(out_buf[8] == 0x2b);
+
+ /* add Packet Page Indication 1 */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p1ro.packet_page_ind[0] = true;
+ append_p1_rest_octets(&bv, &p1ro, NULL);
+ ASSERT_TRUE(out_buf[0] == 0x23); /* L L L L H L L L */
+ p1ro.packet_page_ind[0] = false;
+
+ /* add Packet Page Indication 2 */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p1ro.packet_page_ind[1] = true;
+ append_p1_rest_octets(&bv, &p1ro, NULL);
+ ASSERT_TRUE(out_buf[0] == 0x2f); /* L L L L L H L L */
+ p1ro.packet_page_ind[1] = false;
+
+ /* add ETWS */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p1ro.r8_present = true;
+ p1ro.r8.prio_ul_access = true;
+ p1ro.r8.etws_present = true;
+ p1ro.r8.etws.is_first = true;
+ p1ro.r8.etws.page_nr = 0x5;
+ uint8_t page[] = { 0x22, 0x44, 0x66 };
+ p1ro.r8.etws.page_bytes = sizeof(page);
+ p1ro.r8.etws.page = page;
+ append_p1_rest_octets(&bv, &p1ro, NULL);
+ ASSERT_TRUE(out_buf[0] == 0x2b); /* L L L L L L L L */
+ ASSERT_TRUE(out_buf[1] == 0xe5); /* H 1 1 0 0x5 */
+ ASSERT_TRUE(out_buf[2] == 0x18); /* 0 len=24=0x18 */
+ ASSERT_TRUE(out_buf[3] == 0x22); /* 0x224488 */
+ ASSERT_TRUE(out_buf[4] == 0x44);
+ ASSERT_TRUE(out_buf[5] == 0x66);
+ p1ro.r8_present = false;
+}
+
+static void test_paging_rest_octets2(void)
+{
+ uint8_t out_buf[11];
+ struct p2_rest_octets p2ro = {};
+
+ struct bitvec bv = {
+ .data_len = sizeof(out_buf),
+ .data = out_buf,
+ };
+
+ /* nothing added */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ append_p2_rest_octets(&bv, &p2ro);
+ ASSERT_TRUE(out_buf[0] == 0x2b); /* L L */
+
+ /* add cneed */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p2ro.cneed.present = true;
+ p2ro.cneed.cn3 = 3;
+ append_p2_rest_octets(&bv, &p2ro);
+ ASSERT_TRUE(out_buf[0] == 0xeb); /* H 1 1 L */
+ p2ro.cneed.present = false;
+
+ /* add NLN */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p2ro.nln_pch.present = true;
+ p2ro.nln_pch.nln = 3;
+ p2ro.nln_pch.nln_status = 1;
+ append_p2_rest_octets(&bv, &p2ro);
+ ASSERT_TRUE(out_buf[0] == 0x7b); /* L H 1 11 1 */
+ p2ro.nln_pch.present = 0;
+}
+
+static void test_paging_rest_octets3(void)
+{
+ uint8_t out_buf[3];
+ struct p3_rest_octets p3ro = {};
+
+ struct bitvec bv = {
+ .data_len = sizeof(out_buf),
+ .data = out_buf,
+ };
+
+ /* nothing added */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ append_p3_rest_octets(&bv, &p3ro);
+ ASSERT_TRUE(out_buf[0] == 0x2b); /* L L */
+
+ /* add cneed */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p3ro.cneed.present = true;
+ p3ro.cneed.cn3 = 3;
+ p3ro.cneed.cn4 = 3;
+ append_p3_rest_octets(&bv, &p3ro);
+ ASSERT_TRUE(out_buf[0] == 0xfb); /* H 1 1 1 1 L */
+ p3ro.cneed.present = false;
+
+ /* add NLN */
+ memset(out_buf, GSM_MACBLOCK_PADDING, sizeof(out_buf));
+ bv.cur_bit = 0;
+ p3ro.nln_pch.present = true;
+ p3ro.nln_pch.nln = 3;
+ p3ro.nln_pch.nln_status = 1;
+ append_p3_rest_octets(&bv, &p3ro);
+ ASSERT_TRUE(out_buf[0] == 0x7b); /* L H 1 11 1 */
+ p3ro.nln_pch.present = 0;
+}
+
int main(int argc, char **argv)
{
tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
@@ -184,7 +348,12 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm) {
+ fprintf(stderr, "Failed to create BTS Site Manager structure\n");
+ exit(1);
+ }
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (bts_init(bts) < 0) {
fprintf(stderr, "unable to open bts\n");
exit(1);
@@ -193,6 +362,9 @@ int main(int argc, char **argv)
test_paging_smoke();
test_paging_sleep();
test_is_ccch_for_agch();
+ test_paging_rest_octets1();
+ test_paging_rest_octets2();
+ test_paging_rest_octets3();
printf("Success\n");
return 0;
diff --git a/tests/power/Makefile.am b/tests/power/Makefile.am
index ac45f238..81f3f2a5 100644
--- a/tests/power/Makefile.am
+++ b/tests/power/Makefile.am
@@ -1,9 +1,29 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS)
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
-noinst_PROGRAMS = power_test
-EXTRA_DIST = power_test.ok
+check_PROGRAMS = ms_power_loop_test bs_power_loop_test
+EXTRA_DIST = ms_power_loop_test.ok ms_power_loop_test.err \
+ bs_power_loop_test.ok bs_power_loop_test.err
-power_test_SOURCES = power_test.c $(srcdir)/../stubs.c
-power_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)
+ms_power_loop_test_SOURCES = ms_power_loop_test.c $(srcdir)/../stubs.c
+ms_power_loop_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)
+
+bs_power_loop_test_SOURCES = bs_power_loop_test.c $(srcdir)/../stubs.c
+bs_power_loop_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)
diff --git a/tests/power/bs_power_loop_test.c b/tests/power/bs_power_loop_test.c
new file mode 100644
index 00000000..8fbdcee6
--- /dev/null
+++ b/tests/power/bs_power_loop_test.c
@@ -0,0 +1,515 @@
+/*
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+ *
+ * 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 Affero 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 <stdio.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/application.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/power_control.h>
+
+#define PWR_TEST_RXLEV_TARGET 30
+
+#define PWR_TEST_CFG_RXLEV_THRESH(hyst) \
+ .lower_thresh = PWR_TEST_RXLEV_TARGET - hyst, \
+ .upper_thresh = PWR_TEST_RXLEV_TARGET + hyst
+
+#define DL_MEAS_FULL(rxqual, rxlev) \
+ .rxqual_full = rxqual, \
+ .rxlev_full = rxlev
+
+#define DL_MEAS_SUB(rxqual, rxlev) \
+ .rxqual_sub = rxqual, \
+ .rxlev_sub = rxlev
+
+#define DL_MEAS_FULL_SUB(rxqual, rxlev) \
+ { DL_MEAS_FULL(rxqual, rxlev), \
+ DL_MEAS_SUB(rxqual, rxlev) }
+
+enum power_test_step_type {
+ PWR_TEST_ST_IND_MEAS = 0,
+ PWR_TEST_ST_SET_STATE,
+ PWR_TEST_ST_SET_CTRL_INTERVAL,
+ PWR_TEST_ST_SET_STEP_SIZE,
+ PWR_TEST_ST_SET_RXLEV_PARAMS,
+ PWR_TEST_ST_ENABLE_DTXD,
+ PWR_TEST_ST_DISABLE_DPC,
+};
+
+struct power_test_step {
+ /* Instruction to be performed */
+ enum power_test_step_type type;
+ /* Instruction parameters */
+ union {
+ /* Power Control state */
+ struct lchan_power_ctrl_state state;
+ /* Measurement pre-processing parameters */
+ struct gsm_power_ctrl_meas_params mp;
+ /* Indicated DL measurements */
+ struct {
+ uint8_t rxqual_full;
+ uint8_t rxqual_sub;
+ uint8_t rxlev_full;
+ uint8_t rxlev_sub;
+ } meas;
+ /* Increase / reduce step size */
+ struct {
+ uint8_t inc;
+ uint8_t red;
+ } step_size;
+ /* Power control interval */
+ uint8_t ctrl_interval;
+ };
+ /* Expected Tx power reduction */
+ uint8_t exp_txred;
+};
+
+static struct gsm_bts *g_bts = NULL;
+static struct gsm_bts_trx *g_trx = NULL;
+
+static void init_test(const char *name)
+{
+ if (g_trx != NULL)
+ talloc_free(g_trx);
+ if (g_bts != NULL)
+ talloc_free(g_bts);
+
+ g_bts = talloc_zero(tall_bts_ctx, struct gsm_bts);
+ OSMO_ASSERT(g_bts != NULL);
+
+ INIT_LLIST_HEAD(&g_bts->trx_list);
+ g_trx = gsm_bts_trx_alloc(g_bts);
+ OSMO_ASSERT(g_trx != NULL);
+
+ g_bts->band = GSM_BAND_900;
+ g_bts->c0 = g_trx;
+
+ /* Init defaultBS power control parameters, enable dynamic power control */
+ struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].bs_dpc_params;
+ g_trx->ts[0].lchan[0].bs_power_ctrl.dpc_params = params;
+ *params = power_ctrl_params_def;
+
+ /* Disable loop SACCH block skip by default: */
+ params->ctrl_interval = 0;
+
+ printf("\nStarting test case '%s'\n", name);
+}
+
+static void enc_meas_rep(struct gsm48_meas_res *mr,
+ const unsigned int n,
+ const struct power_test_step *step)
+{
+ *mr = (struct gsm48_meas_res) {
+ .rxlev_full = step->meas.rxlev_full,
+ .rxlev_sub = step->meas.rxlev_sub,
+ .rxqual_full = step->meas.rxqual_full,
+ .rxqual_sub = step->meas.rxqual_sub,
+ };
+
+ printf("#%02u %s() -> Measurement Results (valid): "
+ "RXLEV-FULL(%02u), RXQUAL-FULL(%u), "
+ "RXLEV-SUB(%02u), RXQUAL-SUB(%u)\n",
+ n, __func__,
+ mr->rxlev_full, mr->rxqual_full,
+ mr->rxlev_sub, mr->rxqual_sub);
+}
+
+static int exec_power_step(struct gsm_lchan *lchan,
+ const unsigned int n,
+ const struct power_test_step *step)
+{
+ struct gsm48_meas_res mr;
+ uint8_t old, new;
+
+ switch (step->type) {
+ case PWR_TEST_ST_SET_STATE:
+ printf("#%02u %s() <- State (re)set (current %u dB, max %u dB)\n",
+ n, __func__, step->state.current, step->state.max);
+ lchan->bs_power_ctrl = step->state;
+ lchan->bs_power_ctrl.dpc_params = &lchan->bs_dpc_params;
+ return 0; /* we're done */
+ case PWR_TEST_ST_DISABLE_DPC:
+ printf("#%02u %s() <- Dynamic power control is disabled\n", n, __func__);
+ lchan->bs_power_ctrl.dpc_params = NULL;
+ return 0; /* we're done */
+ case PWR_TEST_ST_SET_CTRL_INTERVAL:
+ printf("#%02u %s() <- (Re)set power control interval: %u -> %u\n",
+ n, __func__, lchan->bs_dpc_params.ctrl_interval, step->ctrl_interval);
+ lchan->bs_dpc_params.ctrl_interval = step->ctrl_interval;
+ return 0; /* we're done */
+ case PWR_TEST_ST_SET_STEP_SIZE:
+ printf("#%02u %s() <- Set step size: inc %u dB, red %u dB\n",
+ n, __func__, step->step_size.inc, step->step_size.red);
+ lchan->bs_dpc_params.inc_step_size_db = step->step_size.inc;
+ lchan->bs_dpc_params.red_step_size_db = step->step_size.red;
+ return 0; /* we're done */
+ case PWR_TEST_ST_SET_RXLEV_PARAMS:
+ printf("#%02u %s() <- (Re)set RxLev params (thresh %u .. %u, "
+ "averaging is %sabled)\n",
+ n, __func__, step->mp.lower_thresh, step->mp.upper_thresh,
+ step->mp.algo != GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE ? "en" : "dis");
+ lchan->bs_dpc_params.rxlev_meas = step->mp;
+ return 0; /* we're done */
+ case PWR_TEST_ST_ENABLE_DTXD:
+ printf("#%02u %s() <- Enable DTXd\n", n, __func__);
+ lchan->tch.dtx.dl_active = true;
+ return 0; /* we're done */
+ case PWR_TEST_ST_IND_MEAS:
+ enc_meas_rep(&mr, n, step);
+ break;
+ }
+
+ printf("#%02u lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 %s\n",
+ n, osmo_hexdump((void *)&mr, sizeof(mr)));
+
+ old = lchan->bs_power_ctrl.current;
+ lchan_bs_pwr_ctrl(lchan, &mr);
+ new = lchan->bs_power_ctrl.current;
+
+ printf("#%02u lchan_bs_pwr_ctrl() -> BS power reduction: "
+ "%u -> %u (expected %u)\n",
+ n, old, new, step->exp_txred);
+
+ return new != step->exp_txred;
+}
+
+static void exec_power_test(const struct power_test_step *steps,
+ unsigned int num_steps,
+ const char *name)
+{
+ unsigned int n;
+ int rc = 0;
+
+ init_test(name);
+
+ struct gsm_lchan *lchan = &g_trx->ts[0].lchan[0];
+ struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params;
+
+ /* No RxLev hysteresis: lower == upper */
+ params->rxlev_meas.lower_thresh = PWR_TEST_RXLEV_TARGET;
+ params->rxlev_meas.upper_thresh = PWR_TEST_RXLEV_TARGET;
+
+ /* No RxLev pre-processing by default */
+ params->rxlev_meas.algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE;
+
+ for (n = 0; n < num_steps; n++)
+ rc |= exec_power_step(lchan, n, &steps[n]);
+
+ printf("Test case verdict: %s\n", rc ? "FAIL" : "SUCCESS");
+}
+
+/* Verify that the power remains constant in fixed mode. */
+static const struct power_test_step TC_fixed_mode[] = {
+ /* Initial state: 10 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 10, .max = 2 * 10 } },
+ { .type = PWR_TEST_ST_DISABLE_DPC },
+
+ /* MS indicates random RxQual/RxLev values, which must be ignored */
+ { .meas = DL_MEAS_FULL_SUB(0, 63), .exp_txred = 10 },
+ { .meas = DL_MEAS_FULL_SUB(7, 0), .exp_txred = 10 },
+ { .meas = DL_MEAS_FULL_SUB(0, 30), .exp_txred = 10 },
+ { .meas = DL_MEAS_FULL_SUB(1, 30), .exp_txred = 10 },
+ { .meas = DL_MEAS_FULL_SUB(1, 50), .exp_txred = 10 },
+};
+
+/* Verify that the power remains constant if RxLev equals the target level. */
+static const struct power_test_step TC_rxlev_target[] = {
+ /* Initial state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ /* MS indicates RxLev values that match the target level */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+};
+
+/* Verify that the power is gradually reduced/increased to the
+ * minimum/maximum if the MS reports high/low RxLev values. */
+static const struct power_test_step TC_rxlev_max_min[] = {
+ /* Initial state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ /* MS indicates high RxLev values (-50 dBm), inc step is 2 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 6 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 8 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 10 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 12 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 14 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 18 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 20 }, /* max */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 20 }, /* max */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 20 }, /* max */
+
+ /* MS indicates low RxLev values (-100 dBm), red step is 4 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 12 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 8 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 }, /* min */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 }, /* min */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 }, /* min */
+};
+
+/* Verify that delta values never exceed the corresponding step size,
+ * but still can be smaller than the step size if the target is close. */
+static const struct power_test_step TC_inc_red_step_size[] = {
+ /* Initial state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ { .type = PWR_TEST_ST_SET_STEP_SIZE,
+ .step_size = { .inc = 6, .red = 4 } },
+
+ /* MS indicates high RxLev values (-50 dBm), red step is 4 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 8 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 12 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 20 }, /* max */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 20 }, /* max */
+
+ /* MS indicates low RxLev values (-100 dBm), inc step is 6 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 14 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 8 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 }, /* min */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 }, /* min */
+
+ /* Reset state: current 10 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 10, .max = 2 * 10 } },
+
+ /* Let's say the current value is now 1 dB greater than the target (current red 10 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 1), .exp_txred = 10 + 1 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 0), .exp_txred = 10 + 1 },
+ /* Let's say the current value is now 2 dB greater than the target (current red 11 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 2), .exp_txred = 11 + 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 0), .exp_txred = 11 + 2 },
+ /* Let's say the current value is now 3 dB greater than the target (current red 13 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 3), .exp_txred = 13 + 3 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 0), .exp_txred = 13 + 3 },
+
+ /* Reset state: current 10 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 10, .max = 2 * 10 } },
+
+ /* Let's say the current value is now 1 dB lower than the target (current red 10 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 1), .exp_txred = 10 - 1 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 0), .exp_txred = 10 - 1 },
+ /* Let's say the current value is now 3 dB lower than the target (current red 9 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 3), .exp_txred = 9 - 3 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 0), .exp_txred = 9 - 3 },
+ /* Let's say the current value is now 5 dB lower than the target (current red 6 dB) */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 5), .exp_txred = 6 - 5 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 0), .exp_txred = 6 - 5 },
+};
+
+/* Verify that the logic picks the 'SUB' values in DTXd mode. */
+static const struct power_test_step TC_dtxd_mode[] = {
+ /* Initial state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },
+
+ { .type = PWR_TEST_ST_ENABLE_DTXD }, /* DTXd mode */
+
+ /* MS indicates target RxLev values as 'SUB', and random as 'FULL' */
+ { .meas = { DL_MEAS_FULL(7, 0), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },
+ { .meas = { DL_MEAS_FULL(3, 30), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },
+ { .meas = { DL_MEAS_FULL(0, 63), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },
+};
+
+/* Verify that high RxQual reduces the current attenuation value. */
+static const struct power_test_step TC_rxqual_ber[] = {
+ /* Initial state: 16 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 16, .max = 2 * 10 } },
+
+ /* MS indicates target RxLev, and no bit errors */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+
+ /* MS indicates target RxLev, but RxQual values better than L_RXQUAL_XX_P=3 */
+ { .meas = DL_MEAS_FULL_SUB(1, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(2, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(3, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+
+ /* MS indicates target RxLev, but RxQual values worse than L_RXQUAL_XX_P=3 */
+ { .meas = DL_MEAS_FULL_SUB(4, PWR_TEST_RXLEV_TARGET + 0), .exp_txred = 16 - 4 },
+ { .meas = DL_MEAS_FULL_SUB(5, PWR_TEST_RXLEV_TARGET + 4), .exp_txred = 16 - 8 },
+ { .meas = DL_MEAS_FULL_SUB(6, PWR_TEST_RXLEV_TARGET + 8), .exp_txred = 16 - 12 },
+ { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET + 12), .exp_txred = 16 - 16 }, /* max */
+ { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET + 16), .exp_txred = 16 - 16 }, /* max */
+
+ /* MS indicates target RxLev, but no bit errors anymore => reducing Tx power */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 16), .exp_txred = 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 14), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 12), .exp_txred = 6 },
+
+ /* Reset state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ /* MS indicates target RxLev, but RxQual values worse than L_RXQUAL_XX_P=3 */
+ { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET) }, /* max */
+ { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET) }, /* max */
+};
+
+/* Verify handling of optional power control interval (P_Con_INTERVAL). */
+static const struct power_test_step TC_ctrl_interval[] = {
+ /* Initial state: 0 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 0, .max = 2 * 10 } },
+
+ /* P_Con_INTERVAL=0 (480 ms): every SACCH block is handled */
+ { .type = PWR_TEST_ST_SET_CTRL_INTERVAL, .ctrl_interval = 0 },
+
+ /* MS indicates high RxLev values (-50 dBm), red step is 2 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 6 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 8 },
+
+ /* MS indicates low RxLev values (-100 dBm), inc step is 4 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 },
+
+ /* P_Con_INTERVAL=1 (960 ms): 1 out of 2 SACCH blocks is handled */
+ { .type = PWR_TEST_ST_SET_CTRL_INTERVAL, .ctrl_interval = 1 },
+
+ /* MS indicates high RxLev values (-50 dBm), red step is 2 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 2 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 2 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 4 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 6 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 6 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 8 },
+ { .meas = DL_MEAS_FULL_SUB(0, 60), .exp_txred = 8 }, /* skipped */
+
+ /* P_Con_INTERVAL=2 (1920 ms): 1 out of 4 SACCH blocks is handled */
+ { .type = PWR_TEST_ST_SET_CTRL_INTERVAL, .ctrl_interval = 2 },
+
+ /* MS indicates low RxLev values (-100 dBm), inc step is 4 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 },
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 4 }, /* skipped */
+ { .meas = DL_MEAS_FULL_SUB(0, 10), .exp_txred = 0 },
+};
+
+/* Verify that small deviations from the target do not trigger any changes. */
+static const struct power_test_step TC_rxlev_hyst[] = {
+ /* Initial state: 16 dB, up to 20 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 12, .max = 2 * 8 } },
+
+ /* Hysteresis is not enabled, so small deviations trigger oscillations */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 1), .exp_txred = 13 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2), .exp_txred = 11 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 3), .exp_txred = 13 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2), .exp_txred = 11 },
+
+ /* Enable hysteresis */
+ { .type = PWR_TEST_ST_SET_RXLEV_PARAMS,
+ .mp = { PWR_TEST_CFG_RXLEV_THRESH(3) }
+ },
+
+ /* Hysteresis is enabled, so small deviations do not trigger any changes */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 1), .exp_txred = 11 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2), .exp_txred = 11 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 3), .exp_txred = 11 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2), .exp_txred = 11 },
+};
+
+/* Verify EWMA based power filtering. */
+static const struct power_test_step TC_rxlev_pf_ewma[] = {
+ /* Initial state: 20 dB, up to 30 dB */
+ { .type = PWR_TEST_ST_SET_STATE,
+ .state = { .current = 16, .max = 2 * 15 } },
+
+ /* Enable EWMA based pre-processing for RxLev */
+ { .type = PWR_TEST_ST_SET_RXLEV_PARAMS,
+ .mp = {
+ PWR_TEST_CFG_RXLEV_THRESH(0),
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,
+ .ewma.alpha = 50,
+ }
+ },
+
+ /* MS indicates target RxLev, power level remains constant */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET), .exp_txred = 16 },
+
+ /* Avg[t] = (0.5 * 26) + (0.5 * 30) = 28, so delta is 2 */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 4), .exp_txred = 14 },
+ /* Avg[t] = (0.5 * 26) + (0.5 * 28) = 27, so delta is 3 */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 4), .exp_txred = 11 },
+ /* Avg[t] = (0.5 * 35) + (0.5 * 27) = 31, so delta is 1 */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 5), .exp_txred = 12 },
+ /* Avg[t] = (0.5 * 35) + (0.5 * 31) = 33, so delta is 3, but red step size is 2 dB */
+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 5), .exp_txred = 14 },
+};
+
+int main(int argc, char **argv)
+{
+ printf("Testing BS Power loop...\n");
+
+ tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
+ msgb_talloc_ctx_init(tall_bts_ctx, 0);
+
+ osmo_init_logging2(tall_bts_ctx, &bts_log_info);
+ osmo_stderr_target->categories[DLOOP].loglevel = LOGL_DEBUG;
+ osmo_stderr_target->categories[DL1C].loglevel = LOGL_DEBUG;
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+
+#define exec_test(test) \
+ exec_power_test(test, ARRAY_SIZE(test), #test)
+
+ exec_test(TC_fixed_mode);
+ exec_test(TC_rxlev_target);
+ exec_test(TC_rxlev_max_min); /* FIXME */
+ exec_test(TC_inc_red_step_size);
+
+ exec_test(TC_dtxd_mode);
+ exec_test(TC_rxqual_ber);
+ exec_test(TC_ctrl_interval);
+
+ exec_test(TC_rxlev_hyst);
+ exec_test(TC_rxlev_pf_ewma);
+
+ return 0;
+}
diff --git a/tests/power/bs_power_loop_test.err b/tests/power/bs_power_loop_test.err
new file mode 100644
index 00000000..24107ba9
--- /dev/null
+++ b/tests/power/bs_power_loop_test.err
@@ -0,0 +1,191 @@
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 0 dB => 2 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 2 dB => 4 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 4 dB => 6 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 6 dB => 8 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 8 dB => 10 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 10 dB => 12 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 12 dB => 14 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 14 dB => 16 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 16 dB => 18 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 18 dB => 20 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 20 dB: max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 20 dB: max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 20 dB => 16 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 16 dB => 12 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 12 dB => 8 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 8 dB => 4 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 4 dB => 0 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 0 dB => 4 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 4 dB => 8 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 8 dB => 12 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 12 dB => 16 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 16 dB => 20 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 20 dB: max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 20 dB => 14 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 14 dB => 8 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 8 dB => 2 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 2 dB => 0 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 10 dB => 11 dB:max 20 dB, RSSI[curr -79, avg -79, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 11 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(32), RXQUAL-FULL(0), RXLEV-SUB(32), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 11 dB => 13 dB:max 20 dB, RSSI[curr -78, avg -78, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 13 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 13 dB => 16 dB:max 20 dB, RSSI[curr -77, avg -77, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(29), RXQUAL-FULL(0), RXLEV-SUB(29), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 10 dB => 9 dB:max 20 dB, RSSI[curr -81, avg -81, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 9 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(27), RXQUAL-FULL(0), RXLEV-SUB(27), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 9 dB => 6 dB:max 20 dB, RSSI[curr -83, avg -83, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 6 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(25), RXQUAL-FULL(0), RXLEV-SUB(25), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 6 dB => 1 dB:max 20 dB, RSSI[curr -85, avg -85, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 1 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 1, avg 1, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(2), RXLEV-SUB(30), RXQUAL-SUB(2), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 2, avg 2, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(3), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 3, avg 3, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(4), RXLEV-SUB(30), RXQUAL-SUB(4), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 16 dB => 12 dB:max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 4, avg 4, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(34), RXQUAL-FULL(5), RXLEV-SUB(34), RXQUAL-SUB(5), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 12 dB => 8 dB:max 20 dB, RSSI[curr -76, avg -76, thresh -80..-80] dBm, RxQual[curr 5, avg 5, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(38), RXQUAL-FULL(6), RXLEV-SUB(38), RXQUAL-SUB(6), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 8 dB => 4 dB:max 20 dB, RSSI[curr -72, avg -72, thresh -80..-80] dBm, RxQual[curr 6, avg 6, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(42), RXQUAL-FULL(7), RXLEV-SUB(42), RXQUAL-SUB(7), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 4 dB => 0 dB:max 20 dB, RSSI[curr -68, avg -68, thresh -80..-80] dBm, RxQual[curr 7, avg 7, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(46), RXQUAL-FULL(7), RXLEV-SUB(46), RXQUAL-SUB(7), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -64, avg -64, thresh -80..-80] dBm, RxQual[curr 7, avg 7, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(46), RXQUAL-FULL(0), RXLEV-SUB(46), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 0 dB => 2 dB:max 20 dB, RSSI[curr -64, avg -64, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(44), RXQUAL-FULL(0), RXLEV-SUB(44), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 2 dB => 4 dB:max 20 dB, RSSI[curr -66, avg -66, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(42), RXQUAL-FULL(0), RXLEV-SUB(42), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 4 dB => 6 dB:max 20 dB, RSSI[curr -68, avg -68, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 7, avg 7, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 0 dB: max 20 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 7, avg 7, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 0 dB => 2 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 2 dB => 4 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 4 dB => 6 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 6 dB => 8 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 8 dB => 4 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 4 dB => 0 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 0 dB => 2 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 2 dB => 4 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 4 dB => 6 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 6 dB => 8 dB:max 20 dB, RSSI[curr -50, avg -50, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 8 dB => 4 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 4 dB => 0 dB:max 20 dB, RSSI[curr -100, avg -100, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 12 dB => 13 dB:max 16 dB, RSSI[curr -79, avg -79, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 13 dB => 11 dB:max 16 dB, RSSI[curr -82, avg -82, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 11 dB => 13 dB:max 16 dB, RSSI[curr -77, avg -77, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 13 dB => 11 dB:max 16 dB, RSSI[curr -82, avg -82, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 11 dB: max 16 dB, RSSI[curr -79, avg -79, thresh -83..-77] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 11 dB: max 16 dB, RSSI[curr -82, avg -82, thresh -83..-77] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 11 dB: max 16 dB, RSSI[curr -77, avg -77, thresh -83..-77] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 11 dB: max 16 dB, RSSI[curr -82, avg -82, thresh -83..-77] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 30 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Keeping DL attenuation at 16 dB: max 30 dB, RSSI[curr -80, avg -80, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 16 dB => 14 dB:max 30 dB, RSSI[curr -84, avg -82, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Lowering DL attenuation 14 dB => 11 dB:max 30 dB, RSSI[curr -84, avg -83, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 11 dB => 12 dB:max 30 dB, RSSI[curr -75, avg -79, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0), DTx is disabled => using FULL
+(bts=0,trx=0,ts=0,ss=0) Raising DL attenuation 12 dB => 14 dB:max 30 dB, RSSI[curr -75, avg -77, thresh -80..-80] dBm, RxQual[curr 0, avg 0, thresh 3..0]
diff --git a/tests/power/bs_power_loop_test.ok b/tests/power/bs_power_loop_test.ok
new file mode 100644
index 00000000..18a94ba7
--- /dev/null
+++ b/tests/power/bs_power_loop_test.ok
@@ -0,0 +1,360 @@
+Testing BS Power loop...
+
+Starting test case 'TC_fixed_mode'
+#00 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)
+#01 exec_power_step() <- Dynamic power control is disabled
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(63), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(00), RXQUAL-SUB(7)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 00 7e 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(50), RXQUAL-FULL(1), RXLEV-SUB(50), RXQUAL-SUB(1)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 32 32 12 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_rxlev_target'
+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_rxlev_max_min'
+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 2 (expected 2)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 4 (expected 4)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 6 (expected 6)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 8 (expected 8)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 10 (expected 10)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 12 (expected 12)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 14 (expected 14)
+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 16 (expected 16)
+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 18 (expected 18)
+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 18 -> 20 (expected 20)
+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)
+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)
+#13 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#13 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#13 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 16 (expected 16)
+#14 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#14 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#14 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 12 (expected 12)
+#15 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#15 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#15 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 8 (expected 8)
+#16 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#16 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#16 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)
+#17 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#17 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#17 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 0 (expected 0)
+#18 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#18 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#18 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#19 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#19 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#19 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_inc_red_step_size'
+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#01 exec_power_step() <- Set step size: inc 6 dB, red 4 dB
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 4 (expected 4)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 8 (expected 8)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 12 (expected 12)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 16 (expected 16)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 20 (expected 20)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)
+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 14 (expected 14)
+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 8 (expected 8)
+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 2 (expected 2)
+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 0 (expected 0)
+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#13 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)
+#14 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)
+#14 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#14 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 11 (expected 11)
+#15 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#15 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#15 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 11 (expected 11)
+#16 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(32), RXQUAL-FULL(0), RXLEV-SUB(32), RXQUAL-SUB(0)
+#16 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#16 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 13 (expected 13)
+#17 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#17 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#17 lchan_bs_pwr_ctrl() -> BS power reduction: 13 -> 13 (expected 13)
+#18 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0)
+#18 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 21 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#18 lchan_bs_pwr_ctrl() -> BS power reduction: 13 -> 16 (expected 16)
+#19 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#19 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#19 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#20 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)
+#21 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(29), RXQUAL-FULL(0), RXLEV-SUB(29), RXQUAL-SUB(0)
+#21 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1d 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#21 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 9 (expected 9)
+#22 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#22 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#22 lchan_bs_pwr_ctrl() -> BS power reduction: 9 -> 9 (expected 9)
+#23 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(27), RXQUAL-FULL(0), RXLEV-SUB(27), RXQUAL-SUB(0)
+#23 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1b 1b 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#23 lchan_bs_pwr_ctrl() -> BS power reduction: 9 -> 6 (expected 6)
+#24 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#24 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#24 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 6 (expected 6)
+#25 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(25), RXQUAL-FULL(0), RXLEV-SUB(25), RXQUAL-SUB(0)
+#25 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 19 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#25 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 1 (expected 1)
+#26 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#26 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#26 lchan_bs_pwr_ctrl() -> BS power reduction: 1 -> 1 (expected 1)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_dtxd_mode'
+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#03 exec_power_step() <- Enable DTXd
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 1e 70 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(0)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 30 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_rxqual_ber'
+#00 exec_power_step() <- State (re)set (current 16 dB, max 20 dB)
+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(2), RXLEV-SUB(30), RXQUAL-SUB(2)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 24 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(3)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 36 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(4), RXLEV-SUB(30), RXQUAL-SUB(4)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 48 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 12 (expected 12)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(34), RXQUAL-FULL(5), RXLEV-SUB(34), RXQUAL-SUB(5)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 22 22 5a 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 8 (expected 8)
+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(38), RXQUAL-FULL(6), RXLEV-SUB(38), RXQUAL-SUB(6)
+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 26 26 6c 00 00 00 00 00 00 00 00 00 00 00 00 00
+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)
+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(42), RXQUAL-FULL(7), RXLEV-SUB(42), RXQUAL-SUB(7)
+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 2a 2a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00
+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 0 (expected 0)
+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(46), RXQUAL-FULL(7), RXLEV-SUB(46), RXQUAL-SUB(7)
+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 2e 2e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00
+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(46), RXQUAL-FULL(0), RXLEV-SUB(46), RXQUAL-SUB(0)
+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 2e 2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 2 (expected 2)
+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(44), RXQUAL-FULL(0), RXLEV-SUB(44), RXQUAL-SUB(0)
+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 2c 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 4 (expected 4)
+#13 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(42), RXQUAL-FULL(0), RXLEV-SUB(42), RXQUAL-SUB(0)
+#13 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 2a 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#13 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 6 (expected 6)
+#14 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#15 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)
+#15 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00
+#15 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+#16 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)
+#16 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00
+#16 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_ctrl_interval'
+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)
+#01 exec_power_step() <- (Re)set power control interval: 0 -> 0
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 2 (expected 2)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 4 (expected 4)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 6 (expected 6)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 8 (expected 8)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 0 (expected 0)
+#08 exec_power_step() <- (Re)set power control interval: 0 -> 1
+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 2 (expected 2)
+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 2 (expected 2)
+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 4 (expected 4)
+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 4 (expected 4)
+#13 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#13 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#13 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 6 (expected 6)
+#14 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#14 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#14 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 6 (expected 6)
+#15 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#15 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#15 lchan_bs_pwr_ctrl() -> BS power reduction: 6 -> 8 (expected 8)
+#16 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)
+#16 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#16 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 8 (expected 8)
+#17 exec_power_step() <- (Re)set power control interval: 1 -> 2
+#18 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#18 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#18 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)
+#19 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#19 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#19 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 4 (expected 4)
+#20 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#20 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#20 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 4 (expected 4)
+#21 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#21 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#21 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 4 (expected 4)
+#22 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)
+#22 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#22 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 0 (expected 0)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_rxlev_hyst'
+#00 exec_power_step() <- State (re)set (current 12 dB, max 16 dB)
+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)
+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 13 (expected 13)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 13 -> 11 (expected 11)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 21 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 13 (expected 13)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 13 -> 11 (expected 11)
+#05 exec_power_step() <- (Re)set RxLev params (thresh 27 .. 33, averaging is disabled)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 11 (expected 11)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 11 (expected 11)
+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0)
+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 21 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 11 (expected 11)
+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)
+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 11 (expected 11)
+Test case verdict: SUCCESS
+
+Starting test case 'TC_rxlev_pf_ewma'
+#00 exec_power_step() <- State (re)set (current 16 dB, max 30 dB)
+#01 exec_power_step() <- (Re)set RxLev params (thresh 30 .. 30, averaging is enabled)
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1a 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 14 (expected 14)
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1a 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 11 (expected 11)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 23 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 12 (expected 12)
+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0)
+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 23 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 14 (expected 14)
+Test case verdict: SUCCESS
diff --git a/tests/power/ms_power_loop_test.c b/tests/power/ms_power_loop_test.c
new file mode 100644
index 00000000..47df68e2
--- /dev/null
+++ b/tests/power/ms_power_loop_test.c
@@ -0,0 +1,433 @@
+/*
+ * (C) 2013,2014 by Holger Hans Peter Freyther
+ * Contributions by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * 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 Affero 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 <osmocom/core/talloc.h>
+#include <osmocom/core/application.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/power_control.h>
+
+#include <stdio.h>
+
+#define PWR_TEST_RXLEV_TARGET_DBM -75
+#define PWR_TEST_RXLEV_TARGET \
+ dbm2rxlev(PWR_TEST_RXLEV_TARGET_DBM)
+
+static struct gsm_bts *g_bts = NULL;
+static struct gsm_bts_trx *g_trx = NULL;
+
+static void init_test(const char *name)
+{
+ if (g_trx != NULL)
+ talloc_free(g_trx);
+ if (g_bts != NULL)
+ talloc_free(g_bts);
+
+ g_bts = talloc_zero(tall_bts_ctx, struct gsm_bts);
+ OSMO_ASSERT(g_bts != NULL);
+
+ INIT_LLIST_HEAD(&g_bts->trx_list);
+ g_trx = gsm_bts_trx_alloc(g_bts);
+ OSMO_ASSERT(g_trx != NULL);
+
+ g_trx->ms_pwr_ctl_soft = true;
+
+ g_bts->band = GSM_BAND_1800;
+ g_bts->c0 = g_trx;
+
+ /* Init default MS power control parameters, enable dynamic power control */
+ struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].ms_dpc_params;
+ g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_params = params;
+ *params = power_ctrl_params_def;
+
+ /* Disable loop SACCH block skip by default: */
+ params->ctrl_interval = 0;
+
+ /* Disable RxLev pre-processing and hysteresis by default */
+ struct gsm_power_ctrl_meas_params *mp = &params->rxlev_meas;
+ mp->lower_thresh = mp->upper_thresh = PWR_TEST_RXLEV_TARGET;
+ mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE;
+
+ printf("\nStarting test case '%s'\n", name);
+}
+
+static void apply_power_test_ext(struct gsm_lchan *lchan, uint8_t ms_pwr, int rxlev, int lqual_cb, int exp_ret, uint8_t exp_current)
+{
+ int ret;
+
+ ret = lchan_ms_pwr_ctrl(lchan, ms_pwr, rxlev, lqual_cb);
+
+ /* Keep the measurement counter updated */
+ lchan->meas.res_nr++;
+
+ printf("lchan_ms_pwr_ctrl(RxLvl=%d dBm) returns %d (expected %d)\n",
+ rxlev, ret, exp_ret);
+ printf("\tMS current power %u -> %u (expected %u)\n",
+ ms_pwr, lchan->ms_power_ctrl.current, exp_current);
+}
+
+static inline void apply_power_test(struct gsm_lchan *lchan, int rxlev, int lqual_cb, int exp_ret, uint8_t exp_current)
+{
+ apply_power_test_ext(lchan, lchan->ms_power_ctrl.current, rxlev, lqual_cb, exp_ret, exp_current);
+}
+
+static void test_power_loop(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ params = lchan->ms_power_ctrl.dpc_params;
+ lchan->type = GSM_LCHAN_SDCCH;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+
+ lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
+
+ /* Simply clamping */
+ apply_power_test(lchan, -60, good_lqual, 0, 15);
+
+ /*
+ * Now 15 dB too little and we should power it up. Could be a
+ * power level of 7 or 8 for 15 dBm. However, since we limit peace at
+ * which we change values, expect several steps of MS_RAISE_MAX_DB/2 levels:
+ */
+ apply_power_test(lchan, -90, good_lqual, 1, 13);
+ apply_power_test(lchan, -90, good_lqual, 1, 11);
+ apply_power_test(lchan, -90, good_lqual, 1, 9);
+ apply_power_test(lchan, -90, good_lqual, 1, 7);
+ apply_power_test(lchan, -90, good_lqual, 1, 5);
+
+ /* Check good RSSI value keeps it at same power level: */
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, good_lqual, 0, 5);
+
+ apply_power_test(lchan, -90, good_lqual, 1, 3);
+ apply_power_test(lchan, -90, good_lqual, 1, 2); /* .max is pwr lvl 2 */
+ apply_power_test(lchan, -90, good_lqual, 0, 2); /* .max is pwr lvl 2 */
+
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 30);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 0);
+ apply_power_test(lchan, -90, good_lqual, 1, 0); /* .max is pwr lvl 0 */
+ apply_power_test(lchan, -90, good_lqual, 0, 0); /* .max is pwr lvl 0 */
+
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 36);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 29);
+ apply_power_test(lchan, -90, good_lqual, 1, 30);
+ apply_power_test(lchan, -90, good_lqual, 1, 29);
+ apply_power_test(lchan, -90, good_lqual, 0, 29);
+
+ /* Check good RSSI value keeps it at same power level: */
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, good_lqual, 0, 29);
+
+ /* Now go down, steps are double size in this direction: */
+ apply_power_test(lchan, -45, good_lqual, 1, 1);
+ apply_power_test(lchan, -45, good_lqual, 1, 5);
+ apply_power_test(lchan, -45, good_lqual, 1, 9);
+
+ /* Go down only one level down and up: */
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, good_lqual, 1, 10);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 2, good_lqual, 1, 9);
+
+ /* Check if BSC requesting a low max power is applied after loop calculation: */
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 2);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 14);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, good_lqual, 1, 14);
+ /* Set back a more normal max: */
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 30);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 0);
+
+ /* Disable dynamic power control and jump down */
+ lchan->ms_power_ctrl.dpc_params = NULL;
+ apply_power_test(lchan, -60, good_lqual, 0, 14);
+
+ /* Enable and leave it again */
+ lchan->ms_power_ctrl.dpc_params = &lchan->ms_dpc_params;
+ apply_power_test(lchan, -40, good_lqual, 1, 15);
+}
+
+static void test_pf_algo_ewma(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual;
+ const int *avg100;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ lchan->type = GSM_LCHAN_SDCCH;
+ params = lchan->ms_power_ctrl.dpc_params;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+ avg100 = &lchan->ms_power_ctrl.rxlev_meas_proc.ewma.Avg100;
+
+ struct gsm_power_ctrl_meas_params *mp = &lchan->ms_dpc_params.rxlev_meas;
+ mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA;
+ mp->ewma.alpha = 20; /* 80% smoothing */
+
+ lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
+
+#define CHECK_RXLEV_AVG100(exp) \
+ printf("\tAvg[t] is RxLev %2.2f (expected %2.2f)\n", \
+ ((float) *avg100) / 100, exp);
+
+ /* UL RSSI remains constant => no UL power change */
+ apply_power_test(lchan, -75, good_lqual, 0, 15);
+ CHECK_RXLEV_AVG100((float)dbm2rxlev(-75)); /* RXLEV 35 */
+
+ /* Avg[t] = (0.2 * 20) + (0.8 * 35) = RXLEV 32, (-78 dBm) */
+ apply_power_test(lchan, -90, good_lqual, 1, 13); /* -90 dBm = RXLEV 20 */
+ CHECK_RXLEV_AVG100(32.00);
+
+ /* Avg[t] = (0.2 * 20) + (0.8 * 32) = RXLEV 29.6 (-80.4 dBm) */
+ apply_power_test(lchan, -90, good_lqual, 1, 11); /* -90 dBm = RXLEV 20 */
+ CHECK_RXLEV_AVG100(29.60);
+
+ /* Avg[t] = (0.2 * 40) + (0.8 * 29.60) = RXLEV 31.68 (-78.32 dBm),
+ * but due to up-/down-scaling artefacts we get the following:
+ * Avg100[t] = Avg100[t - 1] + A * (Pwr - Avg[t] / 100)
+ * Avg100[t] = 2960 + 20 * (40 - ((2960+50) / 100)) <- HERE we lose 0.1: (2960+50) / 100) = 30.1
+ * Avg100[t] = 2960 + 20 * (40 - 30) <- HERE we lose 20*0.1 = 2.0! (upscaled, hence we lose finally 2.0/100=0.2)
+ * Avg[t] = (3160) / 100 = 31.60*/
+ apply_power_test(lchan, -70, good_lqual, 1, 9); /* RXLEV 40 */
+ CHECK_RXLEV_AVG100(31.60);
+
+ mp->ewma.alpha = 70; /* 30% smoothing */
+ lchan->ms_power_ctrl.current = 15;
+ lchan->ms_power_ctrl.rxlev_meas_proc = \
+ (struct gsm_power_ctrl_meas_proc_state) { 0 };
+
+ /* This is the first sample, the filter outputs it as-is */
+ apply_power_test(lchan, -50, good_lqual, 0, 15); /* RXLEV 60 */
+ CHECK_RXLEV_AVG100((float)dbm2rxlev(-50));
+
+ /* Avg[t] = (0.7 * 60) + (0.3 * 60) = RXLEV 60 (-50.0 dBm) */
+ apply_power_test(lchan, -50, good_lqual, 0, 15);
+ CHECK_RXLEV_AVG100((float)dbm2rxlev(-50));
+
+ /* Simulate SACCH block loss (-110 dBm):
+ * Avg[t] = (0.7 * 0) + (0.3 * 60) = RXLEV 18.0 (-92.0 dBm) */
+ apply_power_test(lchan, -110, good_lqual, 1, 13); /* RXLEV 0 */
+ CHECK_RXLEV_AVG100(18.0);
+}
+
+static void test_power_hysteresis(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ lchan->type = GSM_LCHAN_SDCCH;
+ params = lchan->ms_power_ctrl.dpc_params;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+
+ /* Tolerate power deviations in range -80 .. -70 */
+ lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30;
+ lchan->ms_dpc_params.rxlev_meas.upper_thresh = 40;
+
+ lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
+
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, good_lqual, 0, 15);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 3, good_lqual, 0, 15);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 3, good_lqual, 0, 15);
+
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, good_lqual, 0, 15);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 5, good_lqual, 0, 15);
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 5, good_lqual, 0, 15);
+
+ apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 10, good_lqual, 1, 13);
+}
+
+static void test_power_ctrl_interval(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual;
+ unsigned int i, j;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ lchan->type = GSM_LCHAN_SDCCH;
+ params = lchan->ms_power_ctrl.dpc_params;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
+
+ const int script[][8][4] = {
+ { /* P_Con_INTERVAL=0 (480 ms) */
+ /* { UL RxLev, expected rc, expected Tx power level } */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 13 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 11 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 9 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 7 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 5 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 3 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 2 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 2 },
+ },
+ { /* P_Con_INTERVAL=1 (960 ms) */
+ /* { UL RxLev, expected rc, expected Tx power level } */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 13 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 13 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 11 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 11 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 9 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 9 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 7 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 7 }, /* skipped */
+ },
+ { /* P_Con_INTERVAL=2 (1920 ms) */
+ /* { UL RxLev, expected rc, expected Tx power level } */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 13 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 13 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 13 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 13 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 1, 11 },
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 11 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 11 }, /* skipped */
+ { PWR_TEST_RXLEV_TARGET_DBM - 15, good_lqual, 0, 11 }, /* skipped */
+ },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(script); i++) {
+ lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+
+ /* Set the corresponding power control interval */
+ printf("%s(): power control interval is now %u\n", __func__, i);
+ lchan->ms_dpc_params.ctrl_interval = i;
+
+ for (j = 0; j < ARRAY_SIZE(script[i]); j++) {
+ apply_power_test(lchan, script[i][j][0], /* UL RxLev */
+ script[i][j][1], /* UL C/I */
+ script[i][j][2], /* expected rc */
+ script[i][j][3]); /* expected Tx power level */
+ }
+
+ printf("\n");
+ }
+}
+
+static void test_power_loop_ci(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual, too_low_lqual, too_high_lqual;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ params = lchan->ms_power_ctrl.dpc_params;
+ lchan->type = GSM_LCHAN_SDCCH;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+ too_low_lqual = (params->ci_sdcch_meas.lower_thresh - 1) * 10;
+ too_high_lqual = (params->ci_sdcch_meas.upper_thresh + 1) * 10;
+
+ lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
+ OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
+
+ /* Simply clamping */
+ apply_power_test(lchan, -60, good_lqual, 0, 15);
+
+ /* Now UL C/I is too bad as well as RSSI: */
+ apply_power_test(lchan, -100, too_low_lqual, 1, 13);
+ apply_power_test(lchan, -100, too_low_lqual, 1, 11);
+
+ /* Now UL C/I is good again while RSSI is good: */
+ apply_power_test(lchan, -60, good_lqual, 1, 12);
+ apply_power_test(lchan, -60, too_high_lqual, 1, 13);
+
+ /* Now UL C/I is good while RSSI is bad, C/I mandates: */
+ apply_power_test(lchan, -100, good_lqual, 1, 11);
+ apply_power_test(lchan, -100, too_high_lqual, 1, 12);
+
+ /* Now UL C/I is bad again while RSSI is good, C/I mandates: */
+ apply_power_test(lchan, -60, good_lqual, 1, 13);
+ apply_power_test(lchan, -60, too_high_lqual, 1, 14);
+}
+
+/* Test whether ping pong between requested MS Power Level and announced MS
+ * Power level occurs, oscillating between considered good levels all the time:
+ * FIXME: Current code shows there's an issue with oscillating values. */
+static void test_good_threshold_convergence(void)
+{
+ struct gsm_lchan *lchan;
+ const struct gsm_power_ctrl_params *params;
+ int16_t good_lqual, good_rxlev;
+
+ init_test(__func__);
+ lchan = &g_trx->ts[0].lchan[0];
+ params = lchan->ms_power_ctrl.dpc_params;
+ lchan->ms_dpc_params.rxlev_meas.upper_thresh = 37;
+ lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30;
+ lchan->type = GSM_LCHAN_SDCCH;
+ good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
+ good_rxlev = rxlev2dbm(params->rxlev_meas.lower_thresh + 2);
+
+ lchan->ms_power_ctrl.current = 10;
+ lchan->ms_power_ctrl.max = 2;
+
+ apply_power_test_ext(lchan, 9, good_rxlev, good_lqual, 0, 10);
+ apply_power_test_ext(lchan, 10, good_rxlev, good_lqual, 0, 10);
+ apply_power_test_ext(lchan, 9, good_rxlev, good_lqual, 0, 10);
+ apply_power_test_ext(lchan, 10, good_rxlev, good_lqual, 0, 10);
+ apply_power_test_ext(lchan, 9, good_rxlev, good_lqual, 0, 10);
+}
+
+int main(int argc, char **argv)
+{
+ printf("Testing power loop...\n");
+
+ tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
+ msgb_talloc_ctx_init(tall_bts_ctx, 0);
+
+ osmo_init_logging2(tall_bts_ctx, &bts_log_info);
+ osmo_stderr_target->categories[DLOOP].loglevel = LOGL_DEBUG;
+ osmo_stderr_target->categories[DL1C].loglevel = LOGL_DEBUG;
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+
+ test_power_loop();
+ test_pf_algo_ewma();
+ test_power_hysteresis();
+ test_power_ctrl_interval();
+ test_power_loop_ci();
+ test_good_threshold_convergence();
+
+ printf("Power loop test OK\n");
+
+ return 0;
+}
diff --git a/tests/power/ms_power_loop_test.err b/tests/power/ms_power_loop_test.err
new file mode 100644
index 00000000..07d90691
--- /dev/null
+++ b/tests/power/ms_power_loop_test.err
@@ -0,0 +1,65 @@
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (12 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 9 (12 dBm) => 7 (16 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 7 (16 dBm) => 5 (20 dBm): ms-pwr-lvl[curr 7, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 5 (20 dBm): ms-pwr-lvl[curr 5, max 2], RSSI[curr -75, avg -75, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 5 (20 dBm) => 3 (24 dBm): ms-pwr-lvl[curr 5, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 3 (24 dBm) => 2 (26 dBm): ms-pwr-lvl[curr 3, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 2 (26 dBm): ms-pwr-lvl[curr 2, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 2 (26 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 2, max 0], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 0 (30 dBm): ms-pwr-lvl[curr 0, max 0], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 0 (30 dBm) => 30 (34 dBm): ms-pwr-lvl[curr 0, max 29], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 30 (34 dBm) => 29 (36 dBm): ms-pwr-lvl[curr 30, max 29], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 29 (36 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 29 (36 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -75, avg -75, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 29 (36 dBm) => 30 (34 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 30 (34 dBm) => 31 (32 dBm): ms-pwr-lvl[curr 30, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 31 (32 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 31, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 0 (30 dBm) => 1 (28 dBm): ms-pwr-lvl[curr 0, max 29], RSSI[curr -73, avg -73, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 1 (28 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 1, max 29], RSSI[curr -77, avg -77, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 0 (30 dBm) => 14 (2 dBm): ms-pwr-lvl[curr 0, max 14], RSSI[curr -73, avg -73, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 14 (2 dBm) => 15 (0 dBm): ms-pwr-lvl[curr 14, max 0], RSSI[curr -40, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -75, avg -75, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (3 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -78, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -80, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (11 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -70, avg -78, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -50, avg -50, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -50, avg -50, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -110, avg -92, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -75, avg -75, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -72, avg -72, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -78, avg -78, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -75, avg -75, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -70, avg -70, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -80, avg -80, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -85, avg -85, thresh -80..-70] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (12 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 9 (12 dBm) => 7 (16 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 7 (16 dBm) => 5 (20 dBm): ms-pwr-lvl[curr 7, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 5 (20 dBm) => 3 (24 dBm): ms-pwr-lvl[curr 5, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 3 (24 dBm) => 2 (26 dBm): ms-pwr-lvl[curr 3, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 2 (26 dBm): ms-pwr-lvl[curr 2, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (12 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 9 (12 dBm) => 7 (16 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -100, avg -100, thresh -75..-75] dBm, C/I[curr 11, avg 11, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -100, avg -100, thresh -75..-75] dBm, C/I[curr 11, avg 11, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 11 (8 dBm) => 12 (6 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 12 (6 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 12, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 17, avg 17, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -100, avg -100, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 11 (8 dBm) => 12 (6 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -100, avg -100, thresh -75..-75] dBm, C/I[curr 17, avg 17, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 12 (6 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 12, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 13 (4 dBm) => 14 (2 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -60, avg -60, thresh -75..-75] dBm, C/I[curr 17, avg 17, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 9 (12 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -78, avg -78, thresh -80..-73] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 10 (10 dBm): ms-pwr-lvl[curr 10, max 2], RSSI[curr -78, avg -78, thresh -80..-73] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 9 (12 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -78, avg -78, thresh -80..-73] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 10 (10 dBm): ms-pwr-lvl[curr 10, max 2], RSSI[curr -78, avg -78, thresh -80..-73] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
+(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 9 (12 dBm): ms-pwr-lvl[curr 9, max 2], RSSI[curr -78, avg -78, thresh -80..-73] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
diff --git a/tests/power/ms_power_loop_test.ok b/tests/power/ms_power_loop_test.ok
new file mode 100644
index 00000000..09e19ad4
--- /dev/null
+++ b/tests/power/ms_power_loop_test.ok
@@ -0,0 +1,179 @@
+Testing power loop...
+
+Starting test case 'test_power_loop'
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 11 -> 9 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 9 -> 7 (expected 7)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 7 -> 5 (expected 5)
+lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
+ MS current power 5 -> 5 (expected 5)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 5 -> 3 (expected 3)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 3 -> 2 (expected 2)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 2 -> 2 (expected 2)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 2 -> 0 (expected 0)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 0 -> 0 (expected 0)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 0 -> 30 (expected 30)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 30 -> 29 (expected 29)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 29 -> 29 (expected 29)
+lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
+ MS current power 29 -> 29 (expected 29)
+lchan_ms_pwr_ctrl(RxLvl=-45 dBm) returns 1 (expected 1)
+ MS current power 29 -> 30 (expected 1)
+lchan_ms_pwr_ctrl(RxLvl=-45 dBm) returns 1 (expected 1)
+ MS current power 30 -> 31 (expected 5)
+lchan_ms_pwr_ctrl(RxLvl=-45 dBm) returns 1 (expected 1)
+ MS current power 31 -> 0 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-73 dBm) returns 1 (expected 1)
+ MS current power 0 -> 1 (expected 10)
+lchan_ms_pwr_ctrl(RxLvl=-77 dBm) returns 1 (expected 1)
+ MS current power 1 -> 0 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-73 dBm) returns 1 (expected 1)
+ MS current power 0 -> 14 (expected 14)
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 0 (expected 0)
+ MS current power 14 -> 14 (expected 14)
+lchan_ms_pwr_ctrl(RxLvl=-40 dBm) returns 1 (expected 1)
+ MS current power 14 -> 15 (expected 15)
+
+Starting test case 'test_pf_algo_ewma'
+lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+ Avg[t] is RxLev 35.00 (expected 35.00)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+ Avg[t] is RxLev 32.00 (expected 32.00)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+ Avg[t] is RxLev 29.60 (expected 29.60)
+lchan_ms_pwr_ctrl(RxLvl=-70 dBm) returns 1 (expected 1)
+ MS current power 11 -> 9 (expected 9)
+ Avg[t] is RxLev 31.60 (expected 31.60)
+lchan_ms_pwr_ctrl(RxLvl=-50 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+ Avg[t] is RxLev 60.00 (expected 60.00)
+lchan_ms_pwr_ctrl(RxLvl=-50 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+ Avg[t] is RxLev 60.00 (expected 60.00)
+lchan_ms_pwr_ctrl(RxLvl=-110 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+ Avg[t] is RxLev 18.00 (expected 18.00)
+
+Starting test case 'test_power_hysteresis'
+lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-72 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-70 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-80 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-85 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+
+Starting test case 'test_power_ctrl_interval'
+test_power_ctrl_interval(): power control interval is now 0
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 11 -> 9 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 9 -> 7 (expected 7)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 7 -> 5 (expected 5)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 5 -> 3 (expected 3)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 3 -> 2 (expected 2)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 1)
+ MS current power 2 -> 2 (expected 2)
+
+test_power_ctrl_interval(): power control interval is now 1
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 13 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 11 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 11 -> 9 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 9 -> 9 (expected 9)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 9 -> 7 (expected 7)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 7 -> 7 (expected 7)
+
+test_power_ctrl_interval(): power control interval is now 2
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 13 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 13 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 13 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 11 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 11 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 0 (expected 0)
+ MS current power 11 -> 11 (expected 11)
+
+
+Starting test case 'test_power_loop_ci'
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 0 (expected 0)
+ MS current power 15 -> 15 (expected 15)
+lchan_ms_pwr_ctrl(RxLvl=-100 dBm) returns 1 (expected 1)
+ MS current power 15 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-100 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 1 (expected 1)
+ MS current power 11 -> 12 (expected 12)
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 1 (expected 1)
+ MS current power 12 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-100 dBm) returns 1 (expected 1)
+ MS current power 13 -> 11 (expected 11)
+lchan_ms_pwr_ctrl(RxLvl=-100 dBm) returns 1 (expected 1)
+ MS current power 11 -> 12 (expected 12)
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 1 (expected 1)
+ MS current power 12 -> 13 (expected 13)
+lchan_ms_pwr_ctrl(RxLvl=-60 dBm) returns 1 (expected 1)
+ MS current power 13 -> 14 (expected 14)
+
+Starting test case 'test_good_threshold_convergence'
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 9 -> 10 (expected 10)
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 10 -> 10 (expected 10)
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 9 -> 10 (expected 10)
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 10 -> 10 (expected 10)
+lchan_ms_pwr_ctrl(RxLvl=-78 dBm) returns 0 (expected 0)
+ MS current power 9 -> 10 (expected 10)
+Power loop test OK
diff --git a/tests/power/power_test.c b/tests/power/power_test.c
deleted file mode 100644
index a46a430c..00000000
--- a/tests/power/power_test.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * (C) 2013,2014 by Holger Hans Peter Freyther
- *
- * 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 <osmo-bts/bts.h>
-#include <osmo-bts/l1sap.h>
-#include <osmo-bts/power_control.h>
-
-#include <stdio.h>
-
-static inline void apply_power_test(struct gsm_lchan *lchan, int rxlev, int exp_ret, uint8_t exp_current)
-{
- int ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, rxlev);
-
- printf("power control [%d]: MS current power %u\n", ret, lchan->ms_power_ctrl.current);
- OSMO_ASSERT(ret == exp_ret);
- OSMO_ASSERT(lchan->ms_power_ctrl.current == exp_current);
-}
-
-static void test_power_loop(void)
-{
- struct gsm_bts bts;
- struct gsm_bts_trx trx;
- struct gsm_bts_trx_ts ts;
- struct gsm_lchan *lchan;
-
- memset(&bts, 0, sizeof(bts));
- memset(&trx, 0, sizeof(trx));
- memset(&ts, 0, sizeof(ts));
-
- lchan = &ts.lchan[0];
- lchan->ts = &ts;
- ts.trx = &trx;
- trx.bts = &bts;
- bts.band = GSM_BAND_1800;
- trx.ms_power_control = 1;
- bts.ul_power_target = -75;
-
- lchan->state = LCHAN_S_NONE;
- lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
- OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
-
- /* Simply clamping */
- apply_power_test(lchan, -60, 0, 15);
-
- /*
- * Now 15 dB too little and we should power it up. Could be a
- * power level of 7 or 8 for 15 dBm
- */
- apply_power_test(lchan, -90, 1, 7);
-
- /* It should be clamped to level 0 and 30 dBm */
- apply_power_test(lchan, -100, 1, 0);
-
- /* Fix it and jump down */
- lchan->ms_power_ctrl.fixed = 1;
- apply_power_test(lchan, -60, 0, 0);
-
- /* And leave it again */
- lchan->ms_power_ctrl.fixed = 0;
- apply_power_test(lchan, -40, 1, 15);
-}
-
-int main(int argc, char **argv)
-{
- printf("Testing power loop...\n");
-
- test_power_loop();
-
- printf("Power loop test OK\n");
-
- return 0;
-}
diff --git a/tests/power/power_test.ok b/tests/power/power_test.ok
deleted file mode 100644
index cf0a38b4..00000000
--- a/tests/power/power_test.ok
+++ /dev/null
@@ -1,7 +0,0 @@
-Testing power loop...
-power control [0]: MS current power 15
-power control [1]: MS current power 7
-power control [1]: MS current power 0
-power control [0]: MS current power 0
-power control [1]: MS current power 15
-Power loop test OK
diff --git a/tests/stubs.c b/tests/stubs.c
index 7c64034b..72a77a5e 100644
--- a/tests/stubs.c
+++ b/tests/stubs.c
@@ -1,7 +1,10 @@
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_model.h>
struct femtol1_hdl;
struct bts_model_set_dyn_pdch_data;
+struct phy_link;
+struct phy_instance;
/*
* Stubs to provide an empty bts model implementation for testing.
@@ -15,14 +18,14 @@ int bts_model_init(struct gsm_bts *bts)
{ return 0; }
int bts_model_trx_init(struct gsm_bts_trx *trx)
{ return 0; }
-int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
- struct tlv_parsed *new_attr, int kind, void *obj)
+int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
+ struct gsm_abis_mo *mo, void *obj)
{ return 0; }
int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
{ return 0; }
-int bts_model_trx_close(struct gsm_bts_trx *trx)
-{ return 0; }
+void bts_model_trx_close(struct gsm_bts_trx *trx)
+{ bts_model_trx_close_cb(trx, 0); }
int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
struct tlv_parsed *old_attr, struct tlv_parsed *new_attr,
void *obj)
@@ -30,13 +33,16 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
void *obj)
{ return 0; }
-int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
+__attribute__((weak)) int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
+{ return 0; }
+
+uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx)
{ return 0; }
-uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx)
+__attribute__((weak)) int bts_model_oml_estab(struct gsm_bts *bts)
{ return 0; }
-int bts_model_oml_estab(struct gsm_bts *bts)
+__attribute__((weak)) int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
{ return 0; }
int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power)
@@ -48,7 +54,7 @@ int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { return 0; }
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
{ return 0; }
-void bts_model_abis_close(struct gsm_bts *bts)
+__attribute__((weak)) void bts_model_abis_close(struct gsm_bts *bts)
{ }
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
@@ -57,3 +63,12 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
void bts_model_ts_connect(struct gsm_bts_trx_ts *ts,
enum gsm_phys_chan_config as_pchan)
{ return; }
+
+void bts_model_phy_link_set_defaults(struct phy_link *plink)
+{ return; }
+
+void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
+{ return; }
+
+int bts_model_phy_link_open(struct phy_link *plink)
+{ return 0; }
diff --git a/tests/sysmobts/Makefile.am b/tests/sysmobts/Makefile.am
index 0829ca52..ff80fb34 100644
--- a/tests/sysmobts/Makefile.am
+++ b/tests/sysmobts/Makefile.am
@@ -1,11 +1,36 @@
-AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_srcdir)/src/osmo-bts-sysmo $(SYSMOBTS_INCDIR)
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS)
+AM_CPPFLAGS = \
+ $(all_includes) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/osmo-bts-sysmo \
+ $(SYSMOBTS_INCDIR) \
+ $(NULL)
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
-noinst_PROGRAMS = sysmobts_test
+check_PROGRAMS = sysmobts_test
EXTRA_DIST = sysmobts_test.ok
-sysmobts_test_SOURCES = sysmobts_test.c $(top_srcdir)/src/osmo-bts-sysmo/utils.c \
+sysmobts_test_SOURCES = \
+ sysmobts_test.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/utils.c \
$(top_srcdir)/src/osmo-bts-sysmo/l1_if.c \
$(top_srcdir)/src/osmo-bts-sysmo/oml.c \
$(top_srcdir)/src/osmo-bts-sysmo/l1_transp_hw.c \
@@ -13,5 +38,9 @@ sysmobts_test_SOURCES = sysmobts_test.c $(top_srcdir)/src/osmo-bts-sysmo/utils.c
$(top_srcdir)/src/osmo-bts-sysmo/calib_file.c \
$(top_srcdir)/src/osmo-bts-sysmo/calib_fixup.c \
$(top_srcdir)/src/osmo-bts-sysmo/misc/sysmobts_par.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/femtobts.c \
$(top_srcdir)/src/osmo-bts-sysmo/eeprom.c
-sysmobts_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)
+sysmobts_test_LDADD = \
+ $(top_builddir)/src/common/libbts.a \
+ $(LDADD) \
+ $(NULL)
diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c
index 4b01ed7a..27273d8d 100644
--- a/tests/sysmobts/sysmobts_test.c
+++ b/tests/sysmobts/sysmobts_test.c
@@ -11,7 +11,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -52,14 +52,17 @@ static void test_sysmobts_auto_band(void)
{
struct gsm_bts bts;
struct gsm_bts_trx trx;
+ struct phy_instance pinst;
struct femtol1_hdl hdl;
int i;
memset(&bts, 0, sizeof(bts));
memset(&trx, 0, sizeof(trx));
+ memset(&pinst, 0, sizeof(pinst));
memset(&hdl, 0, sizeof(hdl));
trx.bts = &bts;
- trx.role_bts.l1h = &hdl;
+ trx.pinst = &pinst;
+ trx.pinst->u.sysmobts.hdl = &hdl;
/* claim to support all hw_info's */
hdl.hw_info.band_support = GSM_BAND_850 | GSM_BAND_900 |
diff --git a/tests/ta_control/Makefile.am b/tests/ta_control/Makefile.am
new file mode 100644
index 00000000..12c32ac3
--- /dev/null
+++ b/tests/ta_control/Makefile.am
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+
+check_PROGRAMS = ta_control_test
+EXTRA_DIST = ta_control_test.ok
+ta_control_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
diff --git a/tests/ta_control/ta_control_test.c b/tests/ta_control/ta_control_test.c
new file mode 100644
index 00000000..253491a8
--- /dev/null
+++ b/tests/ta_control/ta_control_test.c
@@ -0,0 +1,76 @@
+/* Test cases for tx_control.c Timing Advance Computation */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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 Affero 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 <osmocom/core/talloc.h>
+#include <osmocom/core/application.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/ta_control.h>
+#include <osmo-bts/bts_trx.h>
+
+void lchan_ms_ta_ctrl_test(int16_t toa256_start, unsigned int steps)
+{
+ struct gsm_bts_trx trx = { };
+ struct gsm_bts_trx_ts ts = { .trx = &trx };
+ struct gsm_lchan lchan = { .ts = &ts };
+ unsigned int i;
+ uint8_t rqd_ta_after;
+ uint8_t rqd_ta_before;
+ int16_t toa256 = toa256_start;
+
+ printf("toa256_start = %u / 256 = %u, steps = %u\n", toa256_start,
+ toa256_start / 256, steps);
+
+ for (i = 0; i < steps; i++) {
+ printf("Step #%u\n", i);
+ printf(" lchan.ta_ctrl.current (before) = %u\n", lchan.ta_ctrl.current);
+ printf(" toa256 (before) = %u / 256 = %u\n", toa256,
+ toa256 / 256);
+
+ rqd_ta_before = lchan.ta_ctrl.current;
+
+ lchan_ms_ta_ctrl(&lchan, rqd_ta_before, toa256);
+
+ rqd_ta_after = lchan.ta_ctrl.current;
+ toa256 -= (rqd_ta_after - rqd_ta_before) * 256;
+
+ printf(" lchan.ta_ctrl.current (after) = %u\n", lchan.ta_ctrl.current);
+ printf(" toa256 (after) = %u / 256 = %u\n", toa256,
+ toa256 / 256);
+ }
+
+ printf("Done.\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ void *tall_bts_ctx;
+
+ tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
+ osmo_init_logging2(tall_bts_ctx, &bts_log_info);
+
+ lchan_ms_ta_ctrl_test(16 * 256, 20);
+ lchan_ms_ta_ctrl_test(4000, 50);
+ lchan_ms_ta_ctrl_test(12345, 50);
+}
diff --git a/tests/ta_control/ta_control_test.ok b/tests/ta_control/ta_control_test.ok
new file mode 100644
index 00000000..a1586759
--- /dev/null
+++ b/tests/ta_control/ta_control_test.ok
@@ -0,0 +1,609 @@
+toa256_start = 4096 / 256 = 16, steps = 20
+Step #0
+ lchan.ta_ctrl.current (before) = 0
+ toa256 (before) = 4096 / 256 = 16
+ lchan.ta_ctrl.current (after) = 2
+ toa256 (after) = 3584 / 256 = 14
+Step #1
+ lchan.ta_ctrl.current (before) = 2
+ toa256 (before) = 3584 / 256 = 14
+ lchan.ta_ctrl.current (after) = 4
+ toa256 (after) = 3072 / 256 = 12
+Step #2
+ lchan.ta_ctrl.current (before) = 4
+ toa256 (before) = 3072 / 256 = 12
+ lchan.ta_ctrl.current (after) = 6
+ toa256 (after) = 2560 / 256 = 10
+Step #3
+ lchan.ta_ctrl.current (before) = 6
+ toa256 (before) = 2560 / 256 = 10
+ lchan.ta_ctrl.current (after) = 8
+ toa256 (after) = 2048 / 256 = 8
+Step #4
+ lchan.ta_ctrl.current (before) = 8
+ toa256 (before) = 2048 / 256 = 8
+ lchan.ta_ctrl.current (after) = 10
+ toa256 (after) = 1536 / 256 = 6
+Step #5
+ lchan.ta_ctrl.current (before) = 10
+ toa256 (before) = 1536 / 256 = 6
+ lchan.ta_ctrl.current (after) = 12
+ toa256 (after) = 1024 / 256 = 4
+Step #6
+ lchan.ta_ctrl.current (before) = 12
+ toa256 (before) = 1024 / 256 = 4
+ lchan.ta_ctrl.current (after) = 14
+ toa256 (after) = 512 / 256 = 2
+Step #7
+ lchan.ta_ctrl.current (before) = 14
+ toa256 (before) = 512 / 256 = 2
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #8
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #9
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #10
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #11
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #12
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #13
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #14
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #15
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #16
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #17
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #18
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Step #19
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 0 / 256 = 0
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 0 / 256 = 0
+Done.
+
+toa256_start = 4000 / 256 = 15, steps = 50
+Step #0
+ lchan.ta_ctrl.current (before) = 0
+ toa256 (before) = 4000 / 256 = 15
+ lchan.ta_ctrl.current (after) = 2
+ toa256 (after) = 3488 / 256 = 13
+Step #1
+ lchan.ta_ctrl.current (before) = 2
+ toa256 (before) = 3488 / 256 = 13
+ lchan.ta_ctrl.current (after) = 4
+ toa256 (after) = 2976 / 256 = 11
+Step #2
+ lchan.ta_ctrl.current (before) = 4
+ toa256 (before) = 2976 / 256 = 11
+ lchan.ta_ctrl.current (after) = 6
+ toa256 (after) = 2464 / 256 = 9
+Step #3
+ lchan.ta_ctrl.current (before) = 6
+ toa256 (before) = 2464 / 256 = 9
+ lchan.ta_ctrl.current (after) = 8
+ toa256 (after) = 1952 / 256 = 7
+Step #4
+ lchan.ta_ctrl.current (before) = 8
+ toa256 (before) = 1952 / 256 = 7
+ lchan.ta_ctrl.current (after) = 10
+ toa256 (after) = 1440 / 256 = 5
+Step #5
+ lchan.ta_ctrl.current (before) = 10
+ toa256 (before) = 1440 / 256 = 5
+ lchan.ta_ctrl.current (after) = 12
+ toa256 (after) = 928 / 256 = 3
+Step #6
+ lchan.ta_ctrl.current (before) = 12
+ toa256 (before) = 928 / 256 = 3
+ lchan.ta_ctrl.current (after) = 14
+ toa256 (after) = 416 / 256 = 1
+Step #7
+ lchan.ta_ctrl.current (before) = 14
+ toa256 (before) = 416 / 256 = 1
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #8
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #9
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #10
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #11
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #12
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #13
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #14
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #15
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #16
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #17
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #18
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #19
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #20
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #21
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #22
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #23
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #24
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #25
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #26
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #27
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #28
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #29
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #30
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #31
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #32
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #33
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #34
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #35
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #36
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #37
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #38
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #39
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #40
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #41
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #42
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #43
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #44
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #45
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #46
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #47
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #48
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Step #49
+ lchan.ta_ctrl.current (before) = 15
+ toa256 (before) = 160 / 256 = 0
+ lchan.ta_ctrl.current (after) = 15
+ toa256 (after) = 160 / 256 = 0
+Done.
+
+toa256_start = 12345 / 256 = 48, steps = 50
+Step #0
+ lchan.ta_ctrl.current (before) = 0
+ toa256 (before) = 12345 / 256 = 48
+ lchan.ta_ctrl.current (after) = 2
+ toa256 (after) = 11833 / 256 = 46
+Step #1
+ lchan.ta_ctrl.current (before) = 2
+ toa256 (before) = 11833 / 256 = 46
+ lchan.ta_ctrl.current (after) = 4
+ toa256 (after) = 11321 / 256 = 44
+Step #2
+ lchan.ta_ctrl.current (before) = 4
+ toa256 (before) = 11321 / 256 = 44
+ lchan.ta_ctrl.current (after) = 6
+ toa256 (after) = 10809 / 256 = 42
+Step #3
+ lchan.ta_ctrl.current (before) = 6
+ toa256 (before) = 10809 / 256 = 42
+ lchan.ta_ctrl.current (after) = 8
+ toa256 (after) = 10297 / 256 = 40
+Step #4
+ lchan.ta_ctrl.current (before) = 8
+ toa256 (before) = 10297 / 256 = 40
+ lchan.ta_ctrl.current (after) = 10
+ toa256 (after) = 9785 / 256 = 38
+Step #5
+ lchan.ta_ctrl.current (before) = 10
+ toa256 (before) = 9785 / 256 = 38
+ lchan.ta_ctrl.current (after) = 12
+ toa256 (after) = 9273 / 256 = 36
+Step #6
+ lchan.ta_ctrl.current (before) = 12
+ toa256 (before) = 9273 / 256 = 36
+ lchan.ta_ctrl.current (after) = 14
+ toa256 (after) = 8761 / 256 = 34
+Step #7
+ lchan.ta_ctrl.current (before) = 14
+ toa256 (before) = 8761 / 256 = 34
+ lchan.ta_ctrl.current (after) = 16
+ toa256 (after) = 8249 / 256 = 32
+Step #8
+ lchan.ta_ctrl.current (before) = 16
+ toa256 (before) = 8249 / 256 = 32
+ lchan.ta_ctrl.current (after) = 18
+ toa256 (after) = 7737 / 256 = 30
+Step #9
+ lchan.ta_ctrl.current (before) = 18
+ toa256 (before) = 7737 / 256 = 30
+ lchan.ta_ctrl.current (after) = 20
+ toa256 (after) = 7225 / 256 = 28
+Step #10
+ lchan.ta_ctrl.current (before) = 20
+ toa256 (before) = 7225 / 256 = 28
+ lchan.ta_ctrl.current (after) = 22
+ toa256 (after) = 6713 / 256 = 26
+Step #11
+ lchan.ta_ctrl.current (before) = 22
+ toa256 (before) = 6713 / 256 = 26
+ lchan.ta_ctrl.current (after) = 24
+ toa256 (after) = 6201 / 256 = 24
+Step #12
+ lchan.ta_ctrl.current (before) = 24
+ toa256 (before) = 6201 / 256 = 24
+ lchan.ta_ctrl.current (after) = 26
+ toa256 (after) = 5689 / 256 = 22
+Step #13
+ lchan.ta_ctrl.current (before) = 26
+ toa256 (before) = 5689 / 256 = 22
+ lchan.ta_ctrl.current (after) = 28
+ toa256 (after) = 5177 / 256 = 20
+Step #14
+ lchan.ta_ctrl.current (before) = 28
+ toa256 (before) = 5177 / 256 = 20
+ lchan.ta_ctrl.current (after) = 30
+ toa256 (after) = 4665 / 256 = 18
+Step #15
+ lchan.ta_ctrl.current (before) = 30
+ toa256 (before) = 4665 / 256 = 18
+ lchan.ta_ctrl.current (after) = 32
+ toa256 (after) = 4153 / 256 = 16
+Step #16
+ lchan.ta_ctrl.current (before) = 32
+ toa256 (before) = 4153 / 256 = 16
+ lchan.ta_ctrl.current (after) = 34
+ toa256 (after) = 3641 / 256 = 14
+Step #17
+ lchan.ta_ctrl.current (before) = 34
+ toa256 (before) = 3641 / 256 = 14
+ lchan.ta_ctrl.current (after) = 36
+ toa256 (after) = 3129 / 256 = 12
+Step #18
+ lchan.ta_ctrl.current (before) = 36
+ toa256 (before) = 3129 / 256 = 12
+ lchan.ta_ctrl.current (after) = 38
+ toa256 (after) = 2617 / 256 = 10
+Step #19
+ lchan.ta_ctrl.current (before) = 38
+ toa256 (before) = 2617 / 256 = 10
+ lchan.ta_ctrl.current (after) = 40
+ toa256 (after) = 2105 / 256 = 8
+Step #20
+ lchan.ta_ctrl.current (before) = 40
+ toa256 (before) = 2105 / 256 = 8
+ lchan.ta_ctrl.current (after) = 42
+ toa256 (after) = 1593 / 256 = 6
+Step #21
+ lchan.ta_ctrl.current (before) = 42
+ toa256 (before) = 1593 / 256 = 6
+ lchan.ta_ctrl.current (after) = 44
+ toa256 (after) = 1081 / 256 = 4
+Step #22
+ lchan.ta_ctrl.current (before) = 44
+ toa256 (before) = 1081 / 256 = 4
+ lchan.ta_ctrl.current (after) = 46
+ toa256 (after) = 569 / 256 = 2
+Step #23
+ lchan.ta_ctrl.current (before) = 46
+ toa256 (before) = 569 / 256 = 2
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #24
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #25
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #26
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #27
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #28
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #29
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #30
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #31
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #32
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #33
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #34
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #35
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #36
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #37
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #38
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #39
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #40
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #41
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #42
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #43
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #44
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #45
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #46
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #47
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #48
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Step #49
+ lchan.ta_ctrl.current (before) = 48
+ toa256 (before) = 57 / 256 = 0
+ lchan.ta_ctrl.current (after) = 48
+ toa256 (after) = 57 / 256 = 0
+Done.
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 2d1cefd3..6e2677e2 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -31,10 +31,18 @@ cat $abs_srcdir/handover/handover_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/handover/handover_test], [], [expout], [ignore])
AT_CLEANUP
-AT_SETUP([power])
+AT_SETUP([ms_power_loop])
AT_KEYWORDS([power])
-cat $abs_srcdir/power/power_test.ok > expout
-AT_CHECK([$abs_top_builddir/tests/power/power_test], [], [expout], [ignore])
+cat $abs_srcdir/power/ms_power_loop_test.ok > expout
+cat $abs_srcdir/power/ms_power_loop_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/power/ms_power_loop_test], [], [expout], [experr])
+AT_CLEANUP
+
+AT_SETUP([bs_power_loop])
+AT_KEYWORDS([power])
+cat $abs_srcdir/power/bs_power_loop_test.ok > expout
+cat $abs_srcdir/power/bs_power_loop_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/power/bs_power_loop_test], [], [expout], [experr])
AT_CLEANUP
AT_SETUP([tx_power])
@@ -47,5 +55,25 @@ AT_CLEANUP
AT_SETUP([meas])
AT_KEYWORDS([meas])
cat $abs_srcdir/meas/meas_test.ok > expout
-AT_CHECK([$abs_top_builddir/tests/meas/meas_test], [], [expout], [ignore])
+cat $abs_srcdir/meas/meas_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/meas/meas_test], [], [expout], [experr])
+AT_CLEANUP
+
+AT_SETUP([ta_control])
+AT_KEYWORDS([ta_control])
+cat $abs_srcdir/ta_control/ta_control_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/ta_control/ta_control_test], [], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([amr])
+AT_KEYWORDS([amr])
+cat $abs_srcdir/amr/amr_test.ok > expout
+cat $abs_srcdir/amr/amr_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/amr/amr_test], [], [expout], [experr])
+AT_CLEANUP
+
+AT_SETUP([csd])
+AT_KEYWORDS([csd])
+cat $abs_srcdir/csd/csd_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/csd/csd_test], [], [ignore], [experr])
AT_CLEANUP
diff --git a/tests/tx_power/Makefile.am b/tests/tx_power/Makefile.am
index cd7ccc2f..8c3db1eb 100644
--- a/tests/tx_power/Makefile.am
+++ b/tests/tx_power/Makefile.am
@@ -1,7 +1,23 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS)
-LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS)
-noinst_PROGRAMS = tx_power_test
+AM_CFLAGS = \
+ -Wall \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOTRAU_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
+ $(NULL)
+AM_LDFLAGS = -no-install
+LDADD = \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOTRAU_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
+ $(NULL)
+check_PROGRAMS = tx_power_test
EXTRA_DIST = tx_power_test.ok tx_power_test.err
tx_power_test_SOURCES = tx_power_test.c $(srcdir)/../stubs.c
diff --git a/tests/tx_power/tx_power_test.c b/tests/tx_power/tx_power_test.c
index ad3f68ce..e0f88bc9 100644
--- a/tests/tx_power/tx_power_test.c
+++ b/tests/tx_power/tx_power_test.c
@@ -12,7 +12,7 @@
* 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.
+ * GNU Affero 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/>.
@@ -20,6 +20,7 @@
*/
#include <stdint.h>
+#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/talloc.h>
@@ -27,9 +28,11 @@
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_sm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/tx_power.h>
+static bool power_ramp_finished = false;
static const struct trx_power_params tpp_1002 = {
.trx_p_max_out_mdBm = to_mdB(23),
@@ -120,9 +123,9 @@ static void test_sbts1002(struct gsm_bts_trx *trx)
/* at max_power_red = 2, we expect 21dBm */
OSMO_ASSERT(get_p_nominal_mdBm(trx) == to_mdB(21));
/* at 1 step (of 2dB), we expect full 23-2-2=19 dBm */
- OSMO_ASSERT(get_p_target_mdBm(trx, 1) == to_mdB(19));
+ OSMO_ASSERT(get_p_target_mdBm(trx, 2) == to_mdB(19));
/* at 2 steps (= 4dB), we expect 23-2-4=17*/
- OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 2) == to_mdB(17));
+ OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 4) == to_mdB(17));
}
static void test_sbts1020(struct gsm_bts_trx *trx)
@@ -138,9 +141,9 @@ static void test_sbts1020(struct gsm_bts_trx *trx)
/* at max_power_red = 2, we expect 31dBm */
OSMO_ASSERT(get_p_nominal_mdBm(trx) == to_mdB(31));
/* at 1 step (of 2dB), we expect full 33-2-2=29 dBm */
- OSMO_ASSERT(get_p_target_mdBm(trx, 1) == to_mdB(29));
+ OSMO_ASSERT(get_p_target_mdBm(trx, 2) == to_mdB(29));
/* at 2 steps (= 4dB), we expect 33-2-4-10=17*/
- OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 2) == to_mdB(17));
+ OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 4) == to_mdB(17));
}
@@ -157,9 +160,9 @@ static void test_sbts1100(struct gsm_bts_trx *trx)
/* at max_power_red = 2, we expect 38dBm */
OSMO_ASSERT(get_p_nominal_mdBm(trx) == to_mdB(38));
/* at 1 step (of 2dB), we expect full 40-2-2=36 dBm */
- OSMO_ASSERT(get_p_target_mdBm(trx, 1) == to_mdB(36));
+ OSMO_ASSERT(get_p_target_mdBm(trx, 2) == to_mdB(36));
/* at 2 steps (= 4dB), we expect 40-2-4-17=17*/
- OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 2) == to_mdB(17));
+ OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 4) == to_mdB(17));
}
static void test_sbts2050(struct gsm_bts_trx *trx)
@@ -175,31 +178,63 @@ static void test_sbts2050(struct gsm_bts_trx *trx)
/* at max_power_red = 2, we expect 35dBm */
OSMO_ASSERT(get_p_nominal_mdBm(trx) == to_mdB(35));
/* at 1 step (of 2dB), we expect full 37-2-2=33 dBm */
- OSMO_ASSERT(get_p_target_mdBm(trx, 1) == to_mdB(33));
+ OSMO_ASSERT(get_p_target_mdBm(trx, 2) == to_mdB(33));
/* at 2 steps (= 4dB), we expect 37-2-4=31dBm */
- OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 2) == to_mdB(31));
+ OSMO_ASSERT(get_p_trxout_target_mdBm(trx, 4) == to_mdB(31));
}
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
{
- struct trx_power_params *tpp = &trx->power_params;
printf("CHANGE_POWER(%d)\n", p_trxout_mdBm);
- if (tpp->ramp.attenuation_mdB == 0)
- exit(0);
-
power_trx_change_compl(trx, p_trxout_mdBm);
return 0;
}
-static void test_power_ramp(struct gsm_bts_trx *trx, int dBm)
+static void test_ramp_compl_cb(struct gsm_bts_trx *trx)
+{
+ power_ramp_finished = true;
+ printf("power_ramp finished\n");
+}
+
+static int test_power_ramp(struct gsm_bts_trx *trx, int dBm)
{
printf("Testing tx_power ramping for sysmoBTS 1020\n");
+ int rc;
+
trx->power_params = tpp_1020;
+ trx->power_params.ramp.step_interval_sec = 0; /* speedup test */
trx->max_power_red = 0;
- power_ramp_start(trx, to_mdB(dBm), 0);
+ power_ramp_finished = false;
+ if ((rc = power_ramp_start(trx, to_mdB(dBm), 0, test_ramp_compl_cb)))
+ return rc;
+ while (!power_ramp_finished)
+ osmo_select_main(0);
+ return 0;
+}
+
+
+static int test_power_ramp_from_minus10(struct gsm_bts_trx *trx, int dBm)
+{
+ printf("Testing tx_power ramping for osmo-bts-trx after lock\n");
+ int rc;
+
+ trx->power_params = tpp_1002;
+ trx->power_params.trx_p_max_out_mdBm = to_mdB(20);
+ trx->power_params.p_total_tgt_mdBm = to_mdB(-10);
+ trx->power_params.p_total_cur_mdBm = to_mdB(-10);
+ trx->power_params.ramp.max_initial_pout_mdBm = to_mdB(0);
+ trx->power_params.ramp.step_interval_sec = 0; /* speedup test */
+ trx->max_power_red = 10;
+
+ power_ramp_finished = false;
+ if ((rc = power_ramp_start(trx, to_mdB(dBm), 0, test_ramp_compl_cb)))
+ return rc;
+ while (!power_ramp_finished)
+ osmo_select_main(0);
+ return 0;
}
int main(int argc, char **argv)
@@ -213,9 +248,17 @@ int main(int argc, char **argv)
osmo_init_logging2(tall_bts_ctx, &bts_log_info);
osmo_stderr_target->categories[DL1C].loglevel = LOGL_DEBUG;
- log_set_print_filename(osmo_stderr_target, 0);
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
- bts = gsm_bts_alloc(tall_bts_ctx, 0);
+ g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
+ if (!g_bts_sm) {
+ fprintf(stderr, "Failed to create BTS Site Manager structure\n");
+ exit(1);
+ }
+ bts = gsm_bts_alloc(g_bts_sm, 0);
if (!bts) {
fprintf(stderr, "Failed to create BTS structure\n");
exit(1);
@@ -237,11 +280,10 @@ int main(int argc, char **argv)
test_sbts2050(trx);
/* test error case / excess power (40 dBm is too much) */
- test_power_ramp(trx, 40);
- /* test actaul ramping to full 33 dBm */
+ OSMO_ASSERT(test_power_ramp(trx, 40) == -ERANGE);
+ /* test actual ramping to full 33 dBm */
test_power_ramp(trx, 33);
+ /* Test ramp up from -10dBm (locked) to 10dBm */
+ test_power_ramp_from_minus10(trx, 10);
- while (1) {
- osmo_select_main(0);
- }
}
diff --git a/tests/tx_power/tx_power_test.err b/tests/tx_power/tx_power_test.err
index bf33b424..72a3d853 100644
--- a/tests/tx_power/tx_power_test.err
+++ b/tests/tx_power/tx_power_test.err
@@ -1,38 +1,50 @@
-power_ramp_start(cur=0, tgt=40000)
-Asked to ramp power up to 40000 mdBm, which exceeds P_max_out (33000)
-power_ramp_start(cur=0, tgt=33000)
-ramp_timer_cb(cur_pout=2000, tgt_pout=33000, ramp_att=31000, therm_att=0, user_gain=0)
-ramping TRX board output power to -8000 mdBm.
-ramp_timer_cb(cur_pout=4000, tgt_pout=33000, ramp_att=29000, therm_att=0, user_gain=0)
-ramping TRX board output power to -6000 mdBm.
-ramp_timer_cb(cur_pout=6000, tgt_pout=33000, ramp_att=27000, therm_att=0, user_gain=0)
-ramping TRX board output power to -4000 mdBm.
-ramp_timer_cb(cur_pout=8000, tgt_pout=33000, ramp_att=25000, therm_att=0, user_gain=0)
-ramping TRX board output power to -2000 mdBm.
-ramp_timer_cb(cur_pout=10000, tgt_pout=33000, ramp_att=23000, therm_att=0, user_gain=0)
-ramping TRX board output power to 0 mdBm.
-ramp_timer_cb(cur_pout=12000, tgt_pout=33000, ramp_att=21000, therm_att=0, user_gain=0)
-ramping TRX board output power to 2000 mdBm.
-ramp_timer_cb(cur_pout=14000, tgt_pout=33000, ramp_att=19000, therm_att=0, user_gain=0)
-ramping TRX board output power to 4000 mdBm.
-ramp_timer_cb(cur_pout=16000, tgt_pout=33000, ramp_att=17000, therm_att=0, user_gain=0)
-ramping TRX board output power to 6000 mdBm.
-ramp_timer_cb(cur_pout=18000, tgt_pout=33000, ramp_att=15000, therm_att=0, user_gain=0)
-ramping TRX board output power to 8000 mdBm.
-ramp_timer_cb(cur_pout=20000, tgt_pout=33000, ramp_att=13000, therm_att=0, user_gain=0)
-ramping TRX board output power to 10000 mdBm.
-ramp_timer_cb(cur_pout=22000, tgt_pout=33000, ramp_att=11000, therm_att=0, user_gain=0)
-ramping TRX board output power to 12000 mdBm.
-ramp_timer_cb(cur_pout=24000, tgt_pout=33000, ramp_att=9000, therm_att=0, user_gain=0)
-ramping TRX board output power to 14000 mdBm.
-ramp_timer_cb(cur_pout=26000, tgt_pout=33000, ramp_att=7000, therm_att=0, user_gain=0)
-ramping TRX board output power to 16000 mdBm.
-ramp_timer_cb(cur_pout=28000, tgt_pout=33000, ramp_att=5000, therm_att=0, user_gain=0)
-ramping TRX board output power to 18000 mdBm.
-ramp_timer_cb(cur_pout=30000, tgt_pout=33000, ramp_att=3000, therm_att=0, user_gain=0)
-ramping TRX board output power to 20000 mdBm.
-ramp_timer_cb(cur_pout=32000, tgt_pout=33000, ramp_att=1000, therm_att=0, user_gain=0)
-ramping TRX board output power to 22000 mdBm.
-ramp_timer_cb(cur_pout=33000, tgt_pout=33000, ramp_att=0, therm_att=0, user_gain=0)
-ramping TRX board output power to 23000 mdBm.
- \ No newline at end of file
+(bts=0,trx=1) power_ramp_start(cur=0, tgt=40000)
+(bts=0,trx=1) Asked to ramp power up to 40000 mdBm, which exceeds P_max_out (33000)
+(bts=0,trx=1) power_ramp_start(cur=0, tgt=33000)
+(bts=0,trx=1) ramp_timer_cb(cur_pout=2000, tgt_pout=33000, ramp_att=31000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to -8000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=4000, tgt_pout=33000, ramp_att=29000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to -6000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=6000, tgt_pout=33000, ramp_att=27000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to -4000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=8000, tgt_pout=33000, ramp_att=25000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to -2000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=10000, tgt_pout=33000, ramp_att=23000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 0 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=12000, tgt_pout=33000, ramp_att=21000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 2000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=14000, tgt_pout=33000, ramp_att=19000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 4000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=16000, tgt_pout=33000, ramp_att=17000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 6000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=18000, tgt_pout=33000, ramp_att=15000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 8000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=20000, tgt_pout=33000, ramp_att=13000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 10000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=22000, tgt_pout=33000, ramp_att=11000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 12000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=24000, tgt_pout=33000, ramp_att=9000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 14000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=26000, tgt_pout=33000, ramp_att=7000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 16000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=28000, tgt_pout=33000, ramp_att=5000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 18000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=30000, tgt_pout=33000, ramp_att=3000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 20000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=32000, tgt_pout=33000, ramp_att=1000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 22000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=33000, tgt_pout=33000, ramp_att=0, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 23000 mdBm.
+(bts=0,trx=1) power_ramp_start(cur=-10000, tgt=10000)
+(bts=0,trx=1) ramp_timer_cb(cur_pout=0, tgt_pout=10000, ramp_att=10000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 0 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=2000, tgt_pout=10000, ramp_att=8000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 2000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=4000, tgt_pout=10000, ramp_att=6000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 4000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=6000, tgt_pout=10000, ramp_att=4000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 6000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=8000, tgt_pout=10000, ramp_att=2000, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 8000 mdBm.
+(bts=0,trx=1) ramp_timer_cb(cur_pout=10000, tgt_pout=10000, ramp_att=0, therm_att=0, user_gain=0)
+(bts=0,trx=1) ramping TRX board output power to 10000 mdBm.
diff --git a/tests/tx_power/tx_power_test.ok b/tests/tx_power/tx_power_test.ok
index ceb88ab4..c8f04417 100644
--- a/tests/tx_power/tx_power_test.ok
+++ b/tests/tx_power/tx_power_test.ok
@@ -21,3 +21,12 @@ CHANGE_POWER(18000)
CHANGE_POWER(20000)
CHANGE_POWER(22000)
CHANGE_POWER(23000)
+power_ramp finished
+Testing tx_power ramping for osmo-bts-trx after lock
+CHANGE_POWER(0)
+CHANGE_POWER(2000)
+CHANGE_POWER(4000)
+CHANGE_POWER(6000)
+CHANGE_POWER(8000)
+CHANGE_POWER(10000)
+power_ramp finished