Compare commits

...

32 Commits

Author SHA1 Message Date
Keith
9192c6c6c2 Merging parts of commit 653e974fec00414ba85baf258ccc46ea778a53bd
from branch nrw/litecell15
Original Author: Minh-Quang Nguyen <minh-quang.nguyen@nutaq.com>
 LC15: Implementation of LC15 specific features

Made some modifications to this commit
based on d8cd756da4
 Get rid of 'struct gsm_bts_role_bts'

Only compile tested.
This is just to get a start on this branch.
I have not yet looked at all other commits in the
nuran branch that may be related.

This one however, does seem to be important
as it implements a larger cell radius than
is currently possible with osmo master.

Change-Id: I79416faaa3ba328c9c2dabcd695a1b880fe666da
2020-03-31 22:06:37 -05:00
Oliver Smith
ae4d85d891 VTY: add "test send-failure-event-report"
Send test failure event report OML message to the BSC. I found this
useful while manually testing related handling code in OsmoBSC.

Related: OS#1605
Change-Id: I0c4eba1636d8faf5012db26643bdf1d9fb6bfa1e
2020-03-24 08:01:05 +00:00
Philipp Maier
dbb5addf7d osmo-bts-trx: do not set rx-gain to 1 by default
The sample configs supplied within the doc/trx directory set the
rx-gain parameter to 1. A low value like this may cause a noticeable
degration of rx performance (For an USRP B200 an rx-gain of 38dbm is
recommended). Lets remove this seting from the sample configuration to
allow the default settings in osmo-trx to be applied.

Change-Id: I76be1739b638b3c1b0de5ac667eed53397631caa
Related: OS#4467
2020-03-23 17:18:51 +00:00
Harld Welte
e2f9d0eabe trx: Use NOPE indications on SDCCH
Without using the NOPE indication it might happen that we get
into the following situation:
* bursts 0,1,2 of a given block are received
* burst 3 is lost on the radio interface, OsmoTRX sends NOPE
* osmo-bts-trx doesn't pass the NOPE the the rx_tch*_fn()
* we never detect the end of the block, never perform decoding
  and even if the burst could be fully decoded, we loose the block

Related: OS#4661
Related: OS#2975
Change-Id: Idfc5c9a23db808c5f87ef5646c7e1d1cd3127371
2020-03-22 14:06:56 +01:00
Harld Welte
4e07b83a64 trx: Use NOPE indications from OsmoTRX for TCH/F and TCH/H
Without using the NOPE indication it might happen that we get
into the following situation:
* bursts 0,1,2 of a given block are received
* burst 3 is lost on the radio interface, OsmoTRX sends NOPE
* osmo-bts-trx doesn't pass the NOPE the the rx_tch*_fn()
* we never detect the end of the block, never perform decoding
  and even if the burst could be fully decoded, we loose the block

For voice, it can lead to lost RTP frames in uplink, which is also
problematic.

Let's deal with burst_len=0 in rx_tch*_fn() and use it as nope_fn.

Closes: OS#4661
Related: OS#2975
Change-Id: I0fbf4617daf24bd8aecfd9cfe1efd66cf73a277a
2020-03-22 14:06:47 +01:00
Harld Welte
f1efd727fb trx: Fix reported BER for TCH/H
This fixes a regression introduced in I710d0b7cf193afa8515807836ee69b8b7db84a84

We (obviously!) cannot compute the BER before performing convolutional
decoding.

Change-Id: I4e57f45d49cb513e4843e56f50c8de6980958fdc
Related: OS#2977
Related: OS#4667
2020-03-22 14:06:47 +01:00
Harald Welte
e36fbca15f osmo-bts-virtual: Fix "virtual-um net-device NETDEV"
The VTY option to bind the virtual Um multicast to a specific
network interface has existed ever since osmo-bts-virtual was
first merged to the repo.   However, embarrassingly, until today
it never did anything, i.e. the code to actually perform the bind
was missing.

Depends: libosmocore.git Ib52d22710020b56965aefcef09bde8247ace4a9c
Change-Id: I303f2e616d2d32b5a8005c3dcf0f5fad19ad3445
Related: OS#2966
2020-03-10 21:36:00 +01:00
Harald Welte
5914d76d5c osmo-bts-virtual: Add "virtual-um ttl <0-255>" VTY option
This can be used to determine the multicast TTL packet and hence
how far the packet will propagate in the network.  If you want to
operate the virtual Um only on your own machine, a TTL of 0 would
prevent the packets from ever being transmitted on your local
ethernet segment.

Change-Id: I18a9f93b764aee4e1dc68a1c6ac4d078e52ca61d
Related: OS#2966
2020-03-10 21:35:56 +01:00
Oliver Smith
cb4340b8a4 rsl: make IP DSCP configurable
Related: OS#4438
Depends: libosmo-abis I41603db8c1286660ad57ac1c78a8fb393a2b080b
Change-Id: Icdef5d40243fefdeae23f3bcf9c6702e8487928a
2020-03-08 17:56:52 +01:00
Harald Welte
58d79e88ad osmo-bts-virtual: implement GSMTAP_CHANNEL_VOICE
GSMTAP_CHANNEL_VOICE is the mechanism by which GSMTAP can [finally!]
be used to transport circuit-switched voice codec payload, and not
just signalling.

Original patch by Neels Hofmeyr, heavily extended by Harald Welte.

Depends: libosmocore.git I952044a17334f35712e087dc41781805000aebc1
Change-Id: I1cd9a251ce0b87181a0822d7940bbfc9f1428543
2020-03-08 17:56:52 +01:00
Harald Welte
6a5039674f l1sap: Use msgb_pull_l2() and unify l1sap_tch_ind + l1sap_ph_data_ind
In l1sap_ph_data_ind() we can use msgb_pull_l2() which is an exact
implementation of the functionality there.

In l1sap_tch_ind(), the existing code is actually wrong by making the
assumption that the msgb contains exactly an entire osmo_phsap_prim.
Better to also dynamically compute the number of bytes to ensure
we only pull those ahead of the L2 header, no matter what their exact
count.

Change-Id: I13f7f8ba93795e40b1fb4a306fe765e059f642cf
2020-03-08 17:12:15 +01:00
Vadim Yanitskiy
3f35ab258d osmo-bts-virtual: do not log GSMTAP message sending failure twice
Change-Id: I39e9edf35240ef31e3432412b459c2b8fb0de054
2020-03-04 20:43:02 +07:00
Vadim Yanitskiy
f9e7ccce27 osmo-bts-virtual: do not print redundant info in tx_to_virt_um()
LOGL1S() already prints enough context information.

Change-Id: I29adf9360b96544b7f58766d5cd26d97117884d9
2020-03-02 00:26:33 +07:00
Vadim Yanitskiy
2b948a3d17 osmo-bts-virtual: fix wrong endianness in gsmtap_hdr_stringify()
Change-Id: Ic9e84dc4adc44df735cba102bdace2fb1993ac8e
2020-02-29 18:09:46 +07:00
Vadim Yanitskiy
1f932689fc common/sysinfo: reduce criticality of a logging message
During the process of bootstrapping, it may happen that System
Information Type 3 is not yet received from the BSC, while the
BTS already needs to transmit a block on AGCH or PCH.

Since the RSL link is established later than the OML link, it's
kind of expected, so we should not log it as error.

Change-Id: I41aa3dbe375cf42c39032bafa80dba94d6219d35
2020-02-29 14:29:27 +07:00
Vadim Yanitskiy
7364ef15d9 vty: fix left shift by 31 cannot be represented in type 'int'
Change-Id: I3e5940e8f360bf6563f4c1b5ebd09579f9108c81
2020-02-27 23:35:09 +07:00
Harald Welte
24f98a0df9 virtual: Fix VTY commands to specify GSMTAP multicast groups
osmo-bts-virtual uses GSMTAP over multicast groups to communicate
with one or more virtphy instances.  There are some well-known default
multicast groups, but those can also be overridden via the VTY.

The problem is: If you actually try that, osmo-bts-virtual will abort,
as we try to talloc_free() when using osmo_talloc_replace_string()
on the constant default string.

The proper solution is to talloc_strdup() the constant default string
when setting the default value in bts_model_phy_link_set_defaults().

Change-Id: Ia96fea891a22e5a3c47ce658eda130ba8d4fc411
2020-02-26 14:36:58 +01:00
Pau Espin Pedrol
6ea3b28321 cosmetic: Fix some typos with codespell
Change-Id: I1bbb4871f764816dcbba86d833194be601fa9228
2020-02-25 18:51:15 +01:00
Pau Espin Pedrol
eba074e081 bts-trx: trx_if.c: Fix some printf formats
Compiler from raspberrypi4 warns/errors about those.

Change-Id: I4f973eb4ffdf8869b522d14e25853357fcd1e984
2020-02-25 18:28:52 +01:00
Philipp Maier
5184576572 osmo-bts-sysmo: merge measurement data and payload
For osmo-bts-sysmo the MPH INFO MEAS IND indication is still sent
separately. Lets merge the measurement information into the PH DATA

Change-Id: Iffe7865727fbf9bca8eb32a96e8ea05cf718a948
Related: OS#2977
2020-02-17 12:40:07 +01:00
Philipp Maier
ac61baed2e Do not depend on pcu_direct flag when populating ph_data_ind
The struct members ber10k, ta_offs_256bits and lqual_cb in ph_data_ind
are only populated when the pcu_direct flag is not set.

The pcu_direct flag is set when the pcu is directly attached to the phy
and all pcu related traffic (pdtch) is handled without sending it through
osmo-bts-sysmo. For those cases osmo_bts_sysmo will not make use of
those struct members, even if they were populated. When the PCU is not
directly attached the data is needed because it is sent through the
pcu_sock to the PCU.

Lets remove the check because it is not required. Also in future patches
where measurement indications and data / tch indicatins are merged the
struct members are also needed to carry the measurement information for
SACCH as well.

Change-Id: Iaa37bb62af4f5eb4b6e684cb754e68d11e6fd676
2020-02-17 12:11:43 +01:00
Pau Espin Pedrol
aea29c7249 l1sap: Change loglevel of Rx TCH.ind INFO->DEBUG
This line appears tens of times per second when a call is ongoing,
making it impossible to follow logs on INFO level.

Change-Id: Iadb1baf55df2f6d96f85260f2e8d03627fef7e66
2020-02-12 16:01:47 +01:00
Pau Espin Pedrol
52d7eafcea l1_if: Fix strange formatting of Meas info logging
Some use LOGPC, but were used after a LOGP with a trailing newline.
Let's simply add some defines/macros to be able to include it into a
normal LOGP easily insted of having a function.

Change-Id: Ie082b11c9d6d00ff2206184f03f6e3647c3da18c
2020-02-12 14:29:38 +01:00
Vadim Yanitskiy
cb69d607c9 osmo-bts-sysmo/Makefile.am: fix: do not overwrite bin_PROGRAMS
src/osmo-bts-sysmo/Makefile.am:25: warning: bin_PROGRAMS was already
				   defined in condition TRUE, which
				   includes condition ENABLE_SYSMOBTS_CALIB
src/osmo-bts-sysmo/Makefile.am:10: ... 'bin_PROGRAMS' previously defined here

Change-Id: Ib2334dccefd507eaaa6d33e58d4c1e029d7fd540
2020-01-21 18:52:08 +07:00
Philipp Maier
d4f67591c7 l1sap: merge MEAS IND into PRIM PH DATA / PRIM TCH
The MPH INFO MEAS IND indication, which contains the uplink measurement
data is sent in parallel to the PH DATA and TCH indications as a
separate indications. This makes the overall uplink measurement data
processing unnecessarly complex. So lets put the data that is relevant
for measurement into the PH DATA and TCH indications directly.

This change only affects osmo-bts-trx at the moment. In order to keep
the upper layers (l1sap.c) compatible we add an autodection to switch
between separate measurement indications and included measurement data.

Related: OS#2977
Depends: libosmocore I2c34b02d329f9df190c5035c396403ca0a4f9c42
Change-Id: I710d0b7cf193afa8515807836ee69b8b7db84a84
2020-01-20 14:35:19 +00:00
Philipp Maier
8969adc5d9 measurment: write irssi_full_sum variable correctly
The variable irssi_full_sum is not populated with a dummy value when we
are not able to compute irssi_full_sum. Instead we mistakenly write
MEASUREMENT_DUMMY_IRSSI to ber_full_sum, which is wrong

Change-Id: I44d7cb48e3c68ab1b48c78cceb9381ce3e39d7e8
Related: OS#2987
2020-01-20 14:33:51 +00:00
Philipp Maier
a0403d3769 ta_control: move timing advance code from osmo-bts-trx to common
The timing advance controller that is implemented in loops.c of
osmo-bts-trx only works for osmo-bts-trx and not for any of the phy
based bts. Lets move the timing advance controller into the common part
and make it available for every bts. Also lets add a unit-test.

Change-Id: If7ddf74db3abc9b9872abe620a0aeebe3327e70a
Related: SYS#4567
2020-01-20 14:33:49 +00:00
Vadim Yanitskiy
e7d835ca8c L1SAP: use LOGL_DEBUG for logging from rach_pass_filter()
Due to relatively small training sequence of Access Bursts, there
can be frequent false-positives (basically noise). Fortunately,
we can distinguish them from the real Access Bursts by checking
the signal measurements attached to them (BER, ToA and C/I).

Let's reduce verbosity of logging messages as they are mostly
useful for debugging and may confuse the users / operators.

Change-Id: I7ab6727ffff00140a7f9e762b299b711481393f1
2020-01-14 03:51:08 +07:00
Harald Welte
113712c728 rsl.c: Fix compiler error on gcc-9.2.1
rsl.c: In function ‘rsl_rx_ipac_XXcx’:
rsl.c:2147:39: error: ‘%s’ directive output may be truncated writing up to 255 bytes into a region of size 28 [-Werror=format-truncation=]
 2147 |   snprintf(cname, sizeof(cname), "bts@%s", ipstr);
      |                                       ^~
rsl.c:2147:3: note: ‘snprintf’ output between 5 and 260 bytes into a destination of size 32
 2147 |   snprintf(cname, sizeof(cname), "bts@%s", ipstr);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Change-Id: Id982a814f401e304327d25c77666f039bc156c1f
2020-01-12 16:11:12 +01:00
Vadim Yanitskiy
e5711efbb5 common/abis.c: make use of RSL TEI from OML IPA RSL Connect
Change-Id: I5927f59a49724170a63e87be604973f7c9d5d8be
2020-01-11 00:51:43 +01:00
Vadim Yanitskiy
f9115ae67a common/vty.c: get rid of generic exit / end commands
Those commands are now handled by libosmovty itself.

Change-Id: I425f9058ae15de929e2ba0283d4057bdf767aeeb
2020-01-11 00:17:10 +01:00
Michael McTernan
b54f1bf122 measurement: use signed integer for division of ta256b_sum
The variable ta256b_sum is int32_t and num_ul_meas_actual is unsigned
int. When ta256b_sum is negative the division produces the wrong result.

This is beacuse the division is performed unsigned as the usual
arithmetic conversions promote to unsigned where both both operands are
the same width.

Lets fix this by casting num_ul_meas_actual to signed.

(Note that in the same function there are various other averages
computed in the same pattern, but they have unsigned operands and so are
correct.)

Related: SYS#4728
Change-Id: I37e3f69109c5ca2948bd4cdb7aa017bf2fcb8172
2020-01-06 12:07:23 +01:00
61 changed files with 1545 additions and 380 deletions

1
.gitignore vendored
View File

@@ -62,6 +62,7 @@ tests/meas/meas_test
tests/misc/misc_test tests/misc/misc_test
tests/handover/handover_test tests/handover/handover_test
tests/tx_power/tx_power_test tests/tx_power/tx_power_test
tests/ta_control/ta_control_test
tests/testsuite tests/testsuite
tests/testsuite.log tests/testsuite.log

View File

@@ -382,6 +382,7 @@ AC_OUTPUT(
tests/sysmobts/Makefile tests/sysmobts/Makefile
tests/misc/Makefile tests/misc/Makefile
tests/handover/Makefile tests/handover/Makefile
tests/ta_control/Makefile
tests/tx_power/Makefile tests/tx_power/Makefile
tests/power/Makefile tests/power/Makefile
tests/meas/Makefile tests/meas/Makefile

View File

@@ -22,7 +22,6 @@ line vty
! !
phy 0 phy 0
instance 0 instance 0
osmotrx rx-gain 1
osmotrx ip local 127.0.0.1 osmotrx ip local 127.0.0.1
osmotrx ip remote 127.0.0.1 osmotrx ip remote 127.0.0.1
osmotrx timing-advance-loop osmotrx timing-advance-loop

View File

@@ -21,7 +21,6 @@ line vty
! !
phy 0 phy 0
instance 0 instance 0
osmotrx rx-gain 1
osmotrx ip local 127.0.0.1 osmotrx ip local 127.0.0.1
osmotrx ip remote 127.0.0.1 osmotrx ip remote 127.0.0.1
bts 0 bts 0

View File

@@ -423,9 +423,9 @@ The activation of PDCH is performed by using the regular 'RSL CHANNEL ACTIVATE'
procedure according to <<CHANNEL_ACTIVATION>>, with these modifications: procedure according to <<CHANNEL_ACTIVATION>>, with these modifications:
* The 'C-bits' part of the 'Channel Number' IE take the non-standard binary * 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 08.58 § 9.3.1).
* The 'A-bits' part of the 'Activation Type' IE take the non-standard binary * 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 value 1111, with an additional fourth bit (add A4 to A3 through A1 as seen in
3GPP TS 08.58 § 9.3.3; all remaining reserved bits as well as the 'R' bit are 3GPP TS 08.58 § 9.3.3; all remaining reserved bits as well as the 'R' bit are
coded as zero). coded as zero).
* The normally mandatory 'Channel Mode' IE is omitted; none of the optional IEs * The normally mandatory 'Channel Mode' IE is omitted; none of the optional IEs

View File

@@ -2,4 +2,4 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h gsm_data_shared.h logging.h
oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.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 \ 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 \ power_control.h scheduler.h scheduler_backend.h phy_link.h \
dtx_dl_amr_fsm.h dtx_dl_amr_fsm.h ta_control.h

View File

@@ -479,6 +479,11 @@ enum gsm_bts_features {
BTS_FEAT_SPEECH_H_AMR, BTS_FEAT_SPEECH_H_AMR,
BTS_FEAT_ETWS_PN, BTS_FEAT_ETWS_PN,
BTS_FEAT_MS_PWR_CTRL_DSP, BTS_FEAT_MS_PWR_CTRL_DSP,
/* When the feature 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_FEAT_MEAS_PAYLOAD_COMB,
_NUM_BTS_FEAT _NUM_BTS_FEAT
}; };
@@ -736,6 +741,7 @@ struct gsm_bts {
uint16_t rtp_port_range_start; uint16_t rtp_port_range_start;
uint16_t rtp_port_range_end; uint16_t rtp_port_range_end;
uint16_t rtp_port_range_next; uint16_t rtp_port_range_next;
int rtp_ip_dscp;
struct { struct {
uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */ uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
@@ -777,6 +783,14 @@ struct gsm_bts {
} pcu; } pcu;
void *model_priv; /* Allocated by bts_model, contains model specific data pointer */ void *model_priv; /* Allocated by bts_model, contains model specific data pointer */
#ifdef ENABLE_LC15BTS
/* specific to LC15 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 */
} lc15;
#endif
}; };

View File

@@ -134,7 +134,8 @@ extern uint8_t gsmtap_sapi_acch;
int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg, int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
struct gsm_lchan *lchan, uint8_t chan_nr, uint32_t fn, 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) #define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)

View File

@@ -44,7 +44,6 @@ struct phy_link {
uint16_t base_port_local; uint16_t base_port_local;
uint16_t base_port_remote; uint16_t base_port_remote;
struct osmo_fd trx_ofd_clk; struct osmo_fd trx_ofd_clk;
bool trx_ta_loop;
uint32_t clock_advance; uint32_t clock_advance;
uint32_t rts_advance; uint32_t rts_advance;
bool use_legacy_setbsic; bool use_legacy_setbsic;
@@ -54,6 +53,7 @@ struct phy_link {
} osmotrx; } osmotrx;
struct { struct {
char *mcast_dev; /* Network device for multicast */ char *mcast_dev; /* Network device for multicast */
int ttl; /* TTL of transmitted udp multicast */
char *bts_mcast_group; /* BTS are listening to this group */ char *bts_mcast_group; /* BTS are listening to this group */
uint16_t bts_mcast_port; uint16_t bts_mcast_port;
char *ms_mcast_group; /* MS are listening to this group */ char *ms_mcast_group; /* MS are listening to this group */

View File

@@ -54,7 +54,8 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum osmo_ph_pres_info_type presence_info); enum osmo_ph_pres_info_type presence_info);
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, 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); enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
int16_t ta_offs_256bits, uint16_t ber10k, float rssi);
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, 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); enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);

View File

@@ -0,0 +1,5 @@
#pragma once
#include <osmo-bts/gsm_data.h>
void lchan_ms_ta_ctrl(struct gsm_lchan *lchan);

View File

@@ -6,12 +6,16 @@ if ENABLE_LC15BTS
AM_CFLAGS += -DENABLE_LC15BTS AM_CFLAGS += -DENABLE_LC15BTS
endif endif
if ENABLE_LC15BTS
AM_CFLAGS += -DENABLE_LC15BTS
endif
noinst_LIBRARIES = libbts.a libl1sched.a noinst_LIBRARIES = libbts.a libl1sched.a
libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ 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 \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \
load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \
tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
l1sap.c cbch.c power_control.c main.c phy_link.c \ l1sap.c cbch.c power_control.c main.c phy_link.c \
dtx_dl_amr_fsm.c scheduler_mframe.c dtx_dl_amr_fsm.c scheduler_mframe.c ta_control.c
libl1sched_a_SOURCES = scheduler.c libl1sched_a_SOURCES = scheduler.c

View File

@@ -128,7 +128,8 @@ static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
e1inp_ts_config_sign(&line->ts[type-1], line); e1inp_ts_config_sign(&line->ts[type-1], line);
sign_link = trx->rsl_link = sign_link = trx->rsl_link =
e1inp_sign_link_create(&line->ts[type-1], e1inp_sign_link_create(&line->ts[type-1],
E1INP_SIGN_RSL, trx, 0, 0); E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
trx_link_estab(trx); trx_link_estab(trx);
break; break;
} }

View File

@@ -159,6 +159,7 @@ int bts_init(struct gsm_bts *bts)
bts->rtp_port_range_start = 16384; bts->rtp_port_range_start = 16384;
bts->rtp_port_range_end = 17407; bts->rtp_port_range_end = 17407;
bts->rtp_port_range_next = bts->rtp_port_range_start; bts->rtp_port_range_next = bts->rtp_port_range_start;
bts->rtp_ip_dscp = -1;
/* configurable via OML */ /* configurable via OML */
bts->load.ccch.load_ind_period = 112; bts->load.ccch.load_ind_period = 112;

View File

@@ -109,6 +109,7 @@ const struct value_string gsm_bts_features_descs[] = {
{ BTS_FEAT_SPEECH_H_AMR, "Halfrate speech AMR" }, { BTS_FEAT_SPEECH_H_AMR, "Halfrate speech AMR" },
{ BTS_FEAT_ETWS_PN, "ETWS Primary Notification on PCH" }, { BTS_FEAT_ETWS_PN, "ETWS Primary Notification on PCH" },
{ BTS_FEAT_MS_PWR_CTRL_DSP, "DSP/HW based MS Power Control Loop" }, { BTS_FEAT_MS_PWR_CTRL_DSP, "DSP/HW based MS Power Control Loop" },
{ BTS_FEAT_MEAS_PAYLOAD_COMB, "Measurement and Payload data combined"},
{ 0, NULL } { 0, NULL }
}; };

View File

@@ -176,9 +176,15 @@ struct msgb *l1sap_msgb_alloc(unsigned int l2_len)
return msg; 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, int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
struct gsm_lchan *lchan, uint8_t chan_nr, uint32_t fn, 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; struct osmo_phsap_prim *l1sap;
@@ -194,6 +200,10 @@ int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
l1sap->u.tch.ber10k = ber10k; l1sap->u.tch.ber10k = ber10k;
l1sap->u.tch.lqual_cb = lqual_cb; 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); return l1sap_up(trx, l1sap);
} }
@@ -629,42 +639,93 @@ static inline void set_ms_to_data(struct gsm_lchan *lchan, int16_t data, bool se
} }
/* measurement information received from bts model */ /* measurement information received from bts model */
static int l1sap_info_meas_ind(struct gsm_bts_trx *trx, static void process_l1sap_meas_data(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct osmo_phsap_prim *l1sap,
struct info_meas_ind_param *info_meas_ind) enum osmo_ph_prim ind_type)
{ {
struct bts_ul_meas ulm; struct bts_ul_meas ulm;
struct gsm_lchan *lchan; struct gsm_lchan *lchan;
struct info_meas_ind_param *info_meas_ind;
struct ph_data_param *ph_data_ind;
struct ph_tch_param *ph_tch_ind;
uint8_t chan_nr;
uint32_t fn;
uint8_t inv_rssi;
uint8_t is_sub;
int16_t ta_offs_256bits;
uint16_t ber10k;
const char *ind_name;
lchan = get_active_lchan_by_chan_nr(trx, info_meas_ind->chan_nr); switch (ind_type) {
if (!lchan) { case PRIM_MPH_INFO:
LOGPFN(DL1P, LOGL_ERROR, info_meas_ind->fn, /* (legacy way, see also OS#2977) */
"No lchan for MPH INFO MEAS IND (chan_nr=%s)\n", rsl_chan_nr_str(info_meas_ind->chan_nr)); info_meas_ind = &l1sap->u.info.u.meas_ind;
return 0; chan_nr = info_meas_ind->chan_nr;
fn = info_meas_ind->fn;
inv_rssi = info_meas_ind->inv_rssi;
is_sub = info_meas_ind->is_sub;
ta_offs_256bits = info_meas_ind->ta_offs_256bits;
ber10k = info_meas_ind->ber10k;
ind_name = "MPH INFO";
break;
case PRIM_TCH:
ph_tch_ind = &l1sap->u.tch;
if (ph_tch_ind->rssi == 0)
return;
chan_nr = ph_tch_ind->chan_nr;
fn = ph_tch_ind->fn;
inv_rssi = abs(ph_tch_ind->rssi);
is_sub = ph_tch_ind->is_sub;
ta_offs_256bits = ph_tch_ind->ta_offs_256bits;
ber10k = ph_tch_ind->ber10k;
ind_name = "TCH";
break;
case PRIM_PH_DATA:
ph_data_ind = &l1sap->u.data;
if (ph_data_ind->rssi == 0)
return;
chan_nr = ph_data_ind->chan_nr;
fn = ph_data_ind->fn;
inv_rssi = abs(ph_data_ind->rssi);
is_sub = ph_data_ind->is_sub;
ta_offs_256bits = ph_data_ind->ta_offs_256bits;
ber10k = ph_data_ind->ber10k;
ind_name = "DATA";
break;
default:
OSMO_ASSERT(false);
} }
DEBUGPFN(DL1P, info_meas_ind->fn, lchan = get_active_lchan_by_chan_nr(trx, chan_nr);
"%s MPH_INFO meas ind, ta_offs_256bits=%d, ber10k=%d, inv_rssi=%u\n", if (!lchan) {
gsm_lchan_name(lchan), info_meas_ind->ta_offs_256bits, LOGPFN(DL1P, LOGL_ERROR, fn,
info_meas_ind->ber10k, info_meas_ind->inv_rssi); "No lchan for %s MEAS IND (chan_nr=%s)\n",
ind_name, rsl_chan_nr_str(chan_nr));
return;
}
DEBUGPFN(DL1P, fn,
"%s %s meas ind, ta_offs_256bits=%d, ber10k=%d, inv_rssi=%u\n",
gsm_lchan_name(lchan), ind_name, ta_offs_256bits, ber10k,
inv_rssi);
/* in the GPRS case we are not interested in measurement /* in the GPRS case we are not interested in measurement
* processing. The PCU will take care of it */ * processing. The PCU will take care of it */
if (lchan->type == GSM_LCHAN_PDTCH) if (lchan->type == GSM_LCHAN_PDTCH)
return 0; return;
memset(&ulm, 0, sizeof(ulm)); memset(&ulm, 0, sizeof(ulm));
ulm.ta_offs_256bits = info_meas_ind->ta_offs_256bits; ulm.ta_offs_256bits = ta_offs_256bits;
ulm.ber10k = info_meas_ind->ber10k; ulm.ber10k = ber10k;
ulm.inv_rssi = info_meas_ind->inv_rssi; ulm.inv_rssi = inv_rssi;
ulm.is_sub = info_meas_ind->is_sub; ulm.is_sub = is_sub;
/* we assume that symbol period is 1 bit: */ /* 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, 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 received from bts model */ /* any L1 MPH_INFO indication prim received from bts model */
@@ -685,7 +746,12 @@ static int l1sap_mph_info_ind(struct gsm_bts_trx *trx,
&info->u.time_ind); &info->u.time_ind);
break; break;
case PRIM_INFO_MEAS: 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_FEAT_MEAS_PAYLOAD_COMB is enabled */
if (gsm_bts_has_feature(trx->bts, BTS_FEAT_MEAS_PAYLOAD_COMB))
OSMO_ASSERT(false);
process_l1sap_meas_data(trx, l1sap, PRIM_MPH_INFO);
break; break;
default: default:
LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n", LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n",
@@ -1200,6 +1266,12 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
return -EINVAL; return -EINVAL;
} }
/* The ph_data_param contained in the l1sap primitive may contain
* measurement data. If this data is present, forward it for
* processing */
if (gsm_bts_has_feature(trx->bts, BTS_FEAT_MEAS_PAYLOAD_COMB))
process_l1sap_meas_data(trx, l1sap, PRIM_PH_DATA);
if (ts_is_pdch(&trx->ts[tn])) { if (ts_is_pdch(&trx->ts[tn])) {
lchan = get_lchan_by_chan_nr(trx, chan_nr); lchan = get_lchan_by_chan_nr(trx, chan_nr);
if (!lchan) if (!lchan)
@@ -1283,8 +1355,7 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0); l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0);
/* SDCCH, SACCH and FACCH all go to LAPDm */ /* SDCCH, SACCH and FACCH all go to LAPDm */
msgb_pull(msg, (msg->l2h - msg->data)); msgb_pull_to_l2(msg);
msg->l1h = NULL;
lapdm_phsap_up(&l1sap->oph, le); lapdm_phsap_up(&l1sap->oph, le);
/* don't free, because we forwarded data */ /* don't free, because we forwarded data */
@@ -1307,7 +1378,7 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
gsm_fn2gsmtime(&g_time, fn); gsm_fn2gsmtime(&g_time, fn);
LOGPGT(DL1P, LOGL_INFO, &g_time, "Rx TCH.ind chan_nr=%s\n", rsl_chan_nr_str(chan_nr)); LOGPGT(DL1P, LOGL_DEBUG, &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); lchan = get_active_lchan_by_chan_nr(trx, chan_nr);
if (!lchan) { if (!lchan) {
@@ -1315,7 +1386,13 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
return 0; return 0;
} }
msgb_pull(msg, sizeof(*l1sap)); /* The ph_tch_param contained in the l1sap primitive may contain
* measurement data. If this data is present, forward it for
* processing */
if (gsm_bts_has_feature(trx->bts, BTS_FEAT_MEAS_PAYLOAD_COMB))
process_l1sap_meas_data(trx, l1sap, PRIM_TCH);
msgb_pull_to_l2(msg);
/* Low level layers always call us when TCH content is expected, even if /* Low level layers always call us when TCH content is expected, even if
* the content is not available due to decoding issues. Content not * the content is not available due to decoding issues. Content not
@@ -1358,7 +1435,7 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
/* Check for RACH exceeding BER threshold (ghost RACH) */ /* Check for RACH exceeding BER threshold (ghost RACH) */
if (rach_ind->ber10k > bts->max_ber10k_rach) { if (rach_ind->ber10k > bts->max_ber10k_rach) {
LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring an Access Burst on %s: " LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
"BER10k(%u) > BER10k_MAX(%u)\n", chan_name, "BER10k(%u) > BER10k_MAX(%u)\n", chan_name,
rach_ind->ber10k, bts->max_ber10k_rach); rach_ind->ber10k, bts->max_ber10k_rach);
return false; return false;
@@ -1370,7 +1447,7 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
* according to maximal allowed Timing Advance value. * according to maximal allowed Timing Advance value.
*/ */
if (toa256 < RACH_MIN_TOA256 || toa256 > bts->max_ta * 256) { if (toa256 < RACH_MIN_TOA256 || toa256 > bts->max_ta * 256) {
LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring an Access Burst on %s: " LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
"ToA(%d) exceeds the allowed range (%d..%d)\n", chan_name, "ToA(%d) exceeds the allowed range (%d..%d)\n", chan_name,
toa256, RACH_MIN_TOA256, bts->max_ta * 256); toa256, RACH_MIN_TOA256, bts->max_ta * 256);
return false; return false;
@@ -1378,7 +1455,7 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
/* Link quality defined by C/I (Carrier-to-Interference ratio) */ /* Link quality defined by C/I (Carrier-to-Interference ratio) */
if (rach_ind->lqual_cb < bts->min_qual_rach) { if (rach_ind->lqual_cb < bts->min_qual_rach) {
LOGPFN(DL1C, LOGL_INFO, rach_ind->fn, "Ignoring an Access Burst on %s: " LOGPFN(DL1C, LOGL_DEBUG, rach_ind->fn, "Ignoring an Access Burst on %s: "
"link quality (%d) below the minimum (%d)\n", chan_name, "link quality (%d) below the minimum (%d)\n", chan_name,
rach_ind->lqual_cb, bts->min_qual_rach); rach_ind->lqual_cb, bts->min_qual_rach);
return false; return false;

View File

@@ -10,6 +10,7 @@
#include <osmo-bts/measurement.h> #include <osmo-bts/measurement.h>
#include <osmo-bts/scheduler.h> #include <osmo-bts/scheduler.h>
#include <osmo-bts/rsl.h> #include <osmo-bts/rsl.h>
#include <osmo-bts/ta_control.h>
/* Tables as per TS 45.008 Section 8.3 */ /* 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_f[] = { 52, 53, 54, 55, 56, 57, 58, 59 };
@@ -655,14 +656,14 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
ber_full_sum = ber_full_sum / num_ul_meas; ber_full_sum = ber_full_sum / num_ul_meas;
if (!irssi_full_sum) if (!irssi_full_sum)
ber_full_sum = MEASUREMENT_DUMMY_IRSSI; irssi_full_sum = MEASUREMENT_DUMMY_IRSSI;
else else
irssi_full_sum = irssi_full_sum / num_ul_meas_actual; 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; ta256b_sum = lchan->meas.ms_toa256;
else else
ta256b_sum = ta256b_sum / num_ul_meas_actual; ta256b_sum = ta256b_sum / (signed)num_ul_meas_actual;
if (!num_meas_sub) if (!num_meas_sub)
ber_sub_sum = MEASUREMENT_DUMMY_BER; ber_sub_sum = MEASUREMENT_DUMMY_BER;
@@ -696,6 +697,11 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
lchan_meas_compute_extended(lchan); lchan_meas_compute_extended(lchan);
/* Compute new ta_req value. This has to be done here since the value
* in lchan->meas.num_ul_meas together with lchan->meas.ms_toa256
* is needed for the computation. */
lchan_ms_ta_ctrl(lchan);
lchan->meas.num_ul_meas = 0; lchan->meas.num_ul_meas = 0;
/* return 1 to indicate that the computation has been done and the next /* return 1 to indicate that the computation has been done and the next

View File

@@ -1323,8 +1323,10 @@ static int rx_oml_ipa_rsl_connect(struct gsm_bts_trx *trx, struct msgb *msg,
if (trx->bts->variant == BTS_OSMO_OMLDUMMY) { if (trx->bts->variant == BTS_OSMO_OMLDUMMY) {
rc = 0; rc = 0;
LOGP(DOML, LOGL_NOTICE, "%s: Not connecting RSL in OML-DUMMY!\n", trx_name); LOGP(DOML, LOGL_NOTICE, "%s: Not connecting RSL in OML-DUMMY!\n", trx_name);
} else } else {
trx->rsl_tei = stream_id;
rc = e1inp_ipa_bts_rsl_connect_n(oml_link->ts->line, inet_ntoa(in), port, trx->nr); rc = e1inp_ipa_bts_rsl_connect_n(oml_link->ts->line, inet_ntoa(in), port, trx->nr);
}
if (rc < 0) { if (rc < 0) {
LOGP(DOML, LOGL_ERROR, "%s: Error in abis_open(RSL): %d\n", trx_name, rc); 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); return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);

View File

@@ -2009,8 +2009,15 @@ static int bind_rtp(struct gsm_bts *bts, struct osmo_rtp_socket *rs, const char
bts->rtp_port_range_next += 2; bts->rtp_port_range_next += 2;
if (rc == 0) if (rc != 0)
return 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=%i: %s\n",
bts->rtp_ip_dscp, strerror(errno));
}
return 0;
} }
return -1; return -1;
@@ -2081,7 +2088,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
} }
if (dch->c.msg_type == RSL_MT_IPAC_CRCX) { if (dch->c.msg_type == RSL_MT_IPAC_CRCX) {
char cname[32]; char cname[256+4];
char *ipstr = NULL; char *ipstr = NULL;
if (lchan->abis_ip.rtp_socket) { if (lchan->abis_ip.rtp_socket) {
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC CRCX, " LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Rx RSL IPAC CRCX, "

View File

@@ -191,6 +191,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_tchf_fn, .rts_fn = rts_tchf_fn,
.dl_fn = tx_tchf_fn, .dl_fn = tx_tchf_fn,
.ul_fn = rx_tchf_fn, .ul_fn = rx_tchf_fn,
.nope_fn = rx_tchf_fn,
}, },
[TRXC_TCHH_0] = { [TRXC_TCHH_0] = {
.name = "TCH/H(0)", /* 3GPP TS 05.02, section 3.2 */ .name = "TCH/H(0)", /* 3GPP TS 05.02, section 3.2 */
@@ -211,6 +212,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_tchh_fn, .rts_fn = rts_tchh_fn,
.dl_fn = tx_tchh_fn, .dl_fn = tx_tchh_fn,
.ul_fn = rx_tchh_fn, .ul_fn = rx_tchh_fn,
.nope_fn = rx_tchh_fn,
}, },
[TRXC_TCHH_1] = { [TRXC_TCHH_1] = {
.name = "TCH/H(1)", /* 3GPP TS 05.02, section 3.2 */ .name = "TCH/H(1)", /* 3GPP TS 05.02, section 3.2 */
@@ -222,6 +224,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_tchh_fn, .rts_fn = rts_tchh_fn,
.dl_fn = tx_tchh_fn, .dl_fn = tx_tchh_fn,
.ul_fn = rx_tchh_fn, .ul_fn = rx_tchh_fn,
.nope_fn = rx_tchh_fn,
}, },
[TRXC_SDCCH4_0] = { [TRXC_SDCCH4_0] = {
.name = "SDCCH/4(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/4(0)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -233,6 +236,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH4_1] = { [TRXC_SDCCH4_1] = {
.name = "SDCCH/4(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/4(1)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -244,6 +248,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH4_2] = { [TRXC_SDCCH4_2] = {
.name = "SDCCH/4(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/4(2)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -255,6 +260,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH4_3] = { [TRXC_SDCCH4_3] = {
.name = "SDCCH/4(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/4(3)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -266,6 +272,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_0] = { [TRXC_SDCCH8_0] = {
.name = "SDCCH/8(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(0)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -277,6 +284,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_1] = { [TRXC_SDCCH8_1] = {
.name = "SDCCH/8(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(1)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -288,6 +296,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_2] = { [TRXC_SDCCH8_2] = {
.name = "SDCCH/8(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(2)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -299,6 +308,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_3] = { [TRXC_SDCCH8_3] = {
.name = "SDCCH/8(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(3)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -310,6 +320,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_4] = { [TRXC_SDCCH8_4] = {
.name = "SDCCH/8(4)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(4)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -321,6 +332,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_5] = { [TRXC_SDCCH8_5] = {
.name = "SDCCH/8(5)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(5)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -332,6 +344,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_6] = { [TRXC_SDCCH8_6] = {
.name = "SDCCH/8(6)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(6)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -343,6 +356,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SDCCH8_7] = { [TRXC_SDCCH8_7] = {
.name = "SDCCH/8(7)", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SDCCH/8(7)", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -354,6 +368,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.rts_fn = rts_data_fn, .rts_fn = rts_data_fn,
.dl_fn = tx_data_fn, .dl_fn = tx_data_fn,
.ul_fn = rx_data_fn, .ul_fn = rx_data_fn,
.nope_fn = rx_data_fn,
}, },
[TRXC_SACCHTF] = { [TRXC_SACCHTF] = {
.name = "SACCH/TF", /* 3GPP TS 05.02, section 3.3.4.1 */ .name = "SACCH/TF", /* 3GPP TS 05.02, section 3.3.4.1 */
@@ -753,7 +768,8 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
} }
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, 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) enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
int16_t ta_offs_256bits, uint16_t ber10k, float rssi)
{ {
struct msgb *msg; struct msgb *msg;
struct osmo_phsap_prim *l1sap; struct osmo_phsap_prim *l1sap;
@@ -769,6 +785,10 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
PRIM_OP_INDICATION, msg); PRIM_OP_INDICATION, msg);
l1sap->u.tch.chan_nr = chan_nr; l1sap->u.tch.chan_nr = chan_nr;
l1sap->u.tch.fn = fn; l1sap->u.tch.fn = fn;
l1sap->u.tch.rssi = (int8_t) (rssi);
l1sap->u.tch.ber10k = ber10k;
l1sap->u.tch.ta_offs_256bits = ta_offs_256bits;
msg->l2h = msgb_put(msg, tch_len); msg->l2h = msgb_put(msg, tch_len);
if (tch_len) if (tch_len)
memcpy(msg->l2h, tch, tch_len); memcpy(msg->l2h, tch, tch_len);

View File

@@ -156,7 +156,7 @@ uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg)
si3 = GSM_BTS_SI(b, SYSINFO_TYPE_3); si3 = GSM_BTS_SI(b, SYSINFO_TYPE_3);
return si3->control_channel_desc.bs_ag_blks_res; 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); "value as SI3 is not available yet, fallback to 1\n", arg);
return 1; return 1;
} }

55
src/common/ta_control.c Normal file
View File

@@ -0,0 +1,55 @@
/* Loop control for Timing Advance */
/* (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 <osmo-bts/gsm_data.h>
#include <osmo-bts/logging.h>
/* 90% of one bit duration in 1/256 symbols: 256*0.9 */
#define TOA256_9OPERCENT 230
/* rqd_ta value range */
#define TOA_MIN 0
#define TOA_MAX 63
void lchan_ms_ta_ctrl(struct gsm_lchan *lchan)
{
int16_t toa256 = lchan->meas.ms_toa256;
/* Do not perform any computation when the amount of measurement
* results is too little. */
if (lchan->meas.num_ul_meas < 4)
return;
if (toa256 < -TOA256_9OPERCENT && lchan->rqd_ta > TOA_MIN) {
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 < TOA_MAX) {
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_DEBUG,
"TOA is correct (%d), keeping current TA of %d\n",
toa256, lchan->rqd_ta);
}

View File

@@ -125,48 +125,6 @@ int bts_vty_is_config_node(struct vty *vty, int node)
} }
} }
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[] = 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"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n" "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
@@ -279,6 +237,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " rtp port-range %u %u%s", bts->rtp_port_range_start, vty_out(vty, " rtp port-range %u %u%s", bts->rtp_port_range_start,
bts->rtp_port_range_end, VTY_NEWLINE); bts->rtp_port_range_end, VTY_NEWLINE);
if (bts->rtp_ip_dscp != -1)
vty_out(vty, " rtp ip-dscp %i%s", bts->rtp_ip_dscp, VTY_NEWLINE);
vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(bts->paging_state), vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(bts->paging_state),
VTY_NEWLINE); VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(bts->paging_state), vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(bts->paging_state),
@@ -292,7 +252,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
bts->agch_queue.high_level, VTY_NEWLINE); bts->agch_queue.high_level, VTY_NEWLINE);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
if (gsmtap_sapi_mask & (1 << i)) { if (gsmtap_sapi_mask & ((uint32_t) 1 << i)) {
sapi_buf = osmo_str_tolower(get_value_string(gsmtap_sapi_names, i)); sapi_buf = osmo_str_tolower(get_value_string(gsmtap_sapi_names, i));
vty_out(vty, " gsmtap-sapi %s%s", sapi_buf, VTY_NEWLINE); vty_out(vty, " gsmtap-sapi %s%s", sapi_buf, VTY_NEWLINE);
} }
@@ -543,6 +503,19 @@ DEFUN(cfg_bts_rtp_port_range,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bts_rtp_ip_dscp,
cfg_bts_rtp_ip_dscp_cmd,
"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;
}
#define PAG_STR "Paging related parameters\n" #define PAG_STR "Paging related parameters\n"
DEFUN(cfg_bts_paging_queue_size, DEFUN(cfg_bts_paging_queue_size,
@@ -955,6 +928,25 @@ DEFUN(show_bts, show_bts_cmd, "show bts <0-255>",
return CMD_SUCCESS; return CMD_SUCCESS;
} }
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)
{
struct gsm_network *net = gsmnet_from_vty(vty);
int bts_nr = atoi(argv[0]);
struct gsm_bts *bts;
if (bts_nr >= net->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);
oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MINOR, OSMO_EVT_WARN_SW_WARN, "test message sent from VTY");
return CMD_SUCCESS;
}
static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx) static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
{ {
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s", vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
@@ -1707,6 +1699,7 @@ int bts_vty_init(struct gsm_bts *bts)
install_element(BTS_NODE, &cfg_bts_rtp_bind_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_jitbuf_cmd);
install_element(BTS_NODE, &cfg_bts_rtp_port_range_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_band_cmd); install_element(BTS_NODE, &cfg_bts_band_cmd);
install_element(BTS_NODE, &cfg_description_cmd); install_element(BTS_NODE, &cfg_description_cmd);
install_element(BTS_NODE, &cfg_no_description_cmd); install_element(BTS_NODE, &cfg_no_description_cmd);
@@ -1742,6 +1735,7 @@ int bts_vty_init(struct gsm_bts *bts)
install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_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, &bts_t_t_l_loopback_cmd);
install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd); install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd);
install_element(ENABLE_NODE, &test_send_failure_event_report_cmd);
install_element(CONFIG_NODE, &cfg_phy_cmd); install_element(CONFIG_NODE, &cfg_phy_cmd);
install_node(&phy_node, config_write_phy); install_node(&phy_node, config_write_phy);

View File

@@ -936,12 +936,8 @@ empty_frame:
goto tx; goto tx;
} }
static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) #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
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, static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
GsmL1_MeasParam_t *m, uint32_t fn) GsmL1_MeasParam_t *m, uint32_t fn)
@@ -992,10 +988,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); 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, get_value_string(lc15bts_l1sapi_names, data_ind->sapi), (uint32_t)data_ind->hLayer2,
osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size)); osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
dump_meas_res(LOGL_DEBUG, &data_ind->measParam); LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */ /* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -1028,11 +1024,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.chan_nr = chan_nr;
l1sap->u.data.fn = fn; l1sap->u.data.fn = fn;
l1sap->u.data.rssi = rssi; l1sap->u.data.rssi = rssi;
if (!pcu_direct) { l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64; l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
}
return l1sap_up(trx, l1sap); return l1sap_up(trx, l1sap);
} }
@@ -1046,7 +1041,8 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
struct ph_rach_ind_param rach_ind_param; struct ph_rach_ind_param rach_ind_param;
set_log_ctx_sapi(ra_ind->sapi); set_log_ctx_sapi(ra_ind->sapi);
dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); 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) && if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) { (ra_ind->msgUnitParam.u8Size != 2)) {
@@ -1267,8 +1263,10 @@ 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", LOGP(DL1C, LOGL_FATAL, "RF-ACT.conf with status %s\n",
get_value_string(lc15bts_l1status_names, status)); get_value_string(lc15bts_l1status_names, status));
bts_shutdown(trx->bts, "RF-ACT failure"); bts_shutdown(trx->bts, "RF-ACT failure");
} else } else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 1); if(trx->bts->lc15.led_ctrl_mode == LC15_LED_CONTROL_BTS)
bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
}
/* signal availability */ /* signal availability */
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
@@ -1279,7 +1277,8 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
for (i = 0; i < ARRAY_SIZE(trx->ts); i++) for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
} else { } else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 0); if(trx->bts->lc15.led_ctrl_mode == LC15_LED_CONTROL_BTS)
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->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
} }
@@ -1294,17 +1293,27 @@ int l1if_activate_rf(struct lc15l1_hdl *hdl, int on)
{ {
struct msgb *msg = sysp_msgb_alloc(); struct msgb *msg = sysp_msgb_alloc();
Litecell15_Prim_t *sysp = msgb_sysprim(msg); Litecell15_Prim_t *sysp = msgb_sysprim(msg);
struct phy_instance *pinst = hdl->phy_inst;
if (on) { if (on) {
sysp->id = Litecell15_PrimId_ActivateRfReq; sysp->id = Litecell15_PrimId_ActivateRfReq;
sysp->u.activateRfReq.msgq.u8UseTchMsgq = 0; sysp->u.activateRfReq.msgq.u8UseTchMsgq = 0;
sysp->u.activateRfReq.msgq.u8UsePdtchMsgq = pcu_direct; 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; 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 */ /* 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;
/* auto tx power adjustment mode 0:none, 1: automatic*/
sysp->u.activateRfReq.autoPowerAdjust.u8EnAutoPowerAdjust = pinst->u.lc15.tx_pwr_adj_mode;
/* PSK modulation scheme maximum power level */
sysp->u.activateRfReq.autoPowerAdjust.u8PowerReduction8Psk = pinst->u.lc15.tx_pwr_red_8psk;
} else { } else {
sysp->id = Litecell15_PrimId_DeactivateRfReq; sysp->id = Litecell15_PrimId_DeactivateRfReq;
} }
@@ -1357,7 +1366,8 @@ static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n", LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
get_value_string(lc15bts_l1status_names, status)); get_value_string(lc15bts_l1status_names, status));
bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]); if(trx->bts->lc15.led_ctrl_mode == LC15_LED_CONTROL_BTS)
bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1); oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
osmo_static_assert( osmo_static_assert(
@@ -1593,6 +1603,53 @@ int l1if_close(struct lc15l1_hdl *fl1h)
return 0; return 0;
} }
static void 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_NOTICE, "Rx SYS prim %s, status=%d (%d)\n",
get_value_string(lc15bts_sysprim_names, sysp->id), sac->status, trx->nr);
msgb_free(resp);
}
static int 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);
exit(23);
}
LOGP(DL1C, LOGL_NOTICE, "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 -EIO;
}
/* 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;
}
int bts_model_phy_link_open(struct phy_link *plink) int bts_model_phy_link_open(struct phy_link *plink)
{ {
struct phy_instance *pinst = phy_instance_by_num(plink, 0); struct phy_instance *pinst = phy_instance_by_num(plink, 0);
@@ -1612,6 +1669,24 @@ int bts_model_phy_link_open(struct phy_link *plink)
return -EIO; 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 (!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;
struct lc15l1_hdl *fl1h = pinst->u.lc15.hdl; struct lc15l1_hdl *fl1h = pinst->u.lc15.hdl;
fl1h->dsp_trace_f = dsp_trace; fl1h->dsp_trace_f = dsp_trace;
@@ -1620,5 +1695,24 @@ int bts_model_phy_link_open(struct phy_link *plink)
phy_link_state_set(plink, PHY_LINK_CONNECTED); phy_link_state_set(plink, PHY_LINK_CONNECTED);
/* 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 */
fl1h->hw_alive.dsp_alive_timer.cb = dsp_alive_timer_cb;
fl1h->hw_alive.dsp_alive_timer.data = 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);
return 0; return 0;
} }

View File

@@ -62,6 +62,12 @@ struct lc15l1_hdl {
struct calib_send_state st; struct calib_send_state st;
uint8_t last_rf_mute[8]; uint8_t last_rf_mute[8];
struct {
struct osmo_timer_list dsp_alive_timer;
unsigned int dsp_alive_cnt;
uint8_t dsp_alive_period;
} hw_alive;
}; };
#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) #define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h)

View File

@@ -121,6 +121,8 @@ enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id)
case Litecell15_PrimId_MuteRfCnf: return L1P_T_CONF; case Litecell15_PrimId_MuteRfCnf: return L1P_T_CONF;
case Litecell15_PrimId_SetRxAttenReq: return L1P_T_REQ; case Litecell15_PrimId_SetRxAttenReq: return L1P_T_REQ;
case Litecell15_PrimId_SetRxAttenCnf: return L1P_T_CONF; case Litecell15_PrimId_SetRxAttenCnf: return L1P_T_CONF;
case Litecell15_PrimId_IsAliveReq: return L1P_T_REQ;
case Litecell15_PrimId_IsAliveCnf: return L1P_T_CONF;
default: return L1P_T_INVALID; default: return L1P_T_INVALID;
} }
} }
@@ -142,6 +144,8 @@ const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1] = {
{ Litecell15_PrimId_MuteRfCnf, "MUTE-RF.cnf" }, { Litecell15_PrimId_MuteRfCnf, "MUTE-RF.cnf" },
{ Litecell15_PrimId_SetRxAttenReq, "SET-RX-ATTEN.req" }, { Litecell15_PrimId_SetRxAttenReq, "SET-RX-ATTEN.req" },
{ Litecell15_PrimId_SetRxAttenCnf, "SET-RX-ATTEN-CNF.cnf" }, { Litecell15_PrimId_SetRxAttenCnf, "SET-RX-ATTEN-CNF.cnf" },
{ Litecell15_PrimId_IsAliveReq, "IS-ALIVE.req" },
{ Litecell15_PrimId_IsAliveCnf, "IS-ALIVE-CNF.cnf" },
{ 0, NULL } { 0, NULL }
}; };
@@ -155,6 +159,7 @@ Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id)
case Litecell15_PrimId_SetCalibTblReq: return Litecell15_PrimId_SetCalibTblCnf; case Litecell15_PrimId_SetCalibTblReq: return Litecell15_PrimId_SetCalibTblCnf;
case Litecell15_PrimId_MuteRfReq: return Litecell15_PrimId_MuteRfCnf; case Litecell15_PrimId_MuteRfReq: return Litecell15_PrimId_MuteRfCnf;
case Litecell15_PrimId_SetRxAttenReq: return Litecell15_PrimId_SetRxAttenCnf; case Litecell15_PrimId_SetRxAttenReq: return Litecell15_PrimId_SetRxAttenCnf;
case Litecell15_PrimId_IsAliveReq: return Litecell15_PrimId_IsAliveCnf;
default: return -1; // Weak default: return -1; // Weak
} }
} }

View File

@@ -22,6 +22,27 @@ enum l1prim_type {
L1P_T_IND, 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,
};
enum lc15_auto_pwr_adjust_mode{
LC15_TX_PWR_ADJ_NONE = 0,
LC15_TX_PWR_ADJ_AUTO,
};
enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id); enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id);
const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1]; const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1];
GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id); GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id);
@@ -61,4 +82,13 @@ enum pdch_cs {
const uint8_t pdch_msu_size[_NUM_PDCH_CS]; 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_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 */
#endif /* LC15BTS_H */ #endif /* LC15BTS_H */

View File

@@ -65,6 +65,31 @@ extern int lchan_activate(struct gsm_lchan *lchan);
static struct gsm_bts *vty_bts; 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 }
};
static const struct value_string lc15_auto_adj_pwr_strs[] = {
{ LC15_TX_PWR_ADJ_NONE, "none" },
{ LC15_TX_PWR_ADJ_AUTO, "auto" },
{ 0, NULL }
};
/* configuration */ /* configuration */
DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd, DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd,
@@ -321,8 +346,130 @@ DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
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]);
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.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]);
if((val < LC15_DIVERSITY_SISO_A) || (val > LC15_DIVERSITY_MRC)) {
vty_out(vty, "Invalid reception diversity mode %d%s", val, VTY_NEWLINE);
return CMD_WARNING;
}
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]);
if((val < LC15_PEDESTAL_OFF) || (val > LC15_PEDESTAL_ON)) {
vty_out(vty, "Invalid unused time-slot transmission mode %d%s", val, VTY_NEWLINE);
return CMD_WARNING;
}
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]);
if((val < LC15_LED_CONTROL_BTS) || (val > LC15_LED_CONTROL_EXT)) {
vty_out(vty, "Invalid LED control mode %d%s", val, VTY_NEWLINE);
return CMD_WARNING;
}
bts->lc15.led_ctrl_mode = (uint8_t)val;
return CMD_SUCCESS;
}
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]);
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.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]);
if((val < LC15_TX_PWR_ADJ_NONE) || (val > LC15_TX_PWR_ADJ_AUTO)) {
vty_out(vty, "Invalid output power adjustment mode %d%s", val, VTY_NEWLINE);
return CMD_WARNING;
}
pinst->u.lc15.tx_pwr_adj_mode = (uint8_t)val;
return CMD_SUCCESS;
}
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]);
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.lc15.tx_pwr_red_8psk = (uint8_t)val;
return CMD_SUCCESS;
}
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{ {
vty_out(vty, " led-control-mode %s%s",
get_value_string(lc15_led_mode_strs, bts->lc15.led_ctrl_mode), VTY_NEWLINE);
} }
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
@@ -347,8 +494,27 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst
} }
} }
if (pinst->u.lc15.calib_path) if (pinst->u.lc15.calib_path)
vty_out(vty, " trx-calibration-path %s%s", vty_out(vty, " trx-calibration-path %s%s",
pinst->u.lc15.calib_path, VTY_NEWLINE); 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);
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);
} }
int bts_model_vty_init(struct gsm_bts *bts) int bts_model_vty_init(struct gsm_bts *bts)
@@ -401,12 +567,20 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(BTS_NODE, &cfg_bts_auto_band_cmd); 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_no_auto_band_cmd);
install_element(BTS_NODE, &cfg_bts_led_mode_cmd);
install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
install_element(PHY_INST_NODE, &cfg_phy_dsp_trace_f_cmd); install_element(PHY_INST_NODE, &cfg_phy_dsp_trace_f_cmd);
install_element(PHY_INST_NODE, &cfg_phy_no_dsp_trace_f_cmd); 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_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);
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);
return 0; return 0;
} }

View File

@@ -90,7 +90,8 @@ int bts_model_init(struct gsm_bts *bts)
bts->variant = BTS_OSMO_LITECELL15; bts->variant = BTS_OSMO_LITECELL15;
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
/* specific default values for LC15 platform */
bts->lc15.led_ctrl_mode = LC15_BTS_LED_CTRL_MODE_DEFAULT;
rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd); rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "Error creating the OML router: %s rc=%d\n", fprintf(stderr, "Error creating the OML router: %s rc=%d\n",

View File

@@ -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). 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. 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, 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) int lc15bts_swd_event(struct lc15bts_mgr_instance *mgr, enum mgr_swd_events swd_event)
{ {

View File

@@ -373,7 +373,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP"); rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, 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]; payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -463,7 +463,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (rmsg) if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, data_ind->measParam.fBer * 10000,
data_ind->measParam.fLinkQuality * 10); data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
return 0; return 0;

View File

@@ -992,12 +992,9 @@ empty_frame:
goto tx; goto tx;
} }
static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
{ #define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d"
LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " #define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming
"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, static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
GsmL1_MeasParam_t *m, uint32_t fn) GsmL1_MeasParam_t *m, uint32_t fn)
@@ -1048,10 +1045,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); 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, get_value_string(oc2gbts_l1sapi_names, data_ind->sapi), (uint32_t)data_ind->hLayer2,
osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size)); osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
dump_meas_res(LOGL_DEBUG, &data_ind->measParam); LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */ /* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -1084,11 +1081,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.chan_nr = chan_nr;
l1sap->u.data.fn = fn; l1sap->u.data.fn = fn;
l1sap->u.data.rssi = rssi; l1sap->u.data.rssi = rssi;
if (!pcu_direct) { l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64;
l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming*64; l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
}
return l1sap_up(trx, l1sap); return l1sap_up(trx, l1sap);
} }
@@ -1102,7 +1098,8 @@ static int handle_ph_ra_ind(struct oc2gl1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
struct ph_rach_ind_param rach_ind_param; struct ph_rach_ind_param rach_ind_param;
set_log_ctx_sapi(ra_ind->sapi); set_log_ctx_sapi(ra_ind->sapi);
dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); 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) && if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) { (ra_ind->msgUnitParam.u8Size != 2)) {

View File

@@ -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). 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. 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, 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) int oc2gbts_swd_event(struct oc2gbts_mgr_instance *mgr, enum mgr_swd_events swd_event)
{ {

View File

@@ -373,7 +373,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP"); rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, 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]; payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -475,7 +475,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (rmsg) if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, data_ind->measParam.fBer * 10000,
data_ind->measParam.fLinkQuality * 10); data_ind->measParam.fLinkQuality * 10, 0, 0, 0);
return 0; return 0;

View File

@@ -906,14 +906,9 @@ static void process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
l1sap_up(trx, &l1sap); l1sap_up(trx, &l1sap);
} }
static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m)
{ #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"
LOGP(DMEAS, ll, #define LOG_PARAM_MEAS(meas_param) (meas_param)->sRSSIDbm, (meas_param)->sBurstTiming, (meas_param)->sBurstTiming4x, (meas_param)->usBERCnt, (meas_param)->usBERTotalBitCnt
"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);
}
static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn) static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn)
{ {
@@ -1218,7 +1213,8 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1,
set_log_ctx_sapi(ra_ind->LchId.bySAPI); set_log_ctx_sapi(ra_ind->LchId.bySAPI);
dump_meas_res(LOGL_DEBUG, &ra_ind->MeasurementInfo); 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) { if (ra_ind->ulMsgLength != 1) {
LOGPFN(DL1C, LOGL_ERROR, ra_ind->ulFrameNumber, LOGPFN(DL1C, LOGL_ERROR, ra_ind->ulFrameNumber,

View File

@@ -151,7 +151,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP"); rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, return add_l1sap_header(trx, rmsg, lchan, chan_nr,
data_ind->Data.ulFrameNumber, data_ind->Data.ulFrameNumber,
ber10k, lqual_cb); ber10k, lqual_cb, 0, 0, 0);
} }
payload_len = data_ind->Data.ulDataLength; payload_len = data_ind->Data.ulDataLength;
@@ -210,7 +210,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr,
if (rmsg) if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, return add_l1sap_header(trx, rmsg, lchan, chan_nr,
data_ind->Data.ulFrameNumber, data_ind->Data.ulFrameNumber,
ber10k, lqual_cb); ber10k, lqual_cb, 0, 0, 0);
return 0; return 0;

View File

@@ -22,7 +22,7 @@ l1fwd_proxy_SOURCES = l1_fwd_main.c l1_transp_hw.c
l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD)
if ENABLE_SYSMOBTS_CALIB 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_SOURCES = misc/sysmobts-calib.c misc/sysmobts-layer1.c
sysmobts_calib_LDADD = -lrt $(COMMON_LDADD) sysmobts_calib_LDADD = -lrt $(COMMON_LDADD)

View File

@@ -937,31 +937,8 @@ empty_frame:
goto tx; goto tx;
} }
static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) #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
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);
}
static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind,
struct msgb *l1p_msg) struct msgb *l1p_msg)
@@ -987,14 +964,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
fn = data_ind->u32Fn; fn = data_ind->u32Fn;
link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC; 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); 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, get_value_string(femtobts_l1sapi_names, data_ind->sapi), data_ind->hLayer2,
osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size)); osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
dump_meas_res(LOGL_DEBUG, &data_ind->measParam); LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */ /* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -1014,11 +989,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.chan_nr = chan_nr;
l1sap->u.data.fn = fn; l1sap->u.data.fn = fn;
l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi); 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.ber10k = data_ind->measParam.fBer * 10000; l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64;
l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64; l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
}
/* copy data from L1 primitive to L1SAP primitive */ /* copy data from L1 primitive to L1SAP primitive */
sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size); sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size);
memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer, memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer,
@@ -1040,8 +1014,8 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
struct ph_rach_ind_param rach_ind_param; struct ph_rach_ind_param rach_ind_param;
set_log_ctx_sapi(ra_ind->sapi); set_log_ctx_sapi(ra_ind->sapi);
LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); LOG_PARAM_MEAS(&ra_ind->measParam));
if ((ra_ind->msgUnitParam.u8Size != 1) && if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) { (ra_ind->msgUnitParam.u8Size != 2)) {

View File

@@ -87,6 +87,7 @@ int bts_model_init(struct gsm_bts *bts)
gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR); 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_SPEECH_H_AMR);
gsm_bts_set_feature(bts, BTS_FEAT_MS_PWR_CTRL_DSP); gsm_bts_set_feature(bts, BTS_FEAT_MS_PWR_CTRL_DSP);
gsm_bts_set_feature(bts, BTS_FEAT_MEAS_PAYLOAD_COMB);
bts_model_vty_init(bts); bts_model_vty_init(bts);

View File

@@ -518,7 +518,10 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP"); rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, 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]; payload_type = data_ind->msgUnitParam.u8Buffer[0];
@@ -613,7 +616,10 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
if (rmsg) if (rmsg)
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn, return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
data_ind->measParam.fBer * 10000, 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; return 0;

View File

@@ -572,40 +572,6 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
return l1sap_up(bts->c0, &l1sap); 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 */ /* primitive from common part */
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{ {

View File

@@ -115,8 +115,6 @@ struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst);
int l1if_provision_transceiver_trx(struct trx_l1h *l1h); int l1if_provision_transceiver_trx(struct trx_l1h *l1h);
int l1if_provision_transceiver(struct gsm_bts *bts); int l1if_provision_transceiver(struct gsm_bts *bts);
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn); 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) static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
{ {

View File

@@ -35,63 +35,6 @@
#include "l1_if.h" #include "l1_if.h"
#include "loops.h" #include "loops.h"
/*
* Timing Advance loop
*/
/* 90% of one bit duration in 1/256 symbols: 256*0.9 */
#define TOA256_9OPERCENT 230
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, 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 TA loop is enabled, handle it */
if (pinst->phy_link->u.osmotrx.trx_ta_loop)
ta_val(lchan, chan_state, toa256);
}
void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr, void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
struct l1sched_chan_state *chan_state, struct l1sched_chan_state *chan_state,
int n_errors, int n_bits_total) int n_errors, int n_bits_total)

View File

@@ -11,9 +11,6 @@
* loops api * loops api
*/ */
void trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr,
struct l1sched_chan_state *chan_state, int16_t toa);
void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr, void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
struct l1sched_chan_state *chan_state, struct l1sched_chan_state *chan_state,
int n_errors, int n_bits_total); int n_errors, int n_bits_total);

View File

@@ -116,6 +116,7 @@ int bts_model_init(struct gsm_bts *bts)
gsm_bts_set_feature(bts, BTS_FEAT_SPEECH_F_AMR); 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_SPEECH_H_AMR);
gsm_bts_set_feature(bts, BTS_FEAT_CBCH); gsm_bts_set_feature(bts, BTS_FEAT_CBCH);
gsm_bts_set_feature(bts, BTS_FEAT_MEAS_PAYLOAD_COMB);
bts_model_vty_init(bts); bts_model_vty_init(bts);
@@ -135,7 +136,6 @@ void bts_model_phy_link_set_defaults(struct phy_link *plink)
plink->u.osmotrx.base_port_remote = 5700; plink->u.osmotrx.base_port_remote = 5700;
plink->u.osmotrx.clock_advance = 20; plink->u.osmotrx.clock_advance = 20;
plink->u.osmotrx.rts_advance = 5; plink->u.osmotrx.rts_advance = 5;
plink->u.osmotrx.trx_ta_loop = true;
/* attempt use newest TRXD version by default: */ /* attempt use newest TRXD version by default: */
plink->u.osmotrx.trxd_hdr_ver_max = TRX_DATA_FORMAT_VER; plink->u.osmotrx.trxd_hdr_ver_max = TRX_DATA_FORMAT_VER;
} }

View File

@@ -193,12 +193,10 @@ got_msg:
/* TODO: Should we pass old TOA here? Otherwise we risk /* TODO: Should we pass old TOA here? Otherwise we risk
* unnecessary decreasing TA */ * unnecessary decreasing TA */
/* Send uplink measurement information to L2 */ /* Note: RSSI is set to 0 to indicate to the higher
l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, * layers that this is a faked ph_data_ind */
456, 456, -110, 0);
/* FIXME: use actual values for BER etc */
_sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,
-110, 0, 0, 10000, 0, 0, 0, 10000,
PRES_INFO_INVALID); PRES_INFO_INVALID);
} }
} }
@@ -345,6 +343,9 @@ static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
uint8_t rsl_cmode = chan_state->rsl_cmode; uint8_t rsl_cmode = chan_state->rsl_cmode;
uint8_t tch_mode = chan_state->tch_mode; uint8_t tch_mode = chan_state->tch_mode;
struct osmo_phsap_prim *l1sap; struct osmo_phsap_prim *l1sap;
int32_t *toa256_sum = &chan_state->toa256_sum;
uint8_t *toa_num = &chan_state->toa_num;
int16_t toa256;
/* handle loss detection of received TCH frames */ /* handle loss detection of received TCH frames */
if (rsl_cmode == RSL_CMOD_SPD_SPEECH if (rsl_cmode == RSL_CMOD_SPD_SPEECH
@@ -390,8 +391,17 @@ inval_mode1:
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n"); LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
len = 0; len = 0;
} }
if (len)
_sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len); if (len) {
if (*toa_num == 0)
toa256 = 0;
else
toa256 = *toa256_sum / *toa_num;
/* Note: RSSI is set to 0 to indicate to the higher
* layers that this is a faked tch_ind */
_sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0);
}
} }
/* get frame and unlink from queue */ /* get frame and unlink from queue */
@@ -946,7 +956,7 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
} }
/* Copy burst to buffer of 4 bursts. If the burst indication contains /* Copy burst to buffer of 4 bursts. If the burst indication contains
* no data, ensure that the buffer does not stay uninitalized */ * no data, ensure that the buffer does not stay uninitialized */
burst = *bursts_p + bid * 116; burst = *bursts_p + bid * 116;
if (bi->burst_len > 0) { if (bi->burst_len > 0) {
memcpy(burst, bi->burst + 3, 58); memcpy(burst, bi->burst + 3, 58);
@@ -954,12 +964,6 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
} else } else
memset(burst, 0, 58 * 2); memset(burst, 0, 58 * 2);
/* 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->toa256);
}
/* wait until complete set of bursts */ /* wait until complete set of bursts */
if (bid != 3) if (bid != 3)
return 0; return 0;
@@ -988,12 +992,6 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
} else } else
l2_len = GSM_MACBLOCK_LEN; 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; lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;
ber10k = compute_ber10k(n_bits_total, n_errors); ber10k = compute_ber10k(n_bits_total, n_errors);
return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn, return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn,
@@ -1103,14 +1101,6 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
&n_errors, &n_bits_total); &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) { if (rc <= 0) {
LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn, LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,
"Received bad PDTCH (%u/%u)\n", "Received bad PDTCH (%u/%u)\n",
@@ -1147,6 +1137,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
struct gsm_lchan *lchan = struct gsm_lchan *lchan =
get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn); get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);
unsigned int fn_begin; unsigned int fn_begin;
uint16_t ber10k;
/* handle rach, if handover rach detection is turned on */ /* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1) if (chan_state->ho_rach_detect == 1)
@@ -1174,8 +1165,11 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
/* copy burst to end of buffer of 8 bursts */ /* copy burst to end of buffer of 8 bursts */
burst = *bursts_p + bid * 116 + 464; burst = *bursts_p + bid * 116 + 464;
memcpy(burst, bi->burst + 3, 58); if (bi->burst_len > 0) {
memcpy(burst + 58, bi->burst + 87, 58); memcpy(burst, bi->burst + 3, 58);
memcpy(burst + 58, bi->burst + 87, 58);
} else
memset(burst, 0, 116);
/* wait until complete set of bursts */ /* wait until complete set of bursts */
if (bid != 3) if (bid != 3)
@@ -1246,17 +1240,13 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state) if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)
osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc); osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);
ber10k = compute_ber10k(n_bits_total, n_errors);
if (bfi_flag) if (bfi_flag)
goto bfi; goto bfi;
/* FACCH */ /* FACCH */
if (rc == GSM_MACBLOCK_LEN) { if (rc == GSM_MACBLOCK_LEN) {
uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F);
l1if_process_meas_res(l1t->trx, bi->tn, fn_begin,
trx_chan_desc[chan].chan_nr | bi->tn,
n_errors, n_bits_total,
bi->rssi, bi->toa256);
_sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan, _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,
tch_data + amr, GSM_MACBLOCK_LEN, tch_data + amr, GSM_MACBLOCK_LEN,
/* FIXME: AVG RSSI and ToA256 */ /* FIXME: AVG RSSI and ToA256 */
@@ -1317,12 +1307,8 @@ bfi:
/* TCH or BFI */ /* TCH or BFI */
compose_l1sap: compose_l1sap:
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);
l1if_process_meas_res(l1t->trx, bi->tn, fn_begin,
trx_chan_desc[chan].chan_nr | bi->tn,
n_errors, n_bits_total,
bi->rssi, bi->toa256);
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,
tch_data, rc); tch_data, rc, bi->toa256, ber10k, bi->rssi);
} }
/*! \brief a single TCH/H burst was received by the PHY, process it */ /*! \brief a single TCH/H burst was received by the PHY, process it */
@@ -1349,6 +1335,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
*/ */
int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1; int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1;
unsigned int fn_begin; unsigned int fn_begin;
uint16_t ber10k;
/* handle RACH, if handover RACH detection is turned on */ /* handle RACH, if handover RACH detection is turned on */
if (chan_state->ho_rach_detect == 1) if (chan_state->ho_rach_detect == 1)
@@ -1376,8 +1363,11 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
/* copy burst to end of buffer of 6 bursts */ /* copy burst to end of buffer of 6 bursts */
burst = *bursts_p + bid * 116 + 464; burst = *bursts_p + bid * 116 + 464;
memcpy(burst, bi->burst + 3, 58); if (bi->burst_len > 0) {
memcpy(burst + 58, bi->burst + 87, 58); memcpy(burst, bi->burst + 3, 58);
memcpy(burst + 58, bi->burst + 87, 58);
} else
memset(burst, 0, 116);
/* wait until complete set of bursts */ /* wait until complete set of bursts */
if (bid != 1) if (bid != 1)
@@ -1396,6 +1386,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
chan_state->ul_ongoing_facch = 0; chan_state->ul_ongoing_facch = 0;
memcpy(*bursts_p, *bursts_p + 232, 232); memcpy(*bursts_p, *bursts_p + 232, 232);
memcpy(*bursts_p + 232, *bursts_p + 464, 232); memcpy(*bursts_p + 232, *bursts_p + 464, 232);
ber10k = 0;
goto bfi; goto bfi;
} }
@@ -1442,6 +1433,8 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
} }
memcpy(*bursts_p, *bursts_p + 232, 232); memcpy(*bursts_p, *bursts_p + 232, 232);
memcpy(*bursts_p + 232, *bursts_p + 464, 232); memcpy(*bursts_p + 232, *bursts_p + 464, 232);
ber10k = compute_ber10k(n_bits_total, n_errors);
/* Check if the frame is bad */ /* Check if the frame is bad */
if (rc < 0) { if (rc < 0) {
@@ -1470,10 +1463,6 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H0); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H0);
else else
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1);
l1if_process_meas_res(l1t->trx, bi->tn, fn_begin,
trx_chan_desc[chan].chan_nr | bi->tn,
n_errors, n_bits_total, bi->rssi,
bi->toa256);
_sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan, _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,
tch_data + amr, GSM_MACBLOCK_LEN, tch_data + amr, GSM_MACBLOCK_LEN,
/* FIXME: AVG both RSSI and ToA */ /* FIXME: AVG both RSSI and ToA */
@@ -1539,12 +1528,8 @@ compose_l1sap:
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H0); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H0);
else else
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1); fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1);
l1if_process_meas_res(l1t->trx, bi->tn, fn_begin,
trx_chan_desc[chan].chan_nr | bi->tn,
n_errors, n_bits_total, bi->rssi,
bi->toa256);
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,
tch_data, rc); tch_data, rc, bi->toa256, ber10k, bi->rssi);
} }
/* schedule all frames of all TRX for given FN */ /* schedule all frames of all TRX for given FN */

View File

@@ -394,8 +394,8 @@ static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp
goto parse_err; goto parse_err;
if (p - buf_in >= sizeof(rsp->cmd)) { if (p - buf_in >= sizeof(rsp->cmd)) {
LOGP(DTRX, LOGL_ERROR, "cmd buffer too small %lu >= %lu\n", LOGP(DTRX, LOGL_ERROR, "cmd buffer too small %lu >= %zu\n",
p - buf_in, sizeof(rsp->cmd)); (long unsigned) (p - buf_in), sizeof(rsp->cmd));
goto parse_err; goto parse_err;
} }
@@ -415,7 +415,7 @@ static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp
k = p + strlen(p); k = p + strlen(p);
if (strlen(k) >= sizeof(rsp->params)) { if (strlen(k) >= sizeof(rsp->params)) {
LOGP(DTRX, LOGL_ERROR, "params buffer too small %lu >= %lu\n", LOGP(DTRX, LOGL_ERROR, "params buffer too small %zu >= %zu\n",
strlen(k), sizeof(rsp->params)); strlen(k), sizeof(rsp->params));
goto parse_err; goto parse_err;
} }

View File

@@ -181,23 +181,19 @@ DEFUN_DEPRECATED(cfg_phy_no_ms_power_loop, cfg_phy_no_ms_power_loop_cmd,
return CMD_SUCCESS; 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 "osmotrx timing-advance-loop", OSMOTRX_STR
"Enable timing advance control loop\n") "Enable timing advance control loop\n")
{ {
struct phy_link *plink = vty->index; vty_out (vty, "'osmotrx timing-advance-loop' is deprecated, ta control is now active by default%s", VTY_NEWLINE);
plink->u.osmotrx.trx_ta_loop = true;
return CMD_SUCCESS; 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 osmotrx timing-advance-loop",
NO_STR OSMOTRX_STR "Disable timing advance control loop\n") NO_STR OSMOTRX_STR "Disable timing advance control loop\n")
{ {
struct phy_link *plink = vty->index; vty_out (vty, "'no osmotrx timing-advance-loop' is deprecated, ta control is now active by default%s", VTY_NEWLINE);
plink->u.osmotrx.trx_ta_loop = false;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@@ -522,8 +518,6 @@ void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
vty_out(vty, " osmotrx ip remote %s%s", vty_out(vty, " osmotrx ip remote %s%s",
plink->u.osmotrx.remote_ip, VTY_NEWLINE); plink->u.osmotrx.remote_ip, 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) if (plink->u.osmotrx.base_port_local)
vty_out(vty, " osmotrx base-port local %"PRIu16"%s", vty_out(vty, " osmotrx base-port local %"PRIu16"%s",
plink->u.osmotrx.base_port_local, VTY_NEWLINE); plink->u.osmotrx.base_port_local, VTY_NEWLINE);

View File

@@ -128,12 +128,7 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
break; break;
case GSMTAP_CHANNEL_TCH_F: case GSMTAP_CHANNEL_TCH_F:
case GSMTAP_CHANNEL_TCH_H: case GSMTAP_CHANNEL_TCH_H:
#if 0 /* This is TCH signalling, for voice frames see GSMTAP_CHANNEL_VOICE */
/* TODO: handle voice messages */
if (!facch && ! tch_acch) {
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, msg);
}
#endif
case GSMTAP_CHANNEL_SDCCH4: case GSMTAP_CHANNEL_SDCCH4:
case GSMTAP_CHANNEL_SDCCH8: case GSMTAP_CHANNEL_SDCCH8:
case GSMTAP_CHANNEL_PACCH: case GSMTAP_CHANNEL_PACCH:
@@ -151,6 +146,19 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
l1sap.u.data.pdch_presence_info = PRES_INFO_BOTH; l1sap.u.data.pdch_presence_info = PRES_INFO_BOTH;
l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0); l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0);
break; 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_AGCH:
case GSMTAP_CHANNEL_PCH: case GSMTAP_CHANNEL_PCH:
case GSMTAP_CHANNEL_BCCH: case GSMTAP_CHANNEL_BCCH:
@@ -196,7 +204,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.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, 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) { if (!plink->u.virt.virt_um) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN); phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1; return -1;

View File

@@ -119,10 +119,11 @@ void bts_model_abis_close(struct gsm_bts *bts)
void bts_model_phy_link_set_defaults(struct phy_link *plink) 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.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.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) void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)

View File

@@ -21,6 +21,7 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
@@ -46,21 +47,13 @@
#define MODULO_HYPERFRAME 0 #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. * 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. * 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 * 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, static void _tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, struct msgb *msg) enum trx_chan_type chan, 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[chan];
struct msgb *outmsg; /* msg to send with gsmtap header prepended */ struct msgb *outmsg; /* msg to send with gsmtap header prepended */
@@ -83,7 +76,7 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
l1sap_fn2ccch_block(fn) >= num_agch(l1t->trx, "PH-DATA-REQ")) l1sap_fn2ccch_block(fn) >= num_agch(l1t->trx, "PH-DATA-REQ"))
gsmtap_chantype = GSMTAP_CHANNEL_PCH; gsmtap_chantype = GSMTAP_CHANNEL_PCH;
else 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 MODULO_HYPERFRAME #if MODULO_HYPERFRAME
/* Restart fn after every superframe (26 * 51 frames) to simulate hyperframe overflow each 6 seconds. */ /* Restart fn after every superframe (26 * 51 frames) to simulate hyperframe overflow each 6 seconds. */
@@ -94,18 +87,17 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
if (outmsg) { if (outmsg) {
struct phy_instance *pinst = trx_phy_instance(l1t->trx); struct phy_instance *pinst = trx_phy_instance(l1t->trx);
struct gsmtap_hdr *gh = (struct gsmtap_hdr *)msgb_data(outmsg);
int rc; int rc;
rc = virt_um_write_msg(pinst->phy_link->u.virt.virt_um, outmsg); rc = virt_um_write_msg(pinst->phy_link->u.virt.virt_um, outmsg);
if (rc < 0) if (rc < 0)
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
"%s GSMTAP msg could not send to virtual Um\n", gsmtap_hdr_stringify(gh)); "GSMTAP msg could not send to virtual Um: %s\n", strerror(-rc));
else if (rc == 0) else if (rc == 0)
bts_shutdown(l1t->trx->bts, "VirtPHY write socket died\n"); bts_shutdown(l1t->trx->bts, "VirtPHY write socket died\n");
else else
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn,
"%s Sending GSMTAP message to virtual Um\n", gsmtap_hdr_stringify(gh)); "Sending GSMTAP message to virtual Um\n");
} else } else
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "GSMTAP msg could not be created!\n"); LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "GSMTAP msg could not be created!\n");
@@ -113,6 +105,65 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
msgb_free(msg); msgb_free(msg);
} }
static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, struct msgb *msg)
{
_tx_to_virt_um(l1t, tn, fn, chan, msg, false);
}
static struct gsm_lchan *lchan_from_l1t(struct l1sched_trx *l1t, uint8_t tn, enum trx_chan_type chan)
{
struct gsm_bts_trx_ts *ts;
uint8_t subslot = 0;
OSMO_ASSERT(l1t && l1t->trx);
if (chan == TRXC_TCHH_1)
subslot = 1;
ts = &l1t->trx->ts[tn];
return &ts->lchan[subslot];
}
/* Determine the gsmtap_um_voice_type of a gsm_lchan */
static int get_um_voice_type(const struct gsm_lchan *lchan)
{
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;
}
}
static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, struct msgb *msg)
{
struct gsm_lchan *lchan = lchan_from_l1t(l1t, tn, 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(l1t, tn, fn, chan, msg, true);
}
/* /*
* TX on downlink * TX on downlink
*/ */
@@ -422,8 +473,8 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
if (msg_facch) { if (msg_facch) {
tx_to_virt_um(l1t, tn, fn, chan, msg_facch); tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
msgb_free(msg_tch); msgb_free(msg_tch);
} else } else if (msg_tch)
tx_to_virt_um(l1t, tn, fn, chan, msg_tch); tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
send_burst: send_burst:
@@ -464,7 +515,7 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
tx_to_virt_um(l1t, tn, fn, chan, msg_facch); tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
msgb_free(msg_tch); msgb_free(msg_tch);
} else if (msg_tch) } else if (msg_tch)
tx_to_virt_um(l1t, tn, fn, chan, msg_tch); tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
send_burst: send_burst:
return NULL; return NULL;

View File

@@ -27,7 +27,9 @@
#include <osmocom/core/talloc.h> #include <osmocom/core/talloc.h>
#include "osmo_mcast_sock.h" #include "osmo_mcast_sock.h"
#include "virtual_um.h" #include "virtual_um.h"
#include <unistd.h> #include <unistd.h>
#include <errno.h>
/** /**
* Virtual UM interface file descriptor callback. * Virtual UM interface file descriptor callback.
@@ -60,10 +62,12 @@ static int virt_um_fd_cb(struct osmo_fd *ofd, unsigned int what)
} }
struct virt_um_inst *virt_um_init(void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port, 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 (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg))
{ {
struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst); 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, 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_fd_cb, vui);
if (!vui->mcast_sock) { if (!vui->mcast_sock) {
@@ -73,8 +77,34 @@ struct virt_um_inst *virt_um_init(void *ctx, char *tx_mcast_group, uint16_t tx_m
} }
vui->recv_cb = recv_cb; vui->recv_cb = recv_cb;
/* -1 means default, i.e. no TTL explicitly configured in VTY */
if (ttl >= 0) {
rc = osmo_sock_mcast_ttl_set(vui->mcast_sock->tx_ofd.fd, ttl);
if (rc < 0) {
perror("Cannot set TTL of Virtual Um transmit socket");
goto out_close;
}
}
if (dev_name) {
rc = osmo_sock_mcast_iface_set(vui->mcast_sock->tx_ofd.fd, dev_name);
if (rc < 0) {
perror("Cannot bind multicast tx to given device");
goto out_close;
}
rc = osmo_sock_mcast_iface_set(vui->mcast_sock->rx_ofd.fd, dev_name);
if (rc < 0) {
perror("Cannot bind multicast rx to given device");
goto out_close;
}
}
return vui; 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) void virt_um_destroy(struct virt_um_inst *vui)
@@ -93,7 +123,7 @@ int virt_um_write_msg(struct virt_um_inst *vui, struct msgb *msg)
rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg),
msgb_length(msg)); msgb_length(msg));
if (rc < 0) if (rc < 0)
perror("Writing to multicast socket"); rc = -errno;
msgb_free(msg); msgb_free(msg);
return rc; return rc;

View File

@@ -23,7 +23,7 @@ struct virt_um_inst {
struct virt_um_inst *virt_um_init( struct virt_um_inst *virt_um_init(
void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port, 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 (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg));
void virt_um_destroy(struct virt_um_inst *vui); void virt_um_destroy(struct virt_um_inst *vui);

View File

@@ -69,6 +69,9 @@ void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
if (plink->u.virt.mcast_dev) if (plink->u.virt.mcast_dev)
vty_out(vty, " virtual-um net-device %s%s", vty_out(vty, " virtual-um net-device %s%s",
plink->u.virt.mcast_dev, VTY_NEWLINE); 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)) if (strcmp(plink->u.virt.ms_mcast_group, DEFAULT_BTS_MCAST_GROUP))
vty_out(vty, " virtual-um ms-multicast-group %s%s", vty_out(vty, " virtual-um ms-multicast-group %s%s",
plink->u.virt.ms_mcast_group, VTY_NEWLINE); plink->u.virt.ms_mcast_group, VTY_NEWLINE);
@@ -171,6 +174,23 @@ DEFUN(cfg_phy_mcast_dev, cfg_phy_mcast_dev_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
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")
{
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(struct gsm_bts *bts) int bts_model_vty_init(struct gsm_bts *bts)
{ {
vty_bts = bts; vty_bts = bts;
@@ -180,6 +200,7 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(PHY_NODE, &cfg_phy_bts_mcast_group_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_bts_mcast_port_cmd);
install_element(PHY_NODE, &cfg_phy_mcast_dev_cmd); install_element(PHY_NODE, &cfg_phy_mcast_dev_cmd);
install_element(PHY_NODE, &cfg_phy_mcast_ttl_cmd);
return 0; return 0;
} }

View File

@@ -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
if ENABLE_SYSMOBTS if ENABLE_SYSMOBTS
SUBDIRS += sysmobts SUBDIRS += sysmobts

View File

@@ -585,8 +585,8 @@ meas.ext.toa256_min | 0 | 0
meas.ext.toa256_max | 0 | 0 meas.ext.toa256_max | 0 | 0
meas.ms_toa256 | 0 | 0 meas.ms_toa256 | 0 | 0
meas.ext.toa256_std_dev | 0 | 0 meas.ext.toa256_std_dev | 0 | 0
meas.ul_res.full.rx_lev | 63 | 63 meas.ul_res.full.rx_lev | 1 | 1
meas.ul_res.full.rx_qual | 3 | 3 meas.ul_res.full.rx_qual | 7 | 7
=========================================================== ===========================================================

View File

@@ -131,8 +131,8 @@ static const struct meas_testcase mtc4 = {
.pchan = GSM_PCHAN_TCH_F, .pchan = GSM_PCHAN_TCH_F,
.res = { .res = {
.success = 1, .success = 1,
.rx_lev_full = 63, .rx_lev_full = 1,
.rx_qual_full = 3, .rx_qual_full = 7,
.toa256_mean = 0, .toa256_mean = 0,
.toa256_max = 0, .toa256_max = 0,
.toa256_min = 0, .toa256_min = 0,

View File

@@ -0,0 +1,6 @@
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 = ta_control_test
EXTRA_DIST = ta_control_test.ok
ta_control_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)

View File

@@ -0,0 +1,77 @@
/* 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>
void lchan_ms_ta_ctrl_test(int16_t toa256_start, unsigned int steps)
{
struct gsm_lchan lchan = { };
unsigned int i;
uint8_t rqd_ta_after;
uint8_t rqd_ta_before;
int16_t toa256 = toa256_start;
/* Arbitrary value, high enough so that a computation can happen. */
lchan.meas.num_ul_meas = 10;
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.rqd_ta (before) = %u\n", lchan.rqd_ta);
printf(" toa256 (before) = %u / 256 = %u\n", toa256,
toa256 / 256);
rqd_ta_before = lchan.rqd_ta;
lchan.meas.ms_toa256 = toa256;
lchan_ms_ta_ctrl(&lchan);
rqd_ta_after = lchan.rqd_ta;
toa256 -= (rqd_ta_after - rqd_ta_before) * 256;
printf(" lchan.rqd_ta (after) = %u\n", lchan.rqd_ta);
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);
}

View File

@@ -0,0 +1,609 @@
toa256_start = 4096 / 256 = 16, steps = 20
Step #0
lchan.rqd_ta (before) = 0
toa256 (before) = 4096 / 256 = 16
lchan.rqd_ta (after) = 1
toa256 (after) = 3840 / 256 = 15
Step #1
lchan.rqd_ta (before) = 1
toa256 (before) = 3840 / 256 = 15
lchan.rqd_ta (after) = 2
toa256 (after) = 3584 / 256 = 14
Step #2
lchan.rqd_ta (before) = 2
toa256 (before) = 3584 / 256 = 14
lchan.rqd_ta (after) = 3
toa256 (after) = 3328 / 256 = 13
Step #3
lchan.rqd_ta (before) = 3
toa256 (before) = 3328 / 256 = 13
lchan.rqd_ta (after) = 4
toa256 (after) = 3072 / 256 = 12
Step #4
lchan.rqd_ta (before) = 4
toa256 (before) = 3072 / 256 = 12
lchan.rqd_ta (after) = 5
toa256 (after) = 2816 / 256 = 11
Step #5
lchan.rqd_ta (before) = 5
toa256 (before) = 2816 / 256 = 11
lchan.rqd_ta (after) = 6
toa256 (after) = 2560 / 256 = 10
Step #6
lchan.rqd_ta (before) = 6
toa256 (before) = 2560 / 256 = 10
lchan.rqd_ta (after) = 7
toa256 (after) = 2304 / 256 = 9
Step #7
lchan.rqd_ta (before) = 7
toa256 (before) = 2304 / 256 = 9
lchan.rqd_ta (after) = 8
toa256 (after) = 2048 / 256 = 8
Step #8
lchan.rqd_ta (before) = 8
toa256 (before) = 2048 / 256 = 8
lchan.rqd_ta (after) = 9
toa256 (after) = 1792 / 256 = 7
Step #9
lchan.rqd_ta (before) = 9
toa256 (before) = 1792 / 256 = 7
lchan.rqd_ta (after) = 10
toa256 (after) = 1536 / 256 = 6
Step #10
lchan.rqd_ta (before) = 10
toa256 (before) = 1536 / 256 = 6
lchan.rqd_ta (after) = 11
toa256 (after) = 1280 / 256 = 5
Step #11
lchan.rqd_ta (before) = 11
toa256 (before) = 1280 / 256 = 5
lchan.rqd_ta (after) = 12
toa256 (after) = 1024 / 256 = 4
Step #12
lchan.rqd_ta (before) = 12
toa256 (before) = 1024 / 256 = 4
lchan.rqd_ta (after) = 13
toa256 (after) = 768 / 256 = 3
Step #13
lchan.rqd_ta (before) = 13
toa256 (before) = 768 / 256 = 3
lchan.rqd_ta (after) = 14
toa256 (after) = 512 / 256 = 2
Step #14
lchan.rqd_ta (before) = 14
toa256 (before) = 512 / 256 = 2
lchan.rqd_ta (after) = 15
toa256 (after) = 256 / 256 = 1
Step #15
lchan.rqd_ta (before) = 15
toa256 (before) = 256 / 256 = 1
lchan.rqd_ta (after) = 16
toa256 (after) = 0 / 256 = 0
Step #16
lchan.rqd_ta (before) = 16
toa256 (before) = 0 / 256 = 0
lchan.rqd_ta (after) = 16
toa256 (after) = 0 / 256 = 0
Step #17
lchan.rqd_ta (before) = 16
toa256 (before) = 0 / 256 = 0
lchan.rqd_ta (after) = 16
toa256 (after) = 0 / 256 = 0
Step #18
lchan.rqd_ta (before) = 16
toa256 (before) = 0 / 256 = 0
lchan.rqd_ta (after) = 16
toa256 (after) = 0 / 256 = 0
Step #19
lchan.rqd_ta (before) = 16
toa256 (before) = 0 / 256 = 0
lchan.rqd_ta (after) = 16
toa256 (after) = 0 / 256 = 0
Done.
toa256_start = 4000 / 256 = 15, steps = 50
Step #0
lchan.rqd_ta (before) = 0
toa256 (before) = 4000 / 256 = 15
lchan.rqd_ta (after) = 1
toa256 (after) = 3744 / 256 = 14
Step #1
lchan.rqd_ta (before) = 1
toa256 (before) = 3744 / 256 = 14
lchan.rqd_ta (after) = 2
toa256 (after) = 3488 / 256 = 13
Step #2
lchan.rqd_ta (before) = 2
toa256 (before) = 3488 / 256 = 13
lchan.rqd_ta (after) = 3
toa256 (after) = 3232 / 256 = 12
Step #3
lchan.rqd_ta (before) = 3
toa256 (before) = 3232 / 256 = 12
lchan.rqd_ta (after) = 4
toa256 (after) = 2976 / 256 = 11
Step #4
lchan.rqd_ta (before) = 4
toa256 (before) = 2976 / 256 = 11
lchan.rqd_ta (after) = 5
toa256 (after) = 2720 / 256 = 10
Step #5
lchan.rqd_ta (before) = 5
toa256 (before) = 2720 / 256 = 10
lchan.rqd_ta (after) = 6
toa256 (after) = 2464 / 256 = 9
Step #6
lchan.rqd_ta (before) = 6
toa256 (before) = 2464 / 256 = 9
lchan.rqd_ta (after) = 7
toa256 (after) = 2208 / 256 = 8
Step #7
lchan.rqd_ta (before) = 7
toa256 (before) = 2208 / 256 = 8
lchan.rqd_ta (after) = 8
toa256 (after) = 1952 / 256 = 7
Step #8
lchan.rqd_ta (before) = 8
toa256 (before) = 1952 / 256 = 7
lchan.rqd_ta (after) = 9
toa256 (after) = 1696 / 256 = 6
Step #9
lchan.rqd_ta (before) = 9
toa256 (before) = 1696 / 256 = 6
lchan.rqd_ta (after) = 10
toa256 (after) = 1440 / 256 = 5
Step #10
lchan.rqd_ta (before) = 10
toa256 (before) = 1440 / 256 = 5
lchan.rqd_ta (after) = 11
toa256 (after) = 1184 / 256 = 4
Step #11
lchan.rqd_ta (before) = 11
toa256 (before) = 1184 / 256 = 4
lchan.rqd_ta (after) = 12
toa256 (after) = 928 / 256 = 3
Step #12
lchan.rqd_ta (before) = 12
toa256 (before) = 928 / 256 = 3
lchan.rqd_ta (after) = 13
toa256 (after) = 672 / 256 = 2
Step #13
lchan.rqd_ta (before) = 13
toa256 (before) = 672 / 256 = 2
lchan.rqd_ta (after) = 14
toa256 (after) = 416 / 256 = 1
Step #14
lchan.rqd_ta (before) = 14
toa256 (before) = 416 / 256 = 1
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #15
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #16
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #17
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #18
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #19
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #20
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #21
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #22
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #23
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #24
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #25
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #26
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #27
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #28
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #29
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #30
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #31
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #32
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #33
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #34
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #35
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #36
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #37
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #38
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #39
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #40
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #41
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #42
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #43
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #44
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #45
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #46
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #47
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #48
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Step #49
lchan.rqd_ta (before) = 15
toa256 (before) = 160 / 256 = 0
lchan.rqd_ta (after) = 15
toa256 (after) = 160 / 256 = 0
Done.
toa256_start = 12345 / 256 = 48, steps = 50
Step #0
lchan.rqd_ta (before) = 0
toa256 (before) = 12345 / 256 = 48
lchan.rqd_ta (after) = 1
toa256 (after) = 12089 / 256 = 47
Step #1
lchan.rqd_ta (before) = 1
toa256 (before) = 12089 / 256 = 47
lchan.rqd_ta (after) = 2
toa256 (after) = 11833 / 256 = 46
Step #2
lchan.rqd_ta (before) = 2
toa256 (before) = 11833 / 256 = 46
lchan.rqd_ta (after) = 3
toa256 (after) = 11577 / 256 = 45
Step #3
lchan.rqd_ta (before) = 3
toa256 (before) = 11577 / 256 = 45
lchan.rqd_ta (after) = 4
toa256 (after) = 11321 / 256 = 44
Step #4
lchan.rqd_ta (before) = 4
toa256 (before) = 11321 / 256 = 44
lchan.rqd_ta (after) = 5
toa256 (after) = 11065 / 256 = 43
Step #5
lchan.rqd_ta (before) = 5
toa256 (before) = 11065 / 256 = 43
lchan.rqd_ta (after) = 6
toa256 (after) = 10809 / 256 = 42
Step #6
lchan.rqd_ta (before) = 6
toa256 (before) = 10809 / 256 = 42
lchan.rqd_ta (after) = 7
toa256 (after) = 10553 / 256 = 41
Step #7
lchan.rqd_ta (before) = 7
toa256 (before) = 10553 / 256 = 41
lchan.rqd_ta (after) = 8
toa256 (after) = 10297 / 256 = 40
Step #8
lchan.rqd_ta (before) = 8
toa256 (before) = 10297 / 256 = 40
lchan.rqd_ta (after) = 9
toa256 (after) = 10041 / 256 = 39
Step #9
lchan.rqd_ta (before) = 9
toa256 (before) = 10041 / 256 = 39
lchan.rqd_ta (after) = 10
toa256 (after) = 9785 / 256 = 38
Step #10
lchan.rqd_ta (before) = 10
toa256 (before) = 9785 / 256 = 38
lchan.rqd_ta (after) = 11
toa256 (after) = 9529 / 256 = 37
Step #11
lchan.rqd_ta (before) = 11
toa256 (before) = 9529 / 256 = 37
lchan.rqd_ta (after) = 12
toa256 (after) = 9273 / 256 = 36
Step #12
lchan.rqd_ta (before) = 12
toa256 (before) = 9273 / 256 = 36
lchan.rqd_ta (after) = 13
toa256 (after) = 9017 / 256 = 35
Step #13
lchan.rqd_ta (before) = 13
toa256 (before) = 9017 / 256 = 35
lchan.rqd_ta (after) = 14
toa256 (after) = 8761 / 256 = 34
Step #14
lchan.rqd_ta (before) = 14
toa256 (before) = 8761 / 256 = 34
lchan.rqd_ta (after) = 15
toa256 (after) = 8505 / 256 = 33
Step #15
lchan.rqd_ta (before) = 15
toa256 (before) = 8505 / 256 = 33
lchan.rqd_ta (after) = 16
toa256 (after) = 8249 / 256 = 32
Step #16
lchan.rqd_ta (before) = 16
toa256 (before) = 8249 / 256 = 32
lchan.rqd_ta (after) = 17
toa256 (after) = 7993 / 256 = 31
Step #17
lchan.rqd_ta (before) = 17
toa256 (before) = 7993 / 256 = 31
lchan.rqd_ta (after) = 18
toa256 (after) = 7737 / 256 = 30
Step #18
lchan.rqd_ta (before) = 18
toa256 (before) = 7737 / 256 = 30
lchan.rqd_ta (after) = 19
toa256 (after) = 7481 / 256 = 29
Step #19
lchan.rqd_ta (before) = 19
toa256 (before) = 7481 / 256 = 29
lchan.rqd_ta (after) = 20
toa256 (after) = 7225 / 256 = 28
Step #20
lchan.rqd_ta (before) = 20
toa256 (before) = 7225 / 256 = 28
lchan.rqd_ta (after) = 21
toa256 (after) = 6969 / 256 = 27
Step #21
lchan.rqd_ta (before) = 21
toa256 (before) = 6969 / 256 = 27
lchan.rqd_ta (after) = 22
toa256 (after) = 6713 / 256 = 26
Step #22
lchan.rqd_ta (before) = 22
toa256 (before) = 6713 / 256 = 26
lchan.rqd_ta (after) = 23
toa256 (after) = 6457 / 256 = 25
Step #23
lchan.rqd_ta (before) = 23
toa256 (before) = 6457 / 256 = 25
lchan.rqd_ta (after) = 24
toa256 (after) = 6201 / 256 = 24
Step #24
lchan.rqd_ta (before) = 24
toa256 (before) = 6201 / 256 = 24
lchan.rqd_ta (after) = 25
toa256 (after) = 5945 / 256 = 23
Step #25
lchan.rqd_ta (before) = 25
toa256 (before) = 5945 / 256 = 23
lchan.rqd_ta (after) = 26
toa256 (after) = 5689 / 256 = 22
Step #26
lchan.rqd_ta (before) = 26
toa256 (before) = 5689 / 256 = 22
lchan.rqd_ta (after) = 27
toa256 (after) = 5433 / 256 = 21
Step #27
lchan.rqd_ta (before) = 27
toa256 (before) = 5433 / 256 = 21
lchan.rqd_ta (after) = 28
toa256 (after) = 5177 / 256 = 20
Step #28
lchan.rqd_ta (before) = 28
toa256 (before) = 5177 / 256 = 20
lchan.rqd_ta (after) = 29
toa256 (after) = 4921 / 256 = 19
Step #29
lchan.rqd_ta (before) = 29
toa256 (before) = 4921 / 256 = 19
lchan.rqd_ta (after) = 30
toa256 (after) = 4665 / 256 = 18
Step #30
lchan.rqd_ta (before) = 30
toa256 (before) = 4665 / 256 = 18
lchan.rqd_ta (after) = 31
toa256 (after) = 4409 / 256 = 17
Step #31
lchan.rqd_ta (before) = 31
toa256 (before) = 4409 / 256 = 17
lchan.rqd_ta (after) = 32
toa256 (after) = 4153 / 256 = 16
Step #32
lchan.rqd_ta (before) = 32
toa256 (before) = 4153 / 256 = 16
lchan.rqd_ta (after) = 33
toa256 (after) = 3897 / 256 = 15
Step #33
lchan.rqd_ta (before) = 33
toa256 (before) = 3897 / 256 = 15
lchan.rqd_ta (after) = 34
toa256 (after) = 3641 / 256 = 14
Step #34
lchan.rqd_ta (before) = 34
toa256 (before) = 3641 / 256 = 14
lchan.rqd_ta (after) = 35
toa256 (after) = 3385 / 256 = 13
Step #35
lchan.rqd_ta (before) = 35
toa256 (before) = 3385 / 256 = 13
lchan.rqd_ta (after) = 36
toa256 (after) = 3129 / 256 = 12
Step #36
lchan.rqd_ta (before) = 36
toa256 (before) = 3129 / 256 = 12
lchan.rqd_ta (after) = 37
toa256 (after) = 2873 / 256 = 11
Step #37
lchan.rqd_ta (before) = 37
toa256 (before) = 2873 / 256 = 11
lchan.rqd_ta (after) = 38
toa256 (after) = 2617 / 256 = 10
Step #38
lchan.rqd_ta (before) = 38
toa256 (before) = 2617 / 256 = 10
lchan.rqd_ta (after) = 39
toa256 (after) = 2361 / 256 = 9
Step #39
lchan.rqd_ta (before) = 39
toa256 (before) = 2361 / 256 = 9
lchan.rqd_ta (after) = 40
toa256 (after) = 2105 / 256 = 8
Step #40
lchan.rqd_ta (before) = 40
toa256 (before) = 2105 / 256 = 8
lchan.rqd_ta (after) = 41
toa256 (after) = 1849 / 256 = 7
Step #41
lchan.rqd_ta (before) = 41
toa256 (before) = 1849 / 256 = 7
lchan.rqd_ta (after) = 42
toa256 (after) = 1593 / 256 = 6
Step #42
lchan.rqd_ta (before) = 42
toa256 (before) = 1593 / 256 = 6
lchan.rqd_ta (after) = 43
toa256 (after) = 1337 / 256 = 5
Step #43
lchan.rqd_ta (before) = 43
toa256 (before) = 1337 / 256 = 5
lchan.rqd_ta (after) = 44
toa256 (after) = 1081 / 256 = 4
Step #44
lchan.rqd_ta (before) = 44
toa256 (before) = 1081 / 256 = 4
lchan.rqd_ta (after) = 45
toa256 (after) = 825 / 256 = 3
Step #45
lchan.rqd_ta (before) = 45
toa256 (before) = 825 / 256 = 3
lchan.rqd_ta (after) = 46
toa256 (after) = 569 / 256 = 2
Step #46
lchan.rqd_ta (before) = 46
toa256 (before) = 569 / 256 = 2
lchan.rqd_ta (after) = 47
toa256 (after) = 313 / 256 = 1
Step #47
lchan.rqd_ta (before) = 47
toa256 (before) = 313 / 256 = 1
lchan.rqd_ta (after) = 48
toa256 (after) = 57 / 256 = 0
Step #48
lchan.rqd_ta (before) = 48
toa256 (before) = 57 / 256 = 0
lchan.rqd_ta (after) = 48
toa256 (after) = 57 / 256 = 0
Step #49
lchan.rqd_ta (before) = 48
toa256 (before) = 57 / 256 = 0
lchan.rqd_ta (after) = 48
toa256 (after) = 57 / 256 = 0
Done.

View File

@@ -49,3 +49,9 @@ AT_KEYWORDS([meas])
cat $abs_srcdir/meas/meas_test.ok > expout cat $abs_srcdir/meas/meas_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/meas/meas_test], [], [expout], [ignore]) AT_CHECK([$abs_top_builddir/tests/meas/meas_test], [], [expout], [ignore])
AT_CLEANUP 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