Compare commits

..

61 Commits

Author SHA1 Message Date
Pau Espin Pedrol
309ad4d901 Bump version: 1.2.0.132-3b8f-dirty → 1.3.0
Change-Id: I92b99ebab1d54e9cbdc8469d76105c55bcb03f36
2021-02-23 14:27:15 +01:00
Vadim Yanitskiy
3b8f7c4d97 Add a (hidden) VTY parameter for Rx/Tx freq. shifting
Change-Id: I360e8ba91471757210c7f096c04928a6fbb91c61
Related: SYS#4454
2021-02-21 12:01:16 +01:00
Pau Espin Pedrol
48cad832ea tests: Replace deprecated API log_set_print_filename
Change-Id: I3cc0a92da39ab2594b3a7cefb314e2f2ecb628e2
2021-02-19 14:09:01 +01:00
Pau Espin Pedrol
56237bce95 tests: Explicitly drop category from log
Let's disable category here since we don't care about its formatting here.

In any case, every test relying on logging output validation should
always explicitly state the config to avoid issues in the future if
default values change.

Change-Id: Iaa77f8a7d3f752173507afd988bd76a8aa632082
Related: OS#5034
2021-02-19 14:08:44 +01:00
Pau Espin Pedrol
5738940535 Replace my_gettid with libosmocore osmo_gettid API
The API was moved to libosmocore, let's use it instead of defining our
own here with all the complexity in build system involved.

Depends: libosmocore.git Change-Id Id7534beeb22fcd50813dab76dd68818e2ff87ec2
Related: OS#5027
Change-Id: I19e32fbc47bd88a668e0c912e89b001b0f8831dd
2021-02-17 18:27:41 +01:00
Pau Espin Pedrol
cec9eda227 Threads.cpp: Use already existing gettid wrapper function
A wrapper function with better support already exists in debug.c and
announced in debug.h. Let's use that one instead.

Related: OS#5027
Change-Id: I2ccf94f95a531d5873da2a4681cf89cbc5b31422
2021-02-17 17:28:06 +01:00
Sylvain Munaut
ad202d72e1 sigProcLib: fix C/I computation for 8-PSK modulated bursts
Change-Id: I860af60bc0fbd36dfb38316fad65ddd3a5827a8f
Related: Ib4ceec553f2e5f77bf3f6777724968456a180f5e
Related: OS#4006, OS#4373
2021-02-04 20:44:51 +01:00
Oliver Smith
0f4d5791df configure.ac: set -std=gnu11
Change-Id: Ie95876d1d2ebf31ff588999d85584f6981522fa8
2021-01-28 10:48:35 +00:00
Vadim Yanitskiy
2a637a5c9c Transceiver: use proper factor for amplitude scaling
In Transceiver::addRadioVector() we scale the I/Q samples by scaling
the output voltage of the DAC.   A relative factor/divisor/ration in
the voltage domain cannot be used 1:1 in the power domain.

There exist two similar formulas:

  a) X_dB = 10 * log10(X_lin / X_ref)
  b) Y_db = 20 * log10(Y_lin / Y_ref)

both of them are correct, and according to [1]:

  a) If you convert a quantity X that relates to power or energy,
     => the factor is 10.
  b) If you convert a quantity Y that relates to amplitude,
     => the factor is 20.

Therefore we should be using 20 instead of 10.  This change makes
osmo-trx apply per-lchan attenuation values correctly.  Otherwise
it would double the values indicated in TRXD messages.

[1] https://dspillustrations.com/pages/posts/misc/decibel-conversion-factor-10-or-factor-20.html

Change-Id: I98bc00bd25df4913d45e55eb008d715aca76fc7c
Related: SYS#4918
2021-01-27 01:01:50 +01:00
Vadim Yanitskiy
819cad1776 Transceiver: fix integer division in addRadioVector()
By default, C/C++ compiler does assume integer division.  The
lack of explicit cast to 'double' causes the transceiver to
ignore non-decimal attenuation values (x % 10 > 0):

  txFullScale * 10 ^ ( -3 / 10)
	== txFullScale * 10 ^ 0
	== txFullScale * 1.0

  txFullScale * 10 ^ ( -8 / 10)
	== txFullScale * 10 ^ 0
	== txFullScale * 1.0

  txFullScale * 10 ^ (-10 / 10)
	== txFullScale * 10 ^ -1
	== txFullScale * 0.1

  txFullScale * 10 ^ (-18 / 10)
	== txFullScale * 10 ^ -1
	== txFullScale * 0.1

Change-Id: I85b1063f57f630d90c6da32827bec4a05afc6514
Related: SYS#4918
2021-01-21 00:24:16 +01:00
Pau Espin Pedrol
54a98b5b52 ChannelizerBase: Fix memory leak
The memory leak was reported by ASan:

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x7f23b488e459 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x558e83e39e3c in ChannelizerBase::initFilters() /osmo-trx/Transceiver52M/ChannelizerBase.cpp:84
    #2 0x558e83e3a8a0 in ChannelizerBase::init() /osmo-trx/Transceiver52M/ChannelizerBase.cpp:188
    #3 0x558e83e2d263 in RadioInterfaceMulti::init(int) /osmo-trx/Transceiver52M/radioInterfaceMulti.cpp:197
    #4 0x558e83de76d2 in makeRadioInterface(trx_ctx*, RadioDevice*, int) /osmo-trx/Transceiver52M/osmo-trx.cpp:115
    #5 0x558e83dea663 in trx_start /osmo-trx/Transceiver52M/osmo-trx.cpp:600
    #6 0x558e83dead6f in main /osmo-trx/Transceiver52M/osmo-trx.cpp:695
    #7 0x7f23b2576151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)

Change-Id: Ibc4c7edeb9bba517db08fce152d863e6cc0c7bbb
2021-01-18 11:39:24 +00:00
Pau Espin Pedrol
fca503d0b4 radioInterfaceMulti: Fix memory leak upon close()
The leak was reported by ASan.

Direct leak of 48 byte(s) in 1 object(s) allocated from:
    #0 0x7fd9c9c29f41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x55bd63ae2364 in RadioInterfaceMulti::init(int) /git/osmo-trx/Transceiver52M/radioInterfaceMulti.cpp:209
    #2 0x55bd63a9c6d2 in makeRadioInterface(trx_ctx*, RadioDevice*, int) /git/osmo-trx/Transceiver52M/osmo-trx.cpp:115
    #3 0x55bd63a9f663 in trx_start /git/osmo-trx/Transceiver52M/osmo-trx.cpp:600
    #4 0x55bd63a9fd6f in main /git/osmo-trx/Transceiver52M/osmo-trx.cpp:695
    #5 0x7fd9c7910151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)

Change-Id: Ia4f9d4e47caa86ada98054763573e652d281992c
2021-01-17 17:18:49 +00:00
Oliver Smith
e8edd1fcae contrib/jenkins: don't build osmo-gsm-manuals
Related: OS#4912
Change-Id: Ibacb11da37acfd324cee37068099627136717781
2021-01-13 13:16:48 +01:00
Alexander Couzens
7e27deb8cb osmo-trx.spec: move ipc-driver-test into package ipc-test
Allow to drop the uhd runtime dependency of osmo-trx-ipc.
uhd is only required for the driver-test utility.

Related: SYS#5266
Change-Id: Iff91e09684167247c9c7de0141451a5b9344aa0d
2021-01-08 09:32:03 +01:00
Harald Welte
a9512d963a manual: Fix typo OsmTRX -> OsmoTRX
Change-Id: I4b3a76e41d4abbb08046a241ae9b7c079ce990ae
2021-01-07 14:07:14 +01:00
Harald Welte
c6220741b1 README update
* use https for hyperlinks
* explicitly mention the primary use case with OsmoBTS
* fix spelling in title

Change-Id: I4f20ad8666dcc6bbc23d78b40b7c73ddd7e6eacc
2021-01-06 13:27:56 +01:00
Pau Espin Pedrol
4a4e607a19 ipc-driver-test: Allow setting dir prefix for UD socket
Change-Id: I35282b38a1d560fb3440fe0aa9a27808d9d116cc
2020-12-10 15:26:32 +00:00
Vadim Yanitskiy
1587307a99 vty: fix swapped documentation for 'filler type' command
vty_cmd_string_from_valstr() expands the given 'struct value_string'
sequentionally, so the order of entries in both filler_{types,docs}
shall match (regardless of the value assigned).

Change-Id: Ieb3bbc4fb30f303c47555ca77d03a9e965bc72b5
2020-12-08 15:38:00 +01:00
Pau Espin Pedrol
7e83f18bba ipc: Fix wrong reference to BTS in log line
Change-Id: Idd272959e335c46ca88e348dd792e15ddb317d61
2020-12-07 19:28:44 +01:00
Pau Espin Pedrol
57db77f185 main: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Change-Id: I3a3ff56cb2d740a33731ecfdf76aa32606872883
Fixes: OS#4865
2020-11-25 17:50:21 +01:00
Harald Welte
94def47fdf Use osmo_fd_*_{disable,enable}
Change-Id: Ic8c8c418e123fbdff625556a900b19650deefe0b
Depends: libosmocore.git Idb89ba7bc7c129a6304a76900d17f47daf54d17d
2020-11-11 20:15:59 +00:00
Vadim Yanitskiy
3fb4d31ecb doc/manuals: generate XML VTY reference at build-time
Unfortunately, we cannot re-use the existing Makefile rules from:

  $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc

because they do not allow to generate the list of $(DOCBOOKS) from
a template, and require the project to store everything in separate
folders with specific names.  Also, those rules expect that the
target PDFs contain only a single word in their names (for example,
'osmoapp-vty-reference', not 'osmo-app-vty-reference'), while in a
project with multiple similarly named targets this would reduce
readability (imagine 'osmotrxuhd-vty-reference').

Change-Id: I798ea3b7417b8ca3e9c7d50911158c5413526237
Depends: I6aac73d998c5937894233631e654a160d5623198
Related: SYS#4937, SYS#4910
2020-11-04 19:33:05 +00:00
Vadim Yanitskiy
744e44eaa1 main: use logging API to print SIMD info instead of printf()
Otherwise these logging lines end up in the automatically generated
XML VTY reference (stdout), so this breaks further XML processing.

Change-Id: I8e0fd728d406e2452c9c0ddad5bce5f6b17fab42
Related: SYS#4937, SYS#4910
2020-11-04 19:33:05 +00:00
Vadim Yanitskiy
faacb1987e vty: fix documentation for 'ext-rach (disable|enable)'
Do not use 'extended' because it's not the same 11-bit Access Burst,
as it was assumed before.  Add missing docs for 'enable'/'disable'.

Change-Id: I80b5a584e554eb7cc2416017b10fee032202b372
2020-11-04 19:29:45 +00:00
Vadim Yanitskiy
c0e7ce922a vty: auto-generate cmd and doc strings for cfg_filler_type_cmd
Change-Id: I7fb228c63f3246f443ece67106abba0432b1659e
2020-11-02 09:28:19 +00:00
Vadim Yanitskiy
ab6e7f35ab vty: remove groundless statement about filler type 'dummy'
Dummy bursts have nothing to do with A5/x encryption, and I see
no reason why (and how?!?) would using that filler type break
encryption in osmo-bts-trx.  I asked the author of this code
back in August 2020 [1], and so far didn't get any response.

[1] https://lists.osmocom.org/pipermail/openbsc/2020-August/013208.html

Change-Id: Iae513d7acbb8ef682e1744ac8726cbd6ece8bd87
2020-11-02 09:27:59 +00:00
Vadim Yanitskiy
5d6504c45a vty: fix documentation for 'multi-arfcn (disable|enable)'
Change-Id: Id653ee058b208ddc105947319adad8da667be11f
2020-11-02 09:27:14 +00:00
Vadim Yanitskiy
c620ced36d vty: cosmetic: use VTY_IPV4_CMD in 'bind-ip' / 'remote-ip'
Change-Id: I8e44f771cbd03629c066bc24c3186997761f93f1
2020-11-02 09:27:08 +00:00
Vadim Yanitskiy
ef79fd9b95 vty: fix documentation for 'rx-sps (1|4)' and 'tx-sps (1|4)'
Change-Id: I70d9b16fd2b1c2cbaafc978724369cd2c9679cbd
2020-11-02 09:27:02 +00:00
Vadim Yanitskiy
e0bdb6b47b vty: fix documentation for 'egprs (disable|enable)'
Change-Id: I7a28bede8fd7d68b3afe9deec381fc93e46d65a9
2020-10-30 04:17:39 +07:00
Vadim Yanitskiy
948b4e4096 vty: fix documentation for 'swap-channels (disable|enable)'
Change-Id: Idca1a2beab07ef4df9ae5c55658cab80f7cc7565
2020-10-30 04:17:39 +07:00
Vadim Yanitskiy
c7a750d428 Transceiver: explicitly init m{Rx,Tx}LowerLoopThread
Coverity warns us that a non-static class members:

  - mRxLowerLoopThread, and
  - mTxLowerLoopThread,

are not initialized in this constructor nor in any functions that
it calls.  I don't think it's critical, because we do initialize
them in Transceiver::start(), but let's make them nullptr.

Change-Id: If9e06aa7965f17383ab6599c15945e8ce2703bbf
Fixes: CID#214952
2020-10-25 15:24:21 +07:00
Vadim Yanitskiy
0ff9c9fca3 Transceiver: use size_t and ARRAY_SIZE() in constructor
Change-Id: I164d66aad04d77957300b07e83b085f43a3ee8c1
2020-10-24 23:41:57 +00:00
Vadim Yanitskiy
24cb0c9948 device: drop unreasonable LIBOSMO{CTRL,VTY}_{CFLAGS,LIBS}
Neither VTY nor CTRL API is used in device specific code, excluding
the 'uhd' where osmo_cpu_sched_vty_apply_localthread() is called.

Change-Id: I568b443da4b96c005734d749faa22b9c7440f951
2020-10-24 23:41:57 +00:00
Vadim Yanitskiy
6be2d15541 main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
Change-Id: Ie54c45fdcc8660f37f8db2367b53404b189b3ffc
Depends: Ie2022a7f9e167e5ceacf15350c037dd43768ff40
Related: SYS#4910
2020-10-24 21:16:17 +00:00
Vadim Yanitskiy
bc5263cee1 device/common/Makefile.am: remove $(LMS_CFLAGS) from AM_CXXFLAGS
This is device-independent code, so it should not be here.

Change-Id: I1ffc3431a9a1a46c74c354b3f8a256684bfcbe73
2020-10-24 19:44:21 +00:00
Vadim Yanitskiy
6b4acc12f7 device/lms: get rid of 'using namespace std'
Change-Id: I4329801c502db73efa946f15c103b2c081cee5a7
2020-10-24 19:25:32 +07:00
Vadim Yanitskiy
d1ca287d83 device/lms: fix missing semicolon in LMSDevice::assign_band_desc()
Change-Id: I6aedb72306461ebb944fc13a795b0bf3121ea275
2020-10-24 19:25:32 +07:00
Vadim Yanitskiy
a0d862ba1d device/lms: fix: 'trx_vty.h' header requires C linkage
Otherwise, the linker fails to produce osmo-trx-lms binary:

  LMSDevice.cpp:493: undefined reference to
    `get_value_string(value_string const*, unsigned int)'

  LMSDevice.cpp:237: undefined reference to
    `osmo_panic(char const*, ...)'

Change-Id: I2fef166c13136af7b7aaa744d39427d76ad11769
Fixes: OS#4828
2020-10-24 19:25:32 +07:00
Harald Welte
c5989fe180 Use osmo_fd_setup() wherever applicable
Change-Id: Ie093dea96ec8990368695c0c5824e0fe44fb8540
2020-10-19 12:27:36 +02:00
Harald Welte
08970c562f ipc: Use OSMO_FD_* instead of deprecated BSC_FD_*
Change-Id: I98b3f9525954d6882f7488d650038a8e28f7b769
2020-10-18 22:41:40 +02:00
Pau Espin Pedrol
e91544d740 Calculate RSSI offset based on RxGain configuration
Prior to this patch, osmo-trx relied totally on proper VTY configuration
being set in "rssi-offset" together with the RxGain set through TRXC in
order to provide correct Uplink RSSI measurements to bts-trx.

With this patch, RSSI is now by default calculated (in LMS and UHD
backends) based on the currently set RxGain, by providing empirically
discovered values. Still, for backward compatibility, the old
"rssi-offset" command will overwrite completely the per-default
calculated rssi offset.
A new optional parameter "relative" is added at the end of the
"rssi-offset" VTY command to flag the value as relative to the newly
per-default calculated value. This way specific setups (like adding a
LNA / RF fronted) can still be expressed while still keeping the
automatic per-default offset.

Related: OS#4468
Change-Id: I8ef78fd20c22c60d61bfb18d80a4a36df4fd6c20
2020-10-14 12:53:04 +02:00
Pau Espin Pedrol
93fee1f163 Transceiver: Pass config struct instead of large list of params
Change-Id: Ifb43cb11f3e7a69b0a88f632f0a0c90ada7f939e
2020-10-14 12:52:04 +02:00
Pau Espin Pedrol
e69a56cec5 contrib/jenkins: Enable parallel make in make distcheck
Change-Id: I32925b35126bcd4ef7b5e1315dde28869c2b4b86
Related: OS#4421
2020-10-12 19:48:47 +02:00
Philipp Maier
76795401fb osmo-trx: add commandline option --vty-ref-xml
The commandline option --vty-ref-xml is needed to enable automatic
generation of the VTY reference manual.

Change-Id: I34dd36183e013ab005f39b235c4ab561590befb7
Related: SYS#4937, OS#1601
2020-10-09 20:48:00 +02:00
Philipp Maier
30863e8720 vty: add attributes to VTY commands indicating when they apply
Change-Id: I6dfdedc081eb8c3d53913f6fa38591920c8b3b43
Related: SYS#4937, OS#1601
2020-10-08 19:36:35 +02:00
Pau Espin Pedrol
0fbdfefebc arch: x86: Fix convolve optimizations breaking signal
This patch fixes MS failing to even see the network, and only RACHs of 1
zeroed byte being seen in GSMTAP.

The issue seems to only appear on some specific machines; others have
been running fine for weeks without this memset being an issue.

Fixes: 7a52e42ee0
Change-Id: I98ad885a5d71e7775973a4d881c0f1cd665ea711
2020-09-18 20:19:56 +02:00
Vadim Yanitskiy
b7c6f1e83f radioDevice: fix set_antennas(): consider MULTI_ARFCN mode
In the multi-ARFCN mode, if the Tx/Rx antenna names are explicitly
set in 'chan N' sections of the configuration file:

  trx
   ...
   multi-arfcn disable
   chan 0
    tx-path TX/RX
    rx-path RX2
   chan 1
    tx-path TX/RX
    rx-path RX2
   chan 2
    tx-path TX/RX
    rx-path RX2

osmo-trx would crash, because radioDevice::set_antennas() would
attempt to configure antenna names for all N physical channels,
while USRP devices usually have 2 or even 1 available.

The easiest approach is to remove both 'tx-path'/'rx-path' from
all 'chan N' sections excluding 'chan 0', so it would work fine.
This makes sense, because in the multi-ARFCN mode we actually
use only one physical channel.

However, let's still make sure that explicit configuration of the
Tx/Rx antenna names would not crash osmo-trx and skip N > 0 in
radioDevice::set_antennas().

Change-Id: I09f316f181cbbc2214e8913b73f7c1fcea4e8c05
Related: OS#4636
2020-09-12 14:47:21 +07:00
Vadim Yanitskiy
4d43684194 vty: add multi-ARFCN specific warning for chan N > 0
Change-Id: I12d7c466a9a428a384233c4377627e262f165401
Related: OS#4636
2020-09-12 14:39:20 +07:00
Vadim Yanitskiy
54bde5a8ba proto_trxd: cosmetic: 'if' is not a function, add space
Change-Id: I99cf10662232b1f6845d4019dd3b9be45a82d85b
2020-09-11 21:03:08 +07:00
Harald Welte
fd88564acb [cosmetic] radioIntefaceMulti: Fix whitespace / indent
Change-Id: I3addb844a79a8f4e8af03323fc50e57b8a3590a8
2020-09-11 12:43:05 +02:00
Harald Welte
82c72218fd [cosmetic] radioInterfaceMulti: More comments
Change-Id: If608627a77c39b5faabc72c7dd72d00fae8697a9
2020-09-11 12:43:02 +02:00
Eric
1f37e4dd74 transceiver: initialize reorder flag so we don't miscount
Change-Id: Ia7740b45611dbf09a406b3fd9f0a810d46c96bde
2020-09-04 20:36:34 +02:00
Pau Espin Pedrol
7d8676a144 Add support for TRXC MUTE command
Related: SYS#4920
Change-Id: I39983d026ad54c479aa224968e9491d01f30dc35
2020-09-01 13:27:39 +02:00
Harald Welte
8808fa86f0 Fix build on Debian8
We cannot use C99 or higher features in C code!

Last lines of build log:
[  265s]    for (unsigned int i = 0; i < decoded_region->num_chans; i++)
[  265s]    ^
[  265s] ipc-driver-test.c:473:3: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile
your code
[  265s] Makefile:580: recipe for target 'ipc_driver_test-ipc-driver-test.o' failed
[  265s] make[5]: *** [ipc_driver_test-ipc-driver-test.o] Error 1

Change-Id: I80c9cbd77f1cdf323ad2b492de7e9a177840c383
2020-08-27 10:08:53 +02:00
Pau Espin Pedrol
2a0fb962c7 ipc: fix var declaration in for loop
"""
error: 'for' loop initial declarations are only allowed in C99 or C11 mode
"""

Change-Id: I97cb9a0a3ecf64e3e5fcfca75431f8fe2a07bd10
2020-08-26 09:30:41 +00:00
Pau Espin Pedrol
03334967c9 jenkins.sh: Verify distro-specific patches apply
Change-Id: I75792c5defff63b7deaeb533b6818deaac3e0fd3
2020-08-25 15:41:30 +02:00
Pau Espin Pedrol
e30e0ad9be debian: Update debian8 osmo-trx specific patch
Recent commit adding osmo-trx-ipc didn't update the patch, which fails
to apply now due to files having changed its contents.

Change-Id: I6fa50e82320330f83c9753352418755e8b414edf
2020-08-25 15:41:30 +02:00
Eric
7a52e42ee0 transceiver: optimize code if optimizations are enabled
There is no point in checking basic stuff ten thousand times per second
since the sizes never change, so it's enough to enable the
checks/assertions for unoptimized (debug) builds.

This significantly decreases branch mispredictions.

Change-Id: Iebd9e91b3c7f37f2dc646d3017c45139977e4d15
2020-08-25 01:00:19 +02:00
Eric
4080eb76f8 devices: reset internal smart sample buffers upon stop
They are too smart, they keep the timestamps.

Change-Id: Idb4b8f03eb5ffdfd6d3fdbc137b20e3ddc4cfa65
2020-08-25 01:00:19 +02:00
Eric Wild
1e17c4fb0a osmo-trx-ipc
This adds a IPC backend that uses shared memory interface
to communicate with (proprietary) devices.

Requires config file option
dev-args ipc_msock=/path/to/socket
to specify the master socket the ipc backend should connect to.

If UHD is avaialble the ipc-driver-test tool can be used to test the
backend with a uhd device, this was so far only tested with a b2xx.

Change-Id: Ice63d3499026293ade8aad675ff7a883bcdd5756
2020-08-25 01:00:03 +02:00
67 changed files with 1402 additions and 2316 deletions

5
.gitignore vendored
View File

@@ -7,6 +7,8 @@ Transceiver52M/osmo-trx-usrp1
Transceiver52M/osmo-trx-lms
Transceiver52M/osmo-trx-ipc
.clang-format
# tests
tests/CommonLibs/BitVectorTest
tests/CommonLibs/F16Test
@@ -62,6 +64,9 @@ doc/manuals/*.pdf
doc/manuals/*__*.png
doc/manuals/*.check
doc/manuals/generated/
doc/manuals/vty/osmotrx-*-vty-reference.xml
doc/manuals/vty/osmotrx-*-vty-reference.xml.inc.gen
doc/manuals/vty/osmotrx-*-vty-reference.xml.inc.merged
doc/manuals/osmomsc-usermanual.xml
doc/manuals/common
doc/manuals/build

View File

@@ -32,11 +32,7 @@
#include "Timeval.h"
#include "Logger.h"
#ifndef gettid
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
#include <osmocom/core/thread.h>
using namespace std;
@@ -114,7 +110,7 @@ void Signal::wait(Mutex& wMutex, unsigned timeout) const
void set_selfthread_name(const char *name)
{
pthread_t selfid = pthread_self();
pid_t tid = gettid();
pid_t tid = osmo_gettid();
if (pthread_setname_np(selfid, name) == 0) {
LOG(INFO) << "Thread "<< selfid << " (task " << tid << ") set name: " << name;
} else {

View File

@@ -36,6 +36,11 @@
#include <assert.h>
#include <stdlib.h>
#ifndef __OPTIMIZE__
#define assert_no_opt(x) assert(x)
#else
#define assert_no_opt(x)
#endif
// We can't use Logger.h in this file...
extern int gVectorDebug;
#define BVDEBUG(msg) if (gVectorDebug) {std::cout << msg;}
@@ -81,8 +86,8 @@ template <class T> class Vector {
/** Return the size of the Vector. */
size_t size() const
{
assert(mStart>=mData);
assert(mEnd>=mStart);
assert_no_opt(mStart>=mData);
assert_no_opt(mEnd>=mStart);
return mEnd - mStart;
}
@@ -112,7 +117,7 @@ template <class T> class Vector {
/** Reduce addressable size of the Vector, keeping content. */
void shrink(size_t newSize)
{
assert(newSize <= mEnd - mStart);
assert_no_opt(newSize <= mEnd - mStart);
mEnd = mStart + newSize;
}
@@ -199,7 +204,7 @@ template <class T> class Vector {
{
T* wStart = mStart + start;
T* wEnd = wStart + span;
assert(wEnd<=mEnd);
assert_no_opt(wEnd<=mEnd);
return Vector<T>(NULL,wStart,wEnd);
}
@@ -208,7 +213,7 @@ template <class T> class Vector {
{
T* wStart = mStart + start;
T* wEnd = wStart + span;
assert(wEnd<=mEnd);
assert_no_opt(wEnd<=mEnd);
return Vector<T>(NULL,wStart,wEnd);
}
@@ -228,8 +233,8 @@ template <class T> class Vector {
unsigned int i;
T* dst = other.mStart + start;
T* src = mStart;
assert(dst+span<=other.mEnd);
assert(mStart+span<=mEnd);
assert_no_opt(dst+span<=other.mEnd);
assert_no_opt(mStart+span<=mEnd);
for (i = 0; i < span; i++, src++, dst++)
*dst = *src;
/*TODO if not non-trivially copiable type class, optimize:
@@ -250,8 +255,8 @@ template <class T> class Vector {
void segmentCopyTo(Vector<T>& other, size_t start, size_t span) const
{
const T* base = mStart + start;
assert(base+span<=mEnd);
assert(other.mStart+span<=other.mEnd);
assert_no_opt(base+span<=mEnd);
assert_no_opt(other.mStart+span<=other.mEnd);
memcpy(other.mStart,base,span*sizeof(T));
}
@@ -265,8 +270,8 @@ template <class T> class Vector {
{
const T* baseFrom = mStart + from;
T* baseTo = mStart + to;
assert(baseFrom+span<=mEnd);
assert(baseTo+span<=mEnd);
assert_no_opt(baseFrom+span<=mEnd);
assert_no_opt(baseTo+span<=mEnd);
memmove(baseTo,baseFrom,span*sizeof(T));
}
@@ -280,7 +285,7 @@ template <class T> class Vector {
{
T* dp=mStart+start;
T* end=dp+length;
assert(end<=mEnd);
assert_no_opt(end<=mEnd);
while (dp<end) *dp++=val;
}
@@ -292,13 +297,13 @@ template <class T> class Vector {
T& operator[](size_t index)
{
assert(mStart+index<mEnd);
assert_no_opt(mStart+index<mEnd);
return mStart[index];
}
const T& operator[](size_t index) const
{
assert(mStart+index<mEnd);
assert_no_opt(mStart+index<mEnd);
return mStart[index];
}

View File

@@ -5,6 +5,8 @@
* osmo-trx (CXX, dir Transceiver52)
*/
#include <stdbool.h>
enum FillerType {
FILLER_DUMMY,
FILLER_ZERO,
@@ -18,3 +20,40 @@ enum ReferenceType {
REF_EXTERNAL,
REF_GPS,
};
/* Maximum number of physical RF channels */
#define TRX_CHAN_MAX 8
struct trx_ctx;
struct trx_chan {
struct trx_ctx *trx; /* backpointer */
unsigned int idx; /* channel index */
char *rx_path;
char *tx_path;
};
struct trx_cfg {
char *bind_addr;
char *remote_addr;
char *dev_args;
unsigned int base_port;
unsigned int tx_sps;
unsigned int rx_sps;
unsigned int rtsc;
unsigned int rach_delay;
enum ReferenceType clock_ref;
enum FillerType filler;
bool multi_arfcn;
double offset;
double freq_offset_khz;
double rssi_offset;
bool force_rssi_offset; /* Force value set in VTY? */
bool swap_channels;
bool ext_rach;
bool egprs;
unsigned int sched_rr;
unsigned int stack_size;
unsigned int num_chans;
struct trx_chan chans[TRX_CHAN_MAX];
};

View File

@@ -21,18 +21,6 @@
* See the COPYING file in the main directory for details.
*/
#include "config.h"
/* If HAVE_GETTID, then "_GNU_SOURCE" may need to be defined to use gettid() */
#if HAVE_GETTID
#define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "config.h"
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include "debug.h"
@@ -93,15 +81,3 @@ const struct log_info log_info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
pid_t my_gettid(void)
{
#if HAVE_GETTID
return gettid();
#elif defined(LINUX) && defined(__NR_gettid)
return (pid_t) syscall(__NR_gettid);
#else
#pragma message ("use pid as tid")
return getpid();
#endif
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <stdbool.h>
#include <sys/types.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/thread.h>
extern const struct log_info log_info;
@@ -19,12 +19,10 @@ enum {
DCTR,
};
pid_t my_gettid(void);
#define CLOGC(category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld] " fmt, (long int) my_gettid(), ##args); \
LOGP(category, level, "[tid=%ld] " fmt, (long int) osmo_gettid(), ##args); \
} while(0)
#define CLOGCHAN(chan, category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld][chan=%zu] " fmt, (long int) my_gettid(), chan, ##args); \
LOGP(category, level, "[tid=%ld][chan=%zu] " fmt, (long int) osmo_gettid(), chan, ##args); \
} while(0)

View File

@@ -67,6 +67,15 @@ static const struct value_string filler_types[] = {
{ 0, NULL }
};
static const struct value_string filler_docs[] = {
{ FILLER_DUMMY, "Send a Dummy Burst on C0 (TRX0) and empty burst on other channels" },
{ FILLER_ZERO, "Send an empty burst (default)" },
{ FILLER_NORM_RAND, "Send a GMSK modulated Normal Burst with random bits (spectrum mask testing)" },
{ FILLER_EDGE_RAND, "Send an 8-PSK modulated Normal Burst with random bits (spectrum mask testing)" },
{ FILLER_ACCESS_RAND, "Send an Access Burst with random bits (Rx/Tx alignment testing)" },
{ 0, NULL }
};
struct trx_ctx *trx_from_vty(struct vty *v)
{
@@ -112,7 +121,7 @@ DEFUN(cfg_trx, cfg_trx_cmd,
}
DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
"bind-ip A.B.C.D",
"bind-ip " VTY_IPV4_CMD,
"Set the IP address for the local bind\n"
"IPv4 Address\n")
{
@@ -124,7 +133,7 @@ DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
}
DEFUN(cfg_remote_ip, cfg_remote_ip_cmd,
"remote-ip A.B.C.D",
"remote-ip " VTY_IPV4_CMD,
"Set the IP address for the remote BTS\n"
"IPv4 Address\n")
{
@@ -162,7 +171,9 @@ DEFUN(cfg_dev_args, cfg_dev_args_cmd,
DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
"tx-sps (1|4)",
"Set the Tx Samples-per-Symbol\n"
"Tx Samples-per-Symbol\n")
"Tx Samples-per-Symbol\n"
"1 Sample-per-Symbol\n"
"4 Samples-per-Symbol\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -174,7 +185,9 @@ DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
"rx-sps (1|4)",
"Set the Rx Samples-per-Symbol\n"
"Rx Samples-per-Symbol\n")
"Rx Samples-per-Symbol\n"
"1 Sample-per-Symbol\n"
"4 Samples-per-Symbol\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -199,7 +212,8 @@ DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd,
"multi-arfcn (disable|enable)",
"Enable multi-ARFCN transceiver (default=disable)\n")
"Multi-ARFCN transceiver mode (default=disable)\n"
"Enable multi-ARFCN mode\n" "Disable multi-ARFCN mode\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -230,21 +244,38 @@ DEFUN(cfg_offset, cfg_offset_cmd,
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_freq_offset, cfg_freq_offset_cmd,
"freq-offset FLOAT",
"Apply an artificial offset to Rx/Tx carrier frequency\n"
"Frequency offset in kHz (e.g. -145300)\n",
CMD_ATTR_HIDDEN)
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.freq_offset_khz = atof(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd,
"rssi-offset FLOAT",
"rssi-offset FLOAT [relative]",
"Set the RSSI to dBm offset in dB (default=0)\n"
"RSSI to dBm offset in dB\n")
"RSSI to dBm offset in dB\n"
"Add to the default rssi-offset value instead of completely replacing it\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rssi_offset = atof(argv[0]);
trx->cfg.force_rssi_offset = (argc == 1);
return CMD_SUCCESS;
}
DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
"swap-channels (disable|enable)",
"Swap channels (default=disable)\n")
"Swap primary and secondary channels of the PHY (if any)\n"
"Do not swap primary and secondary channels (default)\n"
"Swap primary and secondary channels\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -261,7 +292,9 @@ DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
DEFUN(cfg_egprs, cfg_egprs_cmd,
"egprs (disable|enable)",
"Enable EDGE receiver (default=disable)\n")
"EGPRS (8-PSK demodulation) support (default=disable)\n"
"Disable EGPRS (8-PSK demodulation) support\n"
"Enable EGPRS (8-PSK demodulation) support\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -278,7 +311,9 @@ DEFUN(cfg_egprs, cfg_egprs_cmd,
DEFUN(cfg_ext_rach, cfg_ext_rach_cmd,
"ext-rach (disable|enable)",
"Enable extended (11-bit) RACH (default=disable)\n")
"11-bit Access Burst correlation support (default=disable)\n"
"Disable 11-bit Access Burst (TS1 & TS2) correlation\n"
"Enable 11-bit Access Burst (TS1 & TS2) correlation\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
@@ -317,20 +352,11 @@ DEFUN(cfg_stack_size, cfg_stack_size_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_filler, cfg_filler_type_cmd,
"filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)",
#define CFG_FILLER_DOC_STR \
"Filler burst settings\n"
"Filler burst type (default=zero)\n"
"Send an empty burst when there is nothing to send (default)\n"
"Send a dummy burst when there is nothing to send on C0 (TRX0) and empty burst on other channels."
" Use for OpenBTS compatibility only, don't use with OsmoBTS as it breaks encryption.\n"
"Send a GMSK modulated Normal Burst with random bits when there is nothing to send."
" Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
"Send an 8-PSK modulated Normal Burst with random bits when there is nothing to send."
" Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
"Send an Access Burst with random bits when there is nothing to send. Use for Rx/Tx alignment."
" Configure 'filler access-burst-delay' to introduce artificial delay.\n"
)
DEFUN(cfg_filler, cfg_filler_type_cmd,
"AUTO-GENERATED", "AUTO-GENERATED")
{
struct trx_ctx *trx = trx_from_vty(vty);
// trx->cfg.filler is unsigned, so we need an interim int var to detect errors
@@ -347,7 +373,7 @@ DEFUN(cfg_filler, cfg_filler_type_cmd,
DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
"filler tsc <0-7>",
"Filler burst settings\n"
CFG_FILLER_DOC_STR
"Set the TSC for GMSK/8-PSK Normal Burst random fillers. Used only with 'random-nb-gmsk' and"
" 'random-nb-8psk' filler types. (default=0)\n"
"TSC\n")
@@ -361,7 +387,7 @@ DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
DEFUN(cfg_test_rach_delay, cfg_filler_rach_delay_cmd,
"filler access-burst-delay <0-68>",
"Filler burst settings\n"
CFG_FILLER_DOC_STR
"Set the delay for Access Burst random fillers. Used only with 'random-ab' filler type. (default=0)\n"
"RACH delay in symbols\n")
{
@@ -415,12 +441,13 @@ static int vty_intv_name_2_id(const char* str) {
INTV_STR_VAL(per-hour) \
INTV_STR_VAL(per-day)
DEFUN(cfg_ctr_error_threshold, cfg_ctr_error_threshold_cmd,
"ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
"Threshold rate for error counter\n"
THRESHOLD_STRS
"Value to set for threshold\n"
INTV_STRS)
DEFUN_ATTR(cfg_ctr_error_threshold, cfg_ctr_error_threshold_cmd,
"ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
"Threshold rate for error counter\n"
THRESHOLD_STRS
"Value to set for threshold\n"
INTV_STRS,
CMD_ATTR_IMMEDIATE)
{
int rc;
struct ctr_threshold ctr;
@@ -446,12 +473,13 @@ DEFUN(cfg_ctr_error_threshold, cfg_ctr_error_threshold_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_no_ctr_error_threshold, cfg_no_ctr_error_threshold_cmd,
"no ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
NO_STR "Threshold rate for error counter\n"
THRESHOLD_STRS
"Value to set for threshold\n"
INTV_STRS)
DEFUN_ATTR(cfg_no_ctr_error_threshold, cfg_no_ctr_error_threshold_cmd,
"no ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
NO_STR "Threshold rate for error counter\n"
THRESHOLD_STRS
"Value to set for threshold\n"
INTV_STRS,
CMD_ATTR_IMMEDIATE)
{
int rc;
struct ctr_threshold ctr;
@@ -520,6 +548,12 @@ DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd,
{
struct trx_chan *chan = vty->index;
if (chan->trx->cfg.multi_arfcn && chan->idx > 0) {
vty_out(vty, "%% Setting 'rx-path' for chan %u in multi-ARFCN mode "
"does not make sense, because only chan 0 is used%s",
chan->idx, VTY_NEWLINE);
}
osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]);
return CMD_SUCCESS;
@@ -532,6 +566,12 @@ DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd,
{
struct trx_chan *chan = vty->index;
if (chan->trx->cfg.multi_arfcn && chan->idx > 0) {
vty_out(vty, "%% Setting 'tx-path' for chan %u in multi-ARFCN mode "
"does not make sense, because only chan 0 is used%s",
chan->idx, VTY_NEWLINE);
}
osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]);
return CMD_SUCCESS;
@@ -566,8 +606,11 @@ static int config_write_trx(struct vty *vty)
vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE);
if (trx->cfg.offset != 0)
vty_out(vty, " offset %f%s", trx->cfg.offset, VTY_NEWLINE);
if (trx->cfg.rssi_offset != 0)
vty_out(vty, " rssi-offset %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
if (trx->cfg.freq_offset_khz != 0)
vty_out(vty, " freq-offset %f%s", trx->cfg.freq_offset_khz, VTY_NEWLINE);
if (!(trx->cfg.rssi_offset == 0 && !trx->cfg.force_rssi_offset))
vty_out(vty, " rssi-offset %f%s%s", trx->cfg.rssi_offset,
trx->cfg.force_rssi_offset ? " relative": "", VTY_NEWLINE);
vty_out(vty, " swap-channels %s%s", trx->cfg.swap_channels ? "enable" : "disable", VTY_NEWLINE);
vty_out(vty, " egprs %s%s", trx->cfg.egprs ? "enable" : "disable", VTY_NEWLINE);
vty_out(vty, " ext-rach %s%s", trx->cfg.ext_rach ? "enable" : "disable", VTY_NEWLINE);
@@ -702,12 +745,19 @@ struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx)
trx->cfg.tx_sps = DEFAULT_TX_SPS;
trx->cfg.rx_sps = DEFAULT_RX_SPS;
trx->cfg.filler = FILLER_ZERO;
trx->cfg.rssi_offset = 0.0f;
return trx;
}
int trx_vty_init(struct trx_ctx* trx)
{
cfg_filler_type_cmd.string = vty_cmd_string_from_valstr(trx, filler_types,
"filler type (", "|", ")", 0);
cfg_filler_type_cmd.doc = vty_cmd_string_from_valstr(trx, filler_docs,
CFG_FILLER_DOC_STR "What to do when there is nothing to send "
"(filler type, default=zero)\n", "\n", "", 0);
g_trx_ctx = trx;
install_element_ve(&show_trx_cmd);
@@ -723,6 +773,7 @@ int trx_vty_init(struct trx_ctx* trx)
install_element(TRX_NODE, &cfg_clock_ref_cmd);
install_element(TRX_NODE, &cfg_multi_arfcn_cmd);
install_element(TRX_NODE, &cfg_offset_cmd);
install_element(TRX_NODE, &cfg_freq_offset_cmd);
install_element(TRX_NODE, &cfg_rssi_offset_cmd);
install_element(TRX_NODE, &cfg_swap_channels_cmd);
install_element(TRX_NODE, &cfg_egprs_cmd);

View File

@@ -8,8 +8,6 @@ extern struct vty_app_info g_vty_info;
extern const struct value_string clock_ref_names[];
extern const struct value_string filler_names[];
/* Maximum number of physical RF channels */
#define TRX_CHAN_MAX 8
/* Maximum number of carriers in multi-ARFCN mode */
#define TRX_MCHAN_MAX 3
@@ -35,38 +33,8 @@ extern const struct value_string filler_names[];
#define DEFAULT_TRX_IP "127.0.0.1"
#define DEFAULT_CHANS 1
struct trx_ctx;
struct trx_chan {
struct trx_ctx *trx; /* backpointer */
unsigned int idx; /* channel index */
char *rx_path;
char *tx_path;
};
struct trx_ctx {
struct {
char *bind_addr;
char *remote_addr;
char *dev_args;
unsigned int base_port;
unsigned int tx_sps;
unsigned int rx_sps;
unsigned int rtsc;
unsigned int rach_delay;
enum ReferenceType clock_ref;
enum FillerType filler;
bool multi_arfcn;
double offset;
double rssi_offset;
bool swap_channels;
bool ext_rach;
bool egprs;
unsigned int sched_rr;
unsigned int stack_size;
unsigned int num_chans;
struct trx_chan chans[TRX_CHAN_MAX];
} cfg;
struct trx_cfg cfg;
};
int trx_vty_init(struct trx_ctx* trx);

View File

@@ -28,13 +28,14 @@ AM_CXXFLAGS = -Wall -pthread
# Order must be preserved
SUBDIRS = \
doc \
CommonLibs \
GSM \
Transceiver52M \
contrib \
tests \
utils
utils \
doc \
$(NULL)
EXTRA_DIST = \
LEGAL \

View File

@@ -1,5 +1,5 @@
About OsmTRX
============
About OsmoTRX
=============
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:
@@ -9,14 +9,12 @@ physical layer of a BTS comprising the following 3GPP specifications:
* TS 05.04 "Modulation"
* TS 05.10 "Radio subsystem synchronization"
OsmoTRX is based on the transceiver code from the
OsmoTRX is originally based on the transceiver code from the
[OpenBTS](https://osmocom.org/projects/osmobts/wiki/OpenBTS) project, but setup
to operate independently with the purpose of using with non-OpenBTS software and
projects, while still maintaining backwards compatibility with OpenBTS when
possible. Currently there are numerous features contained in OsmoTRX that extend
the functionality of the OpenBTS transceiver. These features include enhanced
support for various embedded platforms - notably ARM - and dual channel
diversity support for the Fairwaves umtrx.
projects, specifically within the Osmocom stack. Used together with
[OsmoBTS](https://osmocom.org/projects/osmobts/wiki) you can get a pretty
standard GSM BTS with Abis interface as per the relevant 3GPP specifications.
Homepage
--------
@@ -31,7 +29,7 @@ You can clone from the official osmo-trx.git repository using
git clone git://git.osmocom.org/osmo-trx.git
There is a cgit interface at <http://git.osmocom.org/osmo-trx/>
There is a cgit interface at <https://git.osmocom.org/osmo-trx/>
Documentation
-------------
@@ -39,7 +37,7 @@ Documentation
Doxygen-generated API documentation is generated during the build process, but
also available online for each of the sub-libraries at User Manual for OsmoTRX
can be generated during the build process, and is also available online at
<http://ftp.osmocom.org/docs/latest/osmotrx-usermanual.pdf>.
<https://ftp.osmocom.org/docs/latest/osmotrx-usermanual.pdf>.
Mailing List
------------

View File

@@ -1,2 +0,0 @@
* update libosmocore dependency to > 1.3.x for osmo_sched_vty_init(), osmo_sched_vty_apply_localthread()
* update osmo-gsm-manuals dependency to > 0.3.0 for vty_cpu_sched.adoc include.

View File

@@ -244,6 +244,7 @@ ChannelizerBase::~ChannelizerBase()
free(subFilters[i]);
delete[] hist[i];
}
free(subFilters);
fft_free(fftInput);
fft_free(fftOutput);

View File

@@ -105,9 +105,12 @@ osmo_trx_lms_LDADD = \
osmo_trx_lms_CPPFLAGS = $(AM_CPPFLAGS) $(LMS_CFLAGS)
endif
if DEVICE_IPC
bin_PROGRAMS += osmo-trx-ipc
osmo_trx_ipc_SOURCES = osmo-trx.cpp
osmo_trx_ipc_LDADD = \
$(builddir)/device/ipc/libdevice.la \
$(COMMON_LDADD)
osmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS)
endif

View File

@@ -99,6 +99,7 @@ void Resampler::initFilters(float bw)
reverse(&part[0], &part[filt_len]);
}
#ifndef __OPTIMIZE__
static bool check_vec_len(int in_len, int out_len, int p, int q)
{
if (in_len % q) {
@@ -129,14 +130,15 @@ static bool check_vec_len(int in_len, int out_len, int p, int q)
return true;
}
#endif
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
{
int n, path;
#ifndef __OPTIMIZE__
if (!check_vec_len(in_len, out_len, p, q))
return -1;
#endif
/* Generate output from precomputed input/output paths */
for (size_t i = 0; i < out_len; i++) {
n = in_index[i];

View File

@@ -62,7 +62,8 @@ static void dispatch_trx_rate_ctr_change(TransceiverState *state, unsigned int c
}
TransceiverState::TransceiverState()
: mFiller(FILLER_ZERO), mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
: mFiller(FILLER_ZERO), mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT),
mPower(0.0), mMuted(false), first_dl_fn_rcv()
{
for (int i = 0; i < 8; i++) {
chanType[i] = Transceiver::NONE;
@@ -131,26 +132,21 @@ bool TransceiverState::init(FillerType filler, size_t sps, float scale, size_t r
return false;
}
Transceiver::Transceiver(int wBasePort,
const char *TRXAddress,
const char *GSMcoreAddress,
size_t tx_sps, size_t rx_sps, size_t chans,
Transceiver::Transceiver(const struct trx_cfg *cfg,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset, int wStackSize)
: mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
mClockSocket(-1), mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
rssiOffset(wRssiOffset), stackSize(wStackSize),
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mExtRACH(false), mEdge(false),
mOn(false), mForceClockInterface(false),
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
mWriteBurstToDiskMask(0)
RadioInterface *wRadioInterface)
: cfg(cfg), mClockSocket(-1),
mRxLowerLoopThread(nullptr), mTxLowerLoopThread(nullptr),
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
mChans(cfg->num_chans), mOn(false), mForceClockInterface(false),
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0),
mMaxExpectedDelayNB(0), mWriteBurstToDiskMask(0)
{
txFullScale = mRadioInterface->fullScaleInputValue();
rxFullScale = mRadioInterface->fullScaleOutputValue();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++)
for (size_t i = 0; i < ARRAY_SIZE(mHandover); i++) {
for (size_t j = 0; j < ARRAY_SIZE(mHandover[i]); j++)
mHandover[i][j] = false;
}
}
@@ -198,11 +194,9 @@ int Transceiver::ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags)
* are still expected to report clock indications through control channel
* activity.
*/
bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
bool edge, bool ext_rach)
bool Transceiver::init()
{
int d_srcport, d_dstport, c_srcport, c_dstport;
if (!mChans) {
LOG(FATAL) << "No channels assigned";
return false;
@@ -213,9 +207,6 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
return false;
}
mExtRACH = ext_rach;
mEdge = edge;
mDataSockets.resize(mChans, -1);
mCtrlSockets.resize(mChans);
mTxPriorityQueueServiceLoopThreads.resize(mChans);
@@ -227,27 +218,28 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
mVersionTRXD.resize(mChans);
/* Filler table retransmissions - support only on channel 0 */
if (filler == FILLER_DUMMY)
if (cfg->filler == FILLER_DUMMY)
mStates[0].mRetrans = true;
/* Setup sockets */
mClockSocket = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
mLocalAddr.c_str(), mBasePort,
mRemoteAddr.c_str(), mBasePort + 100,
cfg->bind_addr, cfg->base_port,
cfg->remote_addr, cfg->base_port + 100,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (mClockSocket < 0)
return false;
for (size_t i = 0; i < mChans; i++) {
int rv;
c_srcport = mBasePort + 2 * i + 1;
c_dstport = mBasePort + 2 * i + 101;
d_srcport = mBasePort + 2 * i + 2;
d_dstport = mBasePort + 2 * i + 102;
FillerType filler = cfg->filler;
c_srcport = cfg->base_port + 2 * i + 1;
c_dstport = cfg->base_port + 2 * i + 101;
d_srcport = cfg->base_port + 2 * i + 2;
d_dstport = cfg->base_port + 2 * i + 102;
rv = osmo_sock_init2_ofd(&mCtrlSockets[i].conn_bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
mLocalAddr.c_str(), c_srcport,
mRemoteAddr.c_str(), c_dstport,
cfg->bind_addr, c_srcport,
cfg->remote_addr, c_dstport,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rv < 0)
return false;
@@ -257,8 +249,8 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
mDataSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
mLocalAddr.c_str(), d_srcport,
mRemoteAddr.c_str(), d_dstport,
cfg->bind_addr, d_srcport,
cfg->remote_addr, d_dstport,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (mDataSockets[i] < 0)
return false;
@@ -266,7 +258,7 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
if (i && filler == FILLER_DUMMY)
filler = FILLER_ZERO;
mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
mStates[i].init(filler, cfg->tx_sps, txFullScale, cfg->rtsc, cfg->rach_delay);
}
/* Randomize the central clock */
@@ -308,8 +300,8 @@ bool Transceiver::start()
}
/* Device is running - launch I/O threads */
mRxLowerLoopThread = new Thread(stackSize);
mTxLowerLoopThread = new Thread(stackSize);
mRxLowerLoopThread = new Thread(cfg->stack_size);
mTxLowerLoopThread = new Thread(cfg->stack_size);
mTxLowerLoopThread->start((void * (*)(void*))
TxLowerLoopAdapter,(void*) this);
mRxLowerLoopThread->start((void * (*)(void*))
@@ -320,14 +312,14 @@ bool Transceiver::start()
TrxChanThParams *params = (TrxChanThParams *)malloc(sizeof(struct TrxChanThParams));
params->trx = this;
params->num = i;
mRxServiceLoopThreads[i] = new Thread(stackSize);
mRxServiceLoopThreads[i] = new Thread(cfg->stack_size);
mRxServiceLoopThreads[i]->start((void * (*)(void*))
RxUpperLoopAdapter, (void*) params);
params = (TrxChanThParams *)malloc(sizeof(struct TrxChanThParams));
params->trx = this;
params->num = i;
mTxPriorityQueueServiceLoopThreads[i] = new Thread(stackSize);
mTxPriorityQueueServiceLoopThreads[i] = new Thread(cfg->stack_size);
mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
TxUpperLoopAdapter, (void*) params);
}
@@ -400,11 +392,11 @@ void Transceiver::addRadioVector(size_t chan, BitVector &bits,
/* Use the number of bits as the EDGE burst indicator */
if (bits.size() == EDGE_BURST_NBITS)
burst = modulateEdgeBurst(bits, mSPSTx);
burst = modulateEdgeBurst(bits, cfg->tx_sps);
else
burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), cfg->tx_sps);
scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
scaleVector(*burst, txFullScale * pow(10, (double) -RSSI / 20));
radio_burst = new radioVector(wTime, burst);
@@ -440,7 +432,7 @@ void Transceiver::pushRadioVector(GSM::Time &nowTime)
state = &mStates[i];
ratectr_changed = false;
zeros[i] = state->chanType[TN] == NONE;
zeros[i] = state->chanType[TN] == NONE || state->mMuted;
Mutex *mtx = mTxPriorityQueues[i].getMutex();
mtx->lock();
@@ -565,16 +557,16 @@ CorrType Transceiver::expectedCorrType(GSM::Time currTime,
break;
case IV:
case VI:
return mExtRACH ? EXT_RACH : RACH;
return cfg->ext_rach ? EXT_RACH : RACH;
break;
case V: {
int mod51 = burstFN % 51;
if ((mod51 <= 36) && (mod51 >= 14))
return mExtRACH ? EXT_RACH : RACH;
return cfg->ext_rach ? EXT_RACH : RACH;
else if ((mod51 == 4) || (mod51 == 5))
return mExtRACH ? EXT_RACH : RACH;
return cfg->ext_rach ? EXT_RACH : RACH;
else if ((mod51 == 45) || (mod51 == 46))
return mExtRACH ? EXT_RACH : RACH;
return cfg->ext_rach ? EXT_RACH : RACH;
else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
return RACH;
else
@@ -592,11 +584,11 @@ CorrType Transceiver::expectedCorrType(GSM::Time currTime,
case XIII: {
int mod52 = burstFN % 52;
if ((mod52 == 12) || (mod52 == 38))
return mExtRACH ? EXT_RACH : RACH;
return cfg->ext_rach ? EXT_RACH : RACH;
else if ((mod52 == 25) || (mod52 == 51))
return IDLE;
else /* Enable 8-PSK burst detection if EDGE is enabled */
return mEdge ? EDGE : TSC;
return cfg->egprs ? EDGE : TSC;
break;
}
case LOOPBACK:
@@ -621,6 +613,13 @@ void writeToFile(radioVector *radio_burst, size_t chan)
outfile.close();
}
double Transceiver::rssiOffset(size_t chan)
{
if (cfg->force_rssi_offset)
return cfg->rssi_offset;
return mRadioInterface->rssiOffset(chan) + cfg->rssi_offset;
}
/*
* Pull bursts from the FIFO and handle according to the slot
* and burst correlation type. Equalzation is currently disabled.
@@ -640,6 +639,7 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
SoftVector *rxBurst;
TransceiverState *state = &mStates[chan];
bool ctr_changed = false;
double rssi_offset;
/* Blocking FIFO read */
radioVector *radio_burst = mReceiveFIFO[chan]->read();
@@ -678,9 +678,13 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
return -ENOENT;
}
/* If TRX RF is locked/muted by BTS, send idle burst indications */
if (state->mMuted)
goto ret_idle;
/* Select the diversity channel with highest energy */
for (size_t i = 0; i < radio_burst->chans(); i++) {
float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
float pow = energyDetect(*radio_burst->getVector(i), 20 * cfg->rx_sps);
if (pow > max) {
max = pow;
max_i = i;
@@ -705,8 +709,9 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
state->mNoiseLev = state->mNoises.avg();
}
bi->rssi = 20.0 * log10(rxFullScale / avg) + rssiOffset;
bi->noise = 20.0 * log10(rxFullScale / state->mNoiseLev) + rssiOffset;
rssi_offset = rssiOffset(chan);
bi->rssi = 20.0 * log10(rxFullScale / avg) + rssi_offset;
bi->noise = 20.0 * log10(rxFullScale / state->mNoiseLev) + rssi_offset;
if (type == IDLE)
goto ret_idle;
@@ -715,7 +720,7 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
mMaxExpectedDelayAB : mMaxExpectedDelayNB;
/* Detect normal or RACH bursts */
rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, max_toa, &ebp);
rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, cfg->rx_sps, type, max_toa, &ebp);
if (rc <= 0) {
if (rc == -SIGERR_CLIP) {
LOGCHAN(chan, DTRXDUL, INFO) << "Clipping detected on received RACH or Normal Burst";
@@ -729,11 +734,10 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
goto ret_idle;
}
type = (CorrType) rc;
rxBurst = demodAnyBurst(*burst, (CorrType) rc, cfg->rx_sps, &ebp);
bi->toa = ebp.toa;
bi->tsc = ebp.tsc;
bi->ci = ebp.ci;
rxBurst = demodAnyBurst(*burst, mSPSRx, ebp.amp, ebp.toa, type);
/* EDGE demodulator returns 444 (gSlotLen * 3) bits */
if (rxBurst->size() == EDGE_BURST_NBITS) {
@@ -801,7 +805,7 @@ void Transceiver::ctrl_sock_send(ctrl_msg& m, int chan)
struct osmo_fd *conn_bfd = &s.conn_bfd;
s.txmsgqueue.push_back(m);
conn_bfd->when |= OSMO_FD_WRITE;
osmo_fd_write_enable(conn_bfd);
}
int Transceiver::ctrl_sock_write(int chan)
@@ -816,7 +820,7 @@ int Transceiver::ctrl_sock_write(int chan)
while (s.txmsgqueue.size()) {
const ctrl_msg m = s.txmsgqueue.front();
s.conn_bfd.when &= ~OSMO_FD_WRITE;
osmo_fd_write_disable(&s.conn_bfd);
/* try to send it over the socket */
rc = write(s.conn_bfd.fd, m.data, strlen(m.data) + 1);
@@ -824,7 +828,7 @@ int Transceiver::ctrl_sock_write(int chan)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
s.conn_bfd.when |= OSMO_FD_WRITE;
osmo_fd_write_enable(&s.conn_bfd);
break;
}
goto close;
@@ -950,7 +954,7 @@ int Transceiver::ctrl_sock_handle_rx(int chan)
// tune receiver
int freqKhz;
sscanf(params, "%d", &freqKhz);
mRxFreq = freqKhz * 1e3;
mRxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
LOGCHAN(chan, DTRXCTRL, FATAL) << "RX failed to tune";
sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
@@ -961,7 +965,7 @@ int Transceiver::ctrl_sock_handle_rx(int chan)
// tune txmtr
int freqKhz;
sscanf(params, "%d", &freqKhz);
mTxFreq = freqKhz * 1e3;
mTxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
LOGCHAN(chan, DTRXCTRL, FATAL) << "TX failed to tune";
sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
@@ -1006,6 +1010,12 @@ int Transceiver::ctrl_sock_handle_rx(int chan)
mVersionTRXD[chan] = version_recv;
sprintf(response, "RSP SETFORMAT %u %u", version_recv, version_recv);
}
} else if (match_cmd(command, "RFMUTE", &params)) {
// (Un)mute RF TX and RX
unsigned mute;
sscanf(params, "%u", &mute);
mStates[chan].mMuted = mute ? true : false;
sprintf(response, "RSP RFMUTE 0 %u", mute);
} else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
// debug command! may change or disappear without notice
// set a mask which bursts to dump to disk
@@ -1044,8 +1054,8 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
burstLen = gSlotLen;
break;
case sizeof(*dl) + EDGE_BURST_NBITS: /* EDGE burst */
if (mSPSTx != 4) {
LOGCHAN(chan, DTRXDDL, ERROR) << "EDGE burst received but SPS is set to " << mSPSTx;
if (cfg->tx_sps != 4) {
LOGCHAN(chan, DTRXDDL, ERROR) << "EDGE burst received but SPS is set to " << cfg->tx_sps;
return false;
}
burstLen = EDGE_BURST_NBITS;
@@ -1152,11 +1162,13 @@ void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
else os << "-";
}
double rssi_offset = rssiOffset(chan);
LOGCHAN(chan, DTRXDUL, DEBUG) << std::fixed << std::right
<< " time: " << unsigned(bi->tn) << ":" << bi->fn
<< " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi - rssiOffset)
<< " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi - rssi_offset)
<< "dBFS/" << std::setw(6) << -bi->rssi << "dBm"
<< " noise: " << std::setw(5) << std::setprecision(1) << (bi->noise - rssiOffset)
<< " noise: " << std::setw(5) << std::setprecision(1) << (bi->noise - rssi_offset)
<< "dBFS/" << std::setw(6) << -bi->noise << "dBm"
<< " TOA: " << std::setw(5) << std::setprecision(2) << bi->toa
<< " C/I: " << std::setw(5) << std::setprecision(2) << bi->ci << "dB"

View File

@@ -85,6 +85,9 @@ struct TransceiverState {
/* Shadowed downlink attenuation */
int mPower;
/* RF emission and reception disabled, as per NM Administrative State Locked */
bool mMuted;
/* counters */
struct trx_counters ctrs;
@@ -97,27 +100,19 @@ struct TransceiverState {
class Transceiver {
public:
/** Transceiver constructor
@param wBasePort base port number of UDP sockets
@param TRXAddress IP address of the TRX, as a string
@param GSMcoreAddress IP address of the GSM core, as a string
@param wSPS number of samples per GSM symbol
@param cfg VTY populated config
@param wTransmitLatency initial setting of transmit latency
@param radioInterface associated radioInterface object
*/
Transceiver(int wBasePort,
const char *TRXAddress,
const char *GSMcoreAddress,
size_t tx_sps, size_t rx_sps, size_t chans,
Transceiver(const struct trx_cfg *cfg,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset, int stackSize);
RadioInterface *wRadioInterface);
/** Destructor */
~Transceiver();
/** Start the control loop */
bool init(FillerType filler, size_t rtsc, unsigned rach_delay,
bool edge, bool ext_rach);
bool init(void);
/** attach the radioInterface receive FIFO */
bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
@@ -130,7 +125,7 @@ public:
}
/** accessor for number of channels */
size_t numChans() const { return mChans; };
size_t numChans() const { return cfg->num_chans; };
/** Codes for channel combinations */
typedef enum {
@@ -153,7 +148,6 @@ public:
} ChannelCombination;
private:
struct ctrl_msg {
char data[101];
ctrl_msg() {};
@@ -174,10 +168,7 @@ struct ctrl_sock_state {
}
};
int mBasePort;
std::string mLocalAddr;
std::string mRemoteAddr;
const struct trx_cfg *cfg; ///< VTY populated config
std::vector<int> mDataSockets; ///< socket for writing to/reading from GSM core
std::vector<ctrl_sock_state> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
int mClockSocket; ///< socket for writing clock updates to GSM core
@@ -199,9 +190,6 @@ struct ctrl_sock_state {
double txFullScale; ///< full scale input to radio
double rxFullScale; ///< full scale output to radio
double rssiOffset; ///< RSSI to dBm conversion offset
int stackSize; ///< stack size for threads, 0 = OS default
/** modulate and add a burst to the transmit queue */
void addRadioVector(size_t chan, BitVector &bits,
int RSSI, GSM::Time &wTime);
@@ -230,12 +218,7 @@ struct ctrl_sock_state {
/** drive handling of control messages from GSM core */
int ctrl_sock_handle_rx(int chan);
int mSPSTx; ///< number of samples per Tx symbol
int mSPSRx; ///< number of samples per Rx symbol
size_t mChans;
bool mExtRACH;
bool mEdge;
bool mOn; ///< flag to indicate that transceiver is powered on
bool mForceClockInterface; ///< flag to indicate whether IND CLOCK shall be sent unconditionally after transceiver is started
bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
@@ -277,7 +260,7 @@ protected:
friend void *RxLowerLoopAdapter(Transceiver *transceiver);
friend void *TxLowerLoopAdapter(Transceiver *transceiver);
double rssiOffset(size_t chan);
void reset();
void logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi);

View File

@@ -99,9 +99,10 @@ int convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len, int start, int len)
{
#ifndef __OPTIMIZE__
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
#endif
memset(y, 0, len * 2 * sizeof(float));
switch (h_len) {
@@ -138,9 +139,10 @@ int convolve_complex(const float *x, int x_len,
float *y, int y_len,
int start, int len)
{
#ifndef __OPTIMIZE__
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
#endif
memset(y, 0, len * 2 * sizeof(float));
if (!(h_len % 8))

View File

@@ -2,9 +2,9 @@ include $(top_srcdir)/Makefile.common
SUBDIRS = common
#if DEVICE_IPC
if DEVICE_IPC
SUBDIRS += ipc
#endif
endif
if DEVICE_USRP1
SUBDIRS += usrp1

View File

@@ -1,7 +1,7 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LMS_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
noinst_HEADERS = radioDevice.h smpl_buf.h

View File

@@ -125,6 +125,9 @@ class RadioDevice {
/** return minimum Rx Gain **/
virtual double minRxGain(void) = 0;
/** return base RSSI offset to apply for received samples **/
virtual double rssiOffset(size_t chan) = 0;
/** returns the Nominal transmit output power of the transceiver in dBm, negative on error **/
virtual int getNominalTxPower(size_t chan = 0) = 0;
@@ -186,6 +189,13 @@ class RadioDevice {
for (i = 0; i < tx_paths.size(); i++) {
if (tx_paths[i] == "")
continue;
if (iface == MULTI_ARFCN && i > 0) {
LOGCHAN(i, DDEV, NOTICE) << "Not setting Tx antenna "
<< tx_paths[i]
<< " for a logical channel";
continue;
}
LOGCHAN(i, DDEV, DEBUG) << "Configuring Tx antenna " << tx_paths[i];
if (!setTxAntenna(tx_paths[i], i)) {
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Tx antenna " << tx_paths[i];
@@ -196,6 +206,13 @@ class RadioDevice {
for (i = 0; i < rx_paths.size(); i++) {
if (rx_paths[i] == "")
continue;
if (iface == MULTI_ARFCN && i > 0) {
LOGCHAN(i, DDEV, NOTICE) << "Not setting Rx antenna "
<< rx_paths[i]
<< " for a logical channel";
continue;
}
LOGCHAN(i, DDEV, DEBUG) << "Configuring Rx antenna " << rx_paths[i];
if (!setRxAntenna(rx_paths[i], i)) {
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Rx antenna " << rx_paths[i];

View File

@@ -4,32 +4,33 @@
*
* SPDX-License-Identifier: AGPL-3.0+
*
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/>.
* 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/>.
* See the COPYING file in the main directory for details.
*/
#include <cstdint>
#include <cstring>
#include <cstdlib>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <map>
#include "trx_vty.h"
#include "Logger.h"
#include "Threads.h"
#include "Utils.h"
#include "IPCDevice.h"
#include "smpl_buf.h"
extern "C" {
#include <sys/mman.h>
@@ -37,7 +38,6 @@ extern "C" {
#include <fcntl.h> /* For O_* constants */
#include "osmo_signal.h"
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
@@ -46,11 +46,9 @@ extern "C" {
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
}
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ipc_shm.h"
}
#define SAMPLE_BUF_SZ (1 << 20)
@@ -60,29 +58,25 @@ static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags);
IPCDevice::IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)
: RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths),
tx_attenuation(), tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), shm_dec(0), started(false)
: RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths), tx_attenuation(),
tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), shm_dec(0), started(false)
{
LOGC(DDEV, INFO) << "creating IPC device...";
//m_IPC_stream_rx.resize(chans);
//m_IPC_stream_tx.resize(chans);
rx_gains.resize(chans);
tx_gains.resize(chans);
rx_buffers.resize(chans);
sk_chan_state.resize(chans, ipc_per_trx_sock_state());
/* Set up per-channel Rx timestamp based Ring buffers */
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
memset(&sk_chan_state, 0, sizeof(sk_chan_state));
memset(&trx_is_started, 0, sizeof(trx_is_started));
}
IPCDevice::~IPCDevice()
{
//unsigned int i;
LOGC(DDEV, INFO) << "Closing IPC device";
/* disable all channels */
@@ -91,7 +85,7 @@ IPCDevice::~IPCDevice()
ipc_sock_close(&master_sk_state);
for (unsigned int i = 0; i < ARRAY_SIZE(sk_chan_state); i++)
for (unsigned int i = 0; i < sk_chan_state.size(); i++)
ipc_sock_close(&sk_chan_state[i]);
for (auto i : shm_io_rx_streams)
@@ -99,7 +93,7 @@ IPCDevice::~IPCDevice()
for (auto i : shm_io_tx_streams)
ipc_shm_close(i);
if(shm_dec)
if (shm_dec)
talloc_free(shm_dec);
}
@@ -133,7 +127,7 @@ int IPCDevice::ipc_shm_connect(const char *shm_name)
goto err_mmap;
}
LOGP(DDEV, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
// LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
// LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
/* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
close(fd);
return 0;
@@ -144,7 +138,7 @@ err_shm_open:
return rc;
}
static int ipc_sock_send(struct ipc_sock_state *state, struct msgb *msg);
static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg);
static struct msgb *ipc_msgb_alloc(uint8_t msg_type)
{
@@ -161,7 +155,7 @@ static struct msgb *ipc_msgb_alloc(uint8_t msg_type)
return msg;
}
static int ipc_tx_greeting_req(struct ipc_sock_state *state, uint8_t req_version)
static int ipc_tx_greeting_req(struct ipc_per_trx_sock_state *state, uint8_t req_version)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
@@ -179,7 +173,7 @@ static int ipc_tx_greeting_req(struct ipc_sock_state *state, uint8_t req_version
return ipc_sock_send(state, msg);
}
static int ipc_tx_info_req(struct ipc_sock_state *state)
static int ipc_tx_info_req(struct ipc_per_trx_sock_state *state)
{
struct msgb *msg;
//struct ipc_sk_if *ipc_prim;
@@ -195,7 +189,7 @@ static int ipc_tx_info_req(struct ipc_sock_state *state)
return ipc_sock_send(state, msg);
}
int IPCDevice::ipc_tx_open_req(struct ipc_sock_state *state, uint32_t num_chans, uint32_t ref)
int IPCDevice::ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
@@ -275,17 +269,20 @@ int IPCDevice::ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf)
* cache rx/tx paths per channel, and make sure it matches the one the user wants to set
*/
LOGC(DDEV, NOTICE) << "Rx Info CNF:"
<< " name=" << info_cnf->dev_desc << std::endl
<< " max_num_chans=" << info_cnf->max_num_chans << " feature_mask=" << info_cnf->feature_mask;
LOGC(DDEV, NOTICE)
<< "Rx Info CNF:"
<< " name=" << info_cnf->dev_desc << std::endl
<< " max_num_chans=" << info_cnf->max_num_chans << " feature_mask=" << info_cnf->feature_mask;
for (i = 0; i < info_cnf->max_num_chans; i++) {
int j = 0;
bool rx_found = false, tx_found = false;
while (strcmp(info_cnf->chan_info[i].rx_path[j], "") != 0) {
LOGC(DDEV, NOTICE)
<< "chan " << i << ": RxPath[" << j << "]: " << info_cnf->chan_info[i].rx_path[j]
<< " min_rx_gain=" << info_cnf->chan_info[i].min_rx_gain << " max_rx_gain=" << info_cnf->chan_info[i].max_rx_gain
<< " min_tx_gain=" << info_cnf->chan_info[i].min_tx_gain << " max_tx_gain=" << info_cnf->chan_info[i].max_tx_gain;
<< " min_rx_gain=" << info_cnf->chan_info[i].min_rx_gain
<< " max_rx_gain=" << info_cnf->chan_info[i].max_rx_gain
<< " min_tx_gain=" << info_cnf->chan_info[i].min_tx_gain
<< " max_tx_gain=" << info_cnf->chan_info[i].max_tx_gain;
if (rx_paths.size() < (i + 1) ||
strcmp(rx_paths[i].c_str(), info_cnf->chan_info[i].rx_path[j]) == 0) {
@@ -335,8 +332,7 @@ int IPCDevice::ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf)
/* FIXME: current limit IPC_MAX_NUM_TRX chans, make dynamic */
if (i < IPC_MAX_NUM_TRX) {
struct ipc_sock_state *state = &sk_chan_state[i];
memset(state, 0x00, sizeof(*state));
struct ipc_per_trx_sock_state *state = &sk_chan_state[i];
INIT_LLIST_HEAD(&state->upqueue);
rc = osmo_sock_unix_init_ofd(&state->conn_bfd, SOCK_SEQPACKET, 0,
@@ -373,7 +369,8 @@ int IPCDevice::ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf)
<< "shm: chan" << i << "/ul: buffer_size=" << shm_dec->channels[i]->ul_stream->buffer_size;
shm_io_rx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->ul_stream));
shm_io_tx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->dl_stream));
// shm_io_tx_streams.push_back(ipc_shm_init_producer(shm_dec->channels[i]->dl_stream));
// we should init a producer here, but delegating all producers and therefore lock management
// to the other side is the reasonable approach to circumvent shutdown issues
}
tmp_state = IPC_IF_MSG_OPEN_CNF;
@@ -404,27 +401,23 @@ int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
int IPCDevice::ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal start response for chan #" << chan_nr << " ?!?";
return 0;
}
trx_is_started[chan_nr] = true;
return 0;
}
int IPCDevice::ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal stop response for chan #" << chan_nr << " ?!?";
return 0;
}
trx_is_started[chan_nr] = false;
return 0;
}
int IPCDevice::ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal setgain response for chan #" << chan_nr << " ?!?";
return 0;
}
@@ -434,17 +427,17 @@ int IPCDevice::ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr
}
int IPCDevice::ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal tx attn response for chan #" << chan_nr << " ?!?";
return 0;
}
// trx_is_started[chan_nr] = false;
tx_attenuation[chan_nr] = ret->attenuation;
return 0;
}
int IPCDevice::ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal setfreq response for chan #" << chan_nr << " ?!?";
return 0;
}
@@ -453,7 +446,7 @@ int IPCDevice::ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t cha
}
int IPCDevice::ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal underfloww notification for chan #" << chan_nr << " ?!?";
return 0;
}
@@ -465,7 +458,7 @@ int IPCDevice::ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t
}
int IPCDevice::ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
{
if(chan_nr >= ARRAY_SIZE(trx_is_started)) {
if (chan_nr >= chans) {
LOGC(DDEV, NOTICE) << "shm: illegal overflow notification for chan #" << chan_nr << " ?!?";
return 0;
}
@@ -509,10 +502,9 @@ int IPCDevice::ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, ui
return rc;
}
static int ipc_sock_send(struct ipc_sock_state *state, struct msgb *msg)
static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg)
{
struct osmo_fd *conn_bfd;
//struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;
if (!state) {
LOGP(DMAIN, LOGL_INFO,
@@ -530,12 +522,12 @@ static int ipc_sock_send(struct ipc_sock_state *state, struct msgb *msg)
return -EIO;
}
msgb_enqueue(&state->upqueue, msg);
conn_bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(conn_bfd);
return 0;
}
void IPCDevice::ipc_sock_close(struct ipc_sock_state *state)
void IPCDevice::ipc_sock_close(struct ipc_per_trx_sock_state *state)
{
if (state == 0)
return;
@@ -638,6 +630,9 @@ int IPCDevice::ipc_chan_sock_read(struct osmo_fd *bfd)
return 0;
}
/* store mask of last received messages so we can check later */
sk_chan_state[bfd->priv_nr].messages_processed_mask |= (1 << (ipc_prim->msg_type - IPC_IF_CHAN_MSG_OFFSET));
rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);
/* as we always synchronously process the message in IPC_rx() and
@@ -664,7 +659,7 @@ int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)
msg = llist_entry(master_sk_state.upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
osmo_fd_write_disable(bfd);
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
@@ -681,7 +676,7 @@ int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(bfd);
break;
}
goto close;
@@ -711,7 +706,7 @@ int IPCDevice::ipc_chan_sock_write(struct osmo_fd *bfd)
/* peek at the beginning of the queue */
msg = llist_entry(sk_chan_state[bfd->priv_nr].upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
osmo_fd_write_disable(bfd);
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
LOGP(DDEV, LOGL_ERROR,
@@ -727,14 +722,14 @@ int IPCDevice::ipc_chan_sock_write(struct osmo_fd *bfd)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(bfd);
break;
}
goto close;
}
dontsend:
/* _after_ we send it, we can deueue */
/* _after_ we send it, we can dequeue */
msg2 = msgb_dequeue(&sk_chan_state[bfd->priv_nr].upqueue);
assert(msg == msg2);
msgb_free(msg);
@@ -751,12 +746,12 @@ static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
int rc = 0;
if (flags & BSC_FD_READ)
if (flags & OSMO_FD_READ)
rc = device->ipc_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
if (flags & OSMO_FD_WRITE)
rc = device->ipc_sock_write(bfd);
return rc;
@@ -767,12 +762,12 @@ static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
int rc = 0;
if (flags & BSC_FD_READ)
if (flags & OSMO_FD_READ)
rc = device->ipc_chan_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
if (flags & OSMO_FD_WRITE)
rc = device->ipc_chan_sock_write(bfd);
return rc;
@@ -780,7 +775,7 @@ static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
{
std::string k,v;
std::string k, v;
std::string::size_type keyend;
int rc;
@@ -788,18 +783,17 @@ int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
k = args.substr(0, keyend++);
v = args.substr(keyend);
}
if(k != "ipc_msock" || !v.length()) {
LOGC(DDEV, ERROR) << "Invalid device args provided, expected \"dev-args ipc_msock=/path/to/socket\"\n";
return -1;
if (k != "ipc_msock" || !v.length()) {
LOGC(DDEV, ERROR) << "Invalid device args provided, expected \"dev-args ipc_msock=/path/to/socket\"\n";
return -1;
}
LOGC(DDEV, INFO) << "Opening IPC device" << v << "..";
memset(&master_sk_state, 0x00, sizeof(master_sk_state));
INIT_LLIST_HEAD(&master_sk_state.upqueue);
rc = osmo_sock_unix_init_ofd(&master_sk_state.conn_bfd, SOCK_SEQPACKET, 0, v.c_str(), OSMO_SOCK_F_CONNECT);
if (rc < 0) {
LOGC(DDEV, ERROR) << "Failed to connect to the BTS (" << v << "). "
LOGC(DDEV, ERROR) << "Failed to connect to the IPC device (" << v << "). "
<< "Retrying...\n";
osmo_timer_setup(&master_sk_state.timer, ipc_sock_timeout, NULL);
osmo_timer_schedule(&master_sk_state.timer, 5, 0);
@@ -837,28 +831,29 @@ out_close:
return -1;
}
void IPCDevice::manually_poll_sock_fds() {
struct timeval wait = {0, 100000};
void IPCDevice::manually_poll_sock_fds()
{
struct timeval wait = { 0, 100000 };
fd_set crfds, cwfds;
int max_fd = 0;
FD_ZERO(&crfds);
FD_ZERO(&cwfds);
for(int i = 0; i < chans; i++) {
struct osmo_fd* curr_fd = &sk_chan_state[i].conn_bfd;
for (unsigned int i = 0; i < chans; i++) {
struct osmo_fd *curr_fd = &sk_chan_state[i].conn_bfd;
max_fd = curr_fd->fd > max_fd ? curr_fd->fd : max_fd;
if(curr_fd->when & OSMO_FD_READ)
FD_SET(curr_fd->fd, &crfds);
if(curr_fd->when & OSMO_FD_WRITE)
FD_SET(curr_fd->fd, &cwfds);
if (curr_fd->when & OSMO_FD_READ)
FD_SET(curr_fd->fd, &crfds);
if (curr_fd->when & OSMO_FD_WRITE)
FD_SET(curr_fd->fd, &cwfds);
}
select(max_fd+1, &crfds, &cwfds, 0, &wait);
select(max_fd + 1, &crfds, &cwfds, 0, &wait);
for(int i = 0; i < chans; i++) {
for (unsigned int i = 0; i < chans; i++) {
int flags = 0;
struct osmo_fd* ofd = &sk_chan_state[i].conn_bfd;
struct osmo_fd *ofd = &sk_chan_state[i].conn_bfd;
if (FD_ISSET(ofd->fd, &crfds)) {
flags |= OSMO_FD_READ;
@@ -869,10 +864,74 @@ void IPCDevice::manually_poll_sock_fds() {
flags |= OSMO_FD_WRITE;
FD_CLR(ofd->fd, &cwfds);
}
if(flags)
ipc_chan_sock_cb(ofd, flags);
if (flags)
ipc_chan_sock_cb(ofd, flags);
}
}
bool IPCDevice::send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id)
{
struct timeval timer_now, timeout;
sk_chan_state[chan].messages_processed_mask = 0;
ipc_sock_send(&sk_chan_state[chan], msg_to_send);
gettimeofday(&timeout, 0);
timeout.tv_sec += 2;
while (!(sk_chan_state[chan].messages_processed_mask & (1 << (expected_rsp_msg_id - IPC_IF_CHAN_MSG_OFFSET)))) {
/* just poll here, we're already in select, so there is no other way to drive
* the fds and "wait" for a response or retry */
manually_poll_sock_fds();
gettimeofday(&timer_now, 0);
if (timercmp(&timer_now, &timeout, >))
return false;
}
return true;
}
bool IPCDevice::send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
struct timeval timer_now, timeout;
for (unsigned int i = 0; i < chans; i++) {
msg = ipc_msgb_alloc(msgid_to_send);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.start_req.dummy = 0;
sk_chan_state[i].messages_processed_mask = 0;
ipc_sock_send(&sk_chan_state[i], msg);
}
gettimeofday(&timeout, 0);
timeout.tv_sec += 2;
unsigned int msg_received_count = 0;
while (msg_received_count != chans) {
msg_received_count = 0;
/* just poll here, we're already in select, so there is no other way to drive
* the fds and "wait" for a response or retry */
manually_poll_sock_fds();
for (unsigned int i = 0; i < sk_chan_state.size(); i++)
if (sk_chan_state[i].messages_processed_mask &
(1 << (msgid_to_expect - IPC_IF_CHAN_MSG_OFFSET)))
msg_received_count++;
gettimeofday(&timer_now, 0);
if (timercmp(&timer_now, &timeout, >))
return false;
}
return true;
}
/* the call stack is rather difficult here, we're already in select:
>~"#0 IPCDevice::start (this=<optimized out>) at IPCDevice.cpp:789\n"
>~"#1 in RadioInterface::start (this=0x614000001640) at radioInterface.cpp:187\n"
@@ -893,43 +952,13 @@ bool IPCDevice::start()
return true;
}
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
struct timeval timer_now, timeout;
for(int i = 0; i < chans; i++) {
msg = ipc_msgb_alloc(IPC_IF_MSG_START_REQ);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.start_req.dummy = 0;
ipc_sock_send(&sk_chan_state[i], msg);
if (!(send_all_chan_wait_rsp(IPC_IF_MSG_START_REQ, IPC_IF_MSG_START_CNF))) {
LOGC(DDEV, ERR) << "start timeout!";
return false;
}
gettimeofday(&timeout, 0);
timeout.tv_sec += 2;
int chan_started_count = 0;
while (chan_started_count != chans) {
chan_started_count = 0;
/* just poll here, we're already in select, so there is no other way to drive
* the fds and "wait" for a response or retry */
manually_poll_sock_fds();
for(unsigned int i = 0; i < ARRAY_SIZE(trx_is_started); i++)
if(trx_is_started[i] == true)
chan_started_count++;
gettimeofday(&timer_now, 0);
if(timercmp(&timer_now, &timeout, >))
return false;
}
int max_bufs_to_flush = 0;
for(unsigned int i = 0; i < shm_dec->num_chans; i++) {
for (unsigned int i = 0; i < shm_dec->num_chans; i++) {
int buf_per_chan = shm_dec->channels[i]->ul_stream->num_buffers;
max_bufs_to_flush = max_bufs_to_flush < buf_per_chan ? buf_per_chan : max_bufs_to_flush;
}
@@ -941,48 +970,15 @@ bool IPCDevice::start()
bool IPCDevice::stop()
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
struct timeval timer_now, timeout;
if (!started)
return true;
for(int i = 0; i < chans; i++) {
if(trx_is_started[i] == true) {
msg = ipc_msgb_alloc(IPC_IF_MSG_STOP_REQ);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.start_req.dummy = 0;
ipc_sock_send(&sk_chan_state[i], msg);
}
if (!(send_all_chan_wait_rsp(IPC_IF_MSG_STOP_REQ, IPC_IF_MSG_STOP_CNF))) {
LOGC(DDEV, ERR) << "stop timeout!";
return false;
}
gettimeofday(&timeout, 0);
timeout.tv_sec += 2;
int chan_started_count = 0;
do {
chan_started_count = 0;
/* just poll here, we're already in select, so there is no other way to drive
* the fds and "wait" for a response or retry */
manually_poll_sock_fds();
for(unsigned int i = 0; i < ARRAY_SIZE(trx_is_started); i++)
if(trx_is_started[i] == true)
chan_started_count++;
gettimeofday(&timer_now, 0);
if(timercmp(&timer_now, &timeout, >)) {
LOGC(DDEV, ERR) << "No response to stop msg received, terminating anyway...";
break;
}
} while (chan_started_count > 0);
LOGC(DDEV, NOTICE) << "All chanels stopped, terminating...";
LOGC(DDEV, NOTICE) << "All channels stopped, terminating...";
/* reset internal buffer timestamps */
for (size_t i = 0; i < rx_buffers.size(); i++)
@@ -1002,20 +998,21 @@ double IPCDevice::minRxGain()
return current_info_cnf.chan_info[0].min_rx_gain;
}
int IPCDevice::getNominalTxPower(size_t chan)
{
return current_info_cnf.chan_info[chan].nominal_tx_power;
}
double IPCDevice::setPowerAttenuation(int atten, size_t chan) {
double IPCDevice::setPowerAttenuation(int atten, size_t chan)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
if(chan >= chans)
if (chan >= chans)
return 0;
LOGCHAN(chan, DDEV, NOTICE) << "Setting TX attenuation to " << atten << " dB" << " chan " << chan;
LOGCHAN(chan, DDEV, NOTICE) << "Setting TX attenuation to " << atten << " dB"
<< " chan " << chan;
msg = ipc_msgb_alloc(IPC_IF_MSG_SETTXATTN_REQ);
if (!msg)
@@ -1023,15 +1020,15 @@ double IPCDevice::setPowerAttenuation(int atten, size_t chan) {
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.txatten_req.attenuation = atten;
ipc_sock_send(&sk_chan_state[chan], msg);
if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETTXATTN_CNF))
LOGCHAN(chan, DDEV, ERROR) << "Setting TX attenuation timeout! ";
tx_attenuation[chan] = atten;
return atten;
}
double IPCDevice::getPowerAttenuation(size_t chan) {
if(chan >= chans)
double IPCDevice::getPowerAttenuation(size_t chan)
{
if (chan >= chans)
return 0;
return tx_attenuation[chan];
@@ -1056,9 +1053,9 @@ double IPCDevice::setRxGain(double dB, size_t chan)
ipc_prim->u.set_gain_req.is_tx = 0;
ipc_prim->u.set_gain_req.gain = dB;
ipc_sock_send(&sk_chan_state[chan], msg);
if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETGAIN_CNF))
LOGCHAN(chan, DDEV, ERROR) << "Setting RX gain timeout! ";
rx_gains[chan] = dB;
return rx_gains[chan];
}
@@ -1066,7 +1063,7 @@ bool IPCDevice::flush_recv(size_t num_pkts)
{
std::vector<uint16_t> tmp(4096);
uint64_t tmps;
uint32_t read;
uint32_t read = 0;
for (uint32_t j = 0; j < num_pkts; j++) {
for (unsigned int i = 0; i < chans; i++)
@@ -1124,7 +1121,7 @@ TIMESTAMP IPCDevice::initialReadTimestamp(void)
// NOTE: Assumes sequential reads
int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)
{
int rc, num_smpls, expect_smpls;
int rc, num_smpls; //, expect_smpls;
ssize_t avail_smpls;
TIMESTAMP expect_timestamp;
unsigned int i;
@@ -1153,25 +1150,17 @@ int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, T
uint64_t recv_timestamp = 0;
thread_enable_cancel(false);
num_smpls = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)bufs[i], len - avail_smpls,
&recv_timestamp, 1);
expect_timestamp = timestamp + avail_smpls;
thread_enable_cancel(true);
if(num_smpls == -ETIMEDOUT)
if (num_smpls == -ETIMEDOUT)
continue;
LOGCHAN(i, DDEV, DEBUG)
"Received timestamp = " << (TIMESTAMP)recv_timestamp << " (" << num_smpls << ")";
expect_smpls = len - avail_smpls;
// if (expect_smpls != num_smpls)
// LOGCHAN(i, DDEV, NOTICE)
// << "Unexpected recv buffer len: expect " << expect_smpls << " got " << num_smpls
// << ", diff=" << expect_smpls - num_smpls;
//expect_timestamp = timestamp + avail_smpls;
if (expect_timestamp != (TIMESTAMP)recv_timestamp)
LOGCHAN(i, DDEV, ERROR) << "Unexpected recv buffer timestamp: expect "
<< expect_timestamp << " got " << recv_timestamp << ", diff="
@@ -1181,7 +1170,8 @@ int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, T
rc = rx_buffers[i]->write(bufs[i], num_smpls, (TIMESTAMP)recv_timestamp);
if (rc < 0) {
LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << " num smpls: " << num_smpls << " chan: " << i;
LOGCHAN(i, DDEV, ERROR)
<< rx_buffers[i]->str_code(rc) << " num smpls: " << num_smpls << " chan: " << i;
LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
if (rc != smpl_buf::ERROR_OVERFLOW)
return 0;
@@ -1216,12 +1206,10 @@ int IPCDevice::writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
for (i = 0; i < chans; i++) {
LOGCHAN(i, DDEV, DEBUG) << "send buffer of len " << len << " timestamp " << std::hex << timestamp;
// thread_enable_cancel(false);
thread_enable_cancel(false);
rc = ipc_shm_enqueue(shm_io_tx_streams[i], timestamp, len, (uint16_t *)bufs[i]);
thread_enable_cancel(true);
// rc = LMS_SendStream(&m_lms_stream_tx[i], bufs[i], len, &tx_metadata, 100);
// update_stream_stats_tx(i, underrun);
// thread_enable_cancel(true);
if (rc != len) {
LOGCHAN(i, DDEV, ERROR) << "LMS: Device Tx timed out (" << rc << " vs exp " << len << ").";
return -1;
@@ -1249,7 +1237,7 @@ bool IPCDevice::setTxFreq(double wFreq, size_t chan)
ipc_prim->u.set_freq_req.is_tx = 1;
ipc_prim->u.set_freq_req.freq = wFreq;
return ipc_sock_send(&sk_chan_state[chan], msg) < 0 ? false : true;
return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);
}
bool IPCDevice::setRxFreq(double wFreq, size_t chan)
@@ -1265,7 +1253,7 @@ bool IPCDevice::setRxFreq(double wFreq, size_t chan)
ipc_prim->u.set_freq_req.is_tx = 0;
ipc_prim->u.set_freq_req.freq = wFreq;
return ipc_sock_send(&sk_chan_state[chan], msg) < 0 ? false : true;
return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);
}
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,

View File

@@ -4,21 +4,29 @@
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under multiple licenses; see the COPYING file in
* the main directory for licensing information for this specific distribution.
* 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 use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
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.
* 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/>.
* See the COPYING file in the main directory for details.
*/
#ifndef _IPC_DEVICE_H_
#define _IPC_DEVICE_H_
#include <cstdint>
#include <cstddef>
#include <climits>
#include <string>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -26,36 +34,32 @@
extern "C" {
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/utils.h>
#include "shm.h"
#include "ipc_shm.h"
}
#include "radioDevice.h"
#include "smpl_buf.h"
#include <sys/time.h>
#include <math.h>
#include <limits.h>
#include <string>
#include <iostream>
class smpl_buf;
struct ipc_sock_state {
#define IPC_MAX_NUM_TRX 8
struct ipc_per_trx_sock_state {
struct osmo_fd conn_bfd; /* fd for connection to the BTS */
struct osmo_timer_list timer; /* socket connect retry timer */
struct llist_head upqueue; /* queue for sending messages */
uint32_t messages_processed_mask; // (=| IPC_IF_MSG_xxx-IPC_IF_CHAN_MSG_OFFSET) bitmask
ipc_per_trx_sock_state() : conn_bfd(), timer(), upqueue(), messages_processed_mask()
{
conn_bfd.fd = -1;
}
};
#define IPC_MAX_NUM_TRX 8
/** A class to handle a LimeSuite supported device */
class IPCDevice : public RadioDevice {
protected:
struct ipc_sock_state master_sk_state;
/* FIXME: current limit IPC_MAX_NUM_TRX chans, make dynamic */
struct ipc_sock_state sk_chan_state[IPC_MAX_NUM_TRX];
bool trx_is_started[IPC_MAX_NUM_TRX];
struct ipc_per_trx_sock_state master_sk_state;
std::vector<struct ipc_per_trx_sock_state> sk_chan_state;
uint32_t tx_attenuation[IPC_MAX_NUM_TRX];
uint8_t tmp_state;
char shm_name[SHM_NAME_MAX];
@@ -64,9 +68,9 @@ class IPCDevice : public RadioDevice {
struct ipc_shm_region *shm_dec;
std::vector<smpl_buf *> rx_buffers;
double actualSampleRate; ///< the actual USRP sampling rate
double actualSampleRate;
bool started; ///< flag indicates LMS has started
bool started;
TIMESTAMP ts_initial, ts_offset;
@@ -79,33 +83,49 @@ class IPCDevice : public RadioDevice {
std::vector<struct ipc_shm_io *> shm_io_rx_streams;
std::vector<struct ipc_shm_io *> shm_io_tx_streams;
virtual bool flush_recv(size_t num_pkts);
bool flush_recv(size_t num_pkts);
void update_stream_stats_rx(size_t chan, bool *overrun);
void update_stream_stats_tx(size_t chan, bool *underrun);
void manually_poll_sock_fds();
public:
virtual void ipc_sock_close(ipc_sock_state *state);
virtual int ipc_sock_read(struct osmo_fd *bfd);
virtual int ipc_sock_write(struct osmo_fd *bfd);
virtual int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim);
virtual int ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf);
virtual int ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf);
virtual int ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf);
virtual int ipc_tx_open_req(struct ipc_sock_state *state, uint32_t num_chans, uint32_t ref);
void ipc_sock_close(ipc_per_trx_sock_state *state);
int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim);
int ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf);
int ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf);
int ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf);
int ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref);
int ipc_chan_rx(uint8_t msg_type, ipc_sk_chan_if *ipc_prim, uint8_t chan_nr);
int ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
int ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
int ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr);
int ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr);
int ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
int ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
int ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr);
bool send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id);
bool send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect);
public:
int ipc_sock_read(struct osmo_fd *bfd);
int ipc_sock_write(struct osmo_fd *bfd);
int ipc_chan_sock_read(osmo_fd *bfd);
int ipc_chan_sock_write(osmo_fd *bfd);
/** Object constructor */
IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths);
virtual ~IPCDevice() override;
/** Instantiate the LMS */
/** Instantiate the IPC */
virtual int open(const std::string &args, int ref, bool swap_channels) override;
/** Start the LMS */
/** Start the IPC */
virtual bool start() override;
/** Stop the LMS */
/** Stop the IPC */
virtual bool stop() override;
/* FIXME: any != USRP1 will do for now... */
@@ -115,21 +135,21 @@ public:
}
/**
Read samples from the LMS.
Read samples from the IPC.
@param buf preallocated buf to contain read result
@param len number of samples desired
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
@param timestamp The timestamp of the first samples to be read
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough
@return The number of samples actually read
*/
virtual int readSamples(std::vector<short *> &buf, int len, bool *overrun, TIMESTAMP timestamp = 0xffffffff,
bool *underrun = NULL) override;
/**
Write samples to the LMS.
Write samples to the IPC.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough
@param timestamp The timestamp of the first sample of the data buffer.
@return The number of samples actually written
*/
@@ -178,6 +198,9 @@ public:
/** return minimum Rx Gain **/
virtual double minRxGain(void) override;
/* FIXME: return rx_gains[chan] ? receive factor from IPC Driver? */
double rssiOffset(size_t chan) { return 0.0f; };
double setPowerAttenuation(int atten, size_t chan) override;
double getPowerAttenuation(size_t chan = 0) override;
@@ -214,16 +237,6 @@ public:
{
return actualSampleRate;
}
int ipc_chan_sock_read(osmo_fd *bfd);
int ipc_chan_sock_write(osmo_fd *bfd);
int ipc_chan_rx(uint8_t msg_type, ipc_sk_chan_if *ipc_prim, uint8_t chan_nr);
int ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
int ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
int ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr);
int ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr);
int ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
int ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
int ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr);
};
#endif // _IPC_DEVICE_H_

View File

@@ -1,29 +1,41 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
AM_LDFLAGS = -lpthread -lrt
noinst_HEADERS = IPCDevice.h shm.h ../uhd/UHDDevice.h uhdwrap.h
noinst_HEADERS = IPCDevice.h shm.h ipc_shm.h ipc_chan.h ipc_sock.h
if DEVICE_UHD
noinst_HEADERS += ../uhd/UHDDevice.h uhdwrap.h ipc-driver-test.h
endif
noinst_LTLIBRARIES = libdevice.la
libdevice_la_SOURCES = IPCDevice.cpp shm.c ipc_shm.c ipc_chan.c ipc_sock.c
libdevice_la_SOURCES = IPCDevice.cpp shm.c ipc_shm.c ipc_chan.c ipc_sock.c
libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la
libdevice_la_CXXFLAGS = $(AM_CXXFLAGS) -DIPCMAGIC
if DEVICE_UHD
#work around distclean issue on older autotools vers:
#a direct build of ../uhd/UHDDevice.cpp tries to clean
#../uhd/.dep/UHDDevice.Plo twice and fails
uhddev_ipc.cpp:
echo "#include \"../uhd/UHDDevice.cpp\"" >$@
CLEANFILES= uhddev_ipc.cpp
bin_PROGRAMS = ipc-driver-test
#ipc_driver_test_SHORTNAME = drvt
ipc_driver_test_SOURCES = ipc-driver-test.c uhdwrap.cpp ipc_shm.c ipc_chan.c ipc_sock.c ../uhd/UHDDevice.cpp
ipc_driver_test_SOURCES = ipc-driver-test.c uhdwrap.cpp ipc_shm.c ipc_chan.c ipc_sock.c uhddev_ipc.cpp
ipc_driver_test_LDADD = \
shm.lo \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOVTY_LIBS)
$(NULL)
ipc_driver_test_CXXFLAGS = $(AM_CXXFLAGS) $(UHD_CFLAGS)
ipc_driver_test_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
ipc_driver_test_CFLAGS = $(AM_CFLAGS) $(UHD_CFLAGS)
ipc_driver_test_LDFLAGS = $(AM_LDFLAGS) $(UHD_LIBS)
ipc_driver_test_LDADD += $(top_builddir)/Transceiver52M/device/common/libdevice_common.la $(top_builddir)/CommonLibs/libcommon.la
endif

View File

@@ -4,21 +4,19 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define _GNU_SOURCE
#include <pthread.h>
#include <debug.h>
#include <stdio.h>
@@ -51,6 +49,7 @@ extern "C" {
#include "ipc_sock.h"
#define DEFAULT_SHM_NAME "/osmo-trx-ipc-driver-shm2"
#define IPC_SOCK_PATH_PREFIX "/tmp"
static void *tall_ctx;
struct ipc_sock_state *global_ipc_sock_state;
@@ -65,17 +64,19 @@ void *global_dev;
static struct ipc_shm_region *decoded_region;
/* Debug Areas of the code */
//enum { DMAIN,
//};
static struct {
int msocknum;
char *ud_prefix_dir;
} cmdline_cfg;
static const struct log_info_cat default_categories[] = {
[DMAIN] = {
.name = "DMAIN",
.color = NULL,
.color = NULL,
.description = "Main generic category",
.loglevel = LOGL_DEBUG,.enabled = 1,
.loglevel = LOGL_DEBUG,.enabled = 1,
},
[DDEV] = {
[DDEV] = {
.name = "DDEV",
.description = "Device/Driver specific code",
.color = NULL,
@@ -87,9 +88,6 @@ const struct log_info log_infox = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
#ifdef __cplusplus
}
#endif
#include "uhdwrap.h"
@@ -193,7 +191,8 @@ static int ipc_tx_open_cnf(int rc, uint32_t num_chans, int32_t timingoffset)
chan_info = ipc_prim->u.open_cnf.chan_info;
for (i = 0; i < num_chans; i++) {
snprintf(chan_info->chan_ipc_sk_path, sizeof(chan_info->chan_ipc_sk_path), "%s_%d", IPC_SOCK_PATH_PREFIX, i);
snprintf(chan_info->chan_ipc_sk_path, sizeof(chan_info->chan_ipc_sk_path),"%s/ipc_sock%d_%d",
cmdline_cfg.ud_prefix_dir, cmdline_cfg.msocknum, i);
/* FIXME: dynamc chan limit, currently 8 */
if (i < 8)
ipc_sock_init(chan_info->chan_ipc_sk_path, &global_ctrl_socks[i], ipc_chan_sock_accept, i);
@@ -222,6 +221,7 @@ int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)
{
/* calculate size needed */
unsigned int len;
unsigned int i;
global_dev = uhdwrap_open(open_req);
@@ -232,14 +232,14 @@ int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)
/* Here we verify num_chans, rx_path, tx_path, clockref, etc. */
int rc = ipc_shm_setup(DEFAULT_SHM_NAME, len);
len = ipc_shm_encode_region((struct ipc_shm_raw_region *)shm, open_req->num_chans, 4, shmbuflen);
// LOGP(DMAIN, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
// LOGP(DMAIN, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
/* set up our own copy of the decoded area, we have to do it here,
* since the uhd wrapper does not allow starting single channels
* since the uhd wrapper does not allow starting single channels
* additionally go for the producer init for both, so only we are responsible for the init, instead
* of splitting it with the client and causing potential races if one side uses it too early */
* of splitting it with the client and causing potential races if one side uses it too early */
decoded_region = ipc_shm_decode_region(0, (struct ipc_shm_raw_region *)shm);
for (unsigned int i = 0; i < open_req->num_chans; i++) {
for (i = 0; i < open_req->num_chans; i++) {
// ios_tx_to_device[i] = ipc_shm_init_consumer(decoded_region->channels[i]->dl_stream);
ios_tx_to_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->dl_stream);
ios_rx_from_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->ul_stream);
@@ -249,14 +249,14 @@ int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)
return 0;
}
volatile int ul_running = 0;
volatile int dl_running = 0;
volatile bool ul_running = false;
volatile bool dl_running = false;
void *uplink_thread(void *x_void_ptr)
{
uint32_t chann = decoded_region->num_chans;
ul_running = 1;
pthread_setname_np(pthread_self(), "uplink rx");
ul_running = true;
pthread_setname_np(pthread_self(), "uplink_rx");
while (!ipc_exit_requested) {
int32_t read = uhdwrap_read(global_dev, chann);
@@ -269,8 +269,8 @@ void *uplink_thread(void *x_void_ptr)
void *downlink_thread(void *x_void_ptr)
{
int chann = decoded_region->num_chans;
dl_running = 1;
pthread_setname_np(pthread_self(), "downlink tx");
dl_running = true;
pthread_setname_np(pthread_self(), "downlink_tx");
while (!ipc_exit_requested) {
bool underrun;
@@ -288,10 +288,9 @@ int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)
rc = uhdwrap_start(global_dev, chan_nr);
/* no per-chan start/stop */
if(!dl_running || !ul_running) {
if (!dl_running || !ul_running) {
/* chan != first chan start will "fail", which is fine, usrp can't start/stop chans independently */
if(rc) {
if (rc) {
LOGP(DMAIN, LOGL_INFO, "starting rx/tx threads.. req for chan:%d\n", chan_nr);
pthread_t rx, tx;
pthread_create(&rx, NULL, uplink_thread, 0);
@@ -401,10 +400,7 @@ int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
return -1;
}
bfd->when = BSC_FD_READ;
bfd->cb = sock_callback_fn;
bfd->data = state;
bfd->priv_nr = n;
osmo_fd_setup(bfd, bfd->fd, OSMO_FD_READ, sock_callback_fn, state, n);
rc = osmo_fd_register(bfd);
if (rc < 0) {
@@ -414,8 +410,6 @@ int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
return rc;
}
//osmo_signal_register_handler(SS_GLOBAL, IPC_if_signal_cb, NULL);
LOGP(DMAIN, LOGL_INFO, "Started listening on IPC socket: %s\n", path);
return 0;
@@ -423,26 +417,22 @@ int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
static void print_help(void)
{
printf( "ipc-driver-test Usage:\n"
" -h --help This message\n"
" -n --sock-num NR Master socket suffix number NR\n"
);
printf("ipc-driver-test Usage:\n"
" -h --help This message\n"
" -u --unix-sk-dir DIR Existing directory where to create the Master socket\n"
" -n --sock-num NR Master socket suffix number NR\n");
}
static int msocknum = 0;
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
const struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "sock-num", 1, 0, 'n' },
{0,0,0,0}
};
const struct option long_options[] = { { "help", 0, 0, 'h' },
{ "unix-sk-dir", 1, 0, 'u' },
{ "sock-num", 1, 0, 'n' },
{ 0, 0, 0, 0 } };
c = getopt_long(argc, argv, "hn:",
long_options, &option_index);
c = getopt_long(argc, argv, "hu:n:", long_options, &option_index);
if (c == -1)
break;
@@ -451,9 +441,13 @@ static void handle_options(int argc, char **argv)
print_help();
exit(0);
break;
case 'n':
msocknum = atoi(optarg);
case 'u':
cmdline_cfg.ud_prefix_dir = talloc_strdup(tall_ctx, optarg);
break;
case 'n':
cmdline_cfg.msocknum = atoi(optarg);
break;
default:
exit(2);
break;
@@ -466,36 +460,33 @@ static void handle_options(int argc, char **argv)
}
}
#if defined(IPCMAGIC) && defined(__cplusplus)
extern "C" int osmo_ctx_init(const char *id);
extern "C" int magicmain(int argc, char **argv)
{
osmo_ctx_init("main");
osmo_select_init();
#else
int main(int argc, char **argv)
{
#endif
char ipc_msock_path[sizeof(IPC_SOCK_PATH_PREFIX)+3];
char ipc_msock_path[128];
tall_ctx = talloc_named_const(NULL, 0, "OsmoTRX");
msgb_talloc_ctx_init(tall_ctx, 0);
osmo_init_logging2(tall_ctx, &log_infox);
log_enable_multithread();
handle_options(argc, argv);
snprintf(ipc_msock_path,sizeof(ipc_msock_path), "%s%d", IPC_SOCK_PATH_PREFIX, msocknum);
if (!cmdline_cfg.ud_prefix_dir)
cmdline_cfg.ud_prefix_dir = talloc_strdup(tall_ctx, IPC_SOCK_PATH_PREFIX);
snprintf(ipc_msock_path, sizeof(ipc_msock_path), "%s/ipc_sock%d", cmdline_cfg.ud_prefix_dir, cmdline_cfg.msocknum);
LOGP(DMAIN, LOGL_INFO, "Starting %s\n", argv[0]);
ipc_sock_init(ipc_msock_path, &global_ipc_sock_state, ipc_sock_accept, 0);
while (!ipc_exit_requested)
osmo_select_main(0);
if (global_dev)
for (unsigned int i = 0; i < decoded_region->num_chans; i++)
if (global_dev) {
unsigned int i;
for (i = 0; i < decoded_region->num_chans; i++)
uhdwrap_stop(global_dev, i);
}
//ipc_sock_close()
ipc_sock_close(global_ipc_sock_state);
return 0;
}

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
@@ -25,7 +27,7 @@ extern struct ipc_shm_io *ios_rx_from_device[8];
struct ipc_sock_state {
struct osmo_fd listen_bfd; /* fd for listen socket */
struct osmo_fd conn_bfd; /* fd for connection to lcr */
struct osmo_fd conn_bfd; /* fd for connection */
struct llist_head upqueue; /* queue for sending messages */
};
@@ -41,4 +43,3 @@ int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);
int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr);
int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr);
int ipc_rx_chan_settxatten_req(struct ipc_sk_chan_if_tx_attenuation *req, uint8_t chan_nr);

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
@@ -47,29 +49,23 @@ static int ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_
switch (msg_type) {
case IPC_IF_MSG_START_REQ:
rc = ipc_rx_chan_start_req(&ipc_prim->u.start_req, chan_nr);
fprintf(stderr, "%s:%d: IPC_IF_MSG_START_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);
break;
case IPC_IF_MSG_STOP_REQ:
rc = ipc_rx_chan_stop_req(&ipc_prim->u.stop_req, chan_nr);
fprintf(stderr, "%s:%d: IPC_IF_MSG_STOP_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);
break;
case IPC_IF_MSG_SETGAIN_REQ:
rc = ipc_rx_chan_setgain_req(&ipc_prim->u.set_gain_req, chan_nr);
fprintf(stderr, "%s:%d: IPC_IF_MSG_SETGAIN_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);
break;
case IPC_IF_MSG_SETFREQ_REQ:
rc = ipc_rx_chan_setfreq_req(&ipc_prim->u.set_freq_req, chan_nr);
fprintf(stderr, "%s:%d: IPC_IF_MSG_SETFREQ_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);
break;
case IPC_IF_MSG_SETTXATTN_REQ:
rc = ipc_rx_chan_settxatten_req(&ipc_prim->u.txatten_req, chan_nr);
fprintf(stderr, "%s:%d: IPC_IF_MSG_SETTXATTN_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);
break;
default:
fprintf(stderr, "Received unknown IPC msg type %d\n", msg_type);
LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type 0x%02x on chan %d\n", msg_type, chan_nr);
rc = -EINVAL;
}
fflush(stderr);
return rc;
}
@@ -100,7 +96,7 @@ static int ipc_chan_sock_read(struct osmo_fd *bfd)
}
if (rc < (int)sizeof(*ipc_prim)) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"Received %d bytes on Unix Socket, but primitive size "
"is %zu, discarding\n",
rc, sizeof(*ipc_prim));
@@ -131,7 +127,7 @@ int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr)
return -EINVAL;
if (!state) {
LOGP(DMAIN, LOGL_INFO,
LOGP(DDEV, LOGL_INFO,
"IPC socket not created, "
"dropping message\n");
msgb_free(msg);
@@ -139,14 +135,14 @@ int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr)
}
conn_bfd = &state->conn_bfd;
if (conn_bfd->fd <= 0) {
LOGP(DMAIN, LOGL_NOTICE,
LOGP(DDEV, LOGL_NOTICE,
"IPC socket not connected, "
"dropping message\n");
msgb_free(msg);
return -EIO;
}
msgb_enqueue(&state->upqueue, msg);
conn_bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(conn_bfd);
return 0;
}
@@ -164,11 +160,11 @@ static int ipc_chan_sock_write(struct osmo_fd *bfd)
msg = llist_entry(state->upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
osmo_fd_write_disable(bfd);
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"message type (%d) with ZERO "
"bytes!\n",
ipc_prim->msg_type);
@@ -181,14 +177,14 @@ static int ipc_chan_sock_write(struct osmo_fd *bfd)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(bfd);
break;
}
goto close;
}
dontsend:
/* _after_ we send it, we can deueue */
/* _after_ we send it, we can dequeue */
msg2 = msgb_dequeue(&state->upqueue);
assert(msg == msg2);
msgb_free(msg);
@@ -204,12 +200,12 @@ static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
int rc = 0;
if (flags & BSC_FD_READ)
if (flags & OSMO_FD_READ)
rc = ipc_chan_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
if (flags & OSMO_FD_WRITE)
rc = ipc_chan_sock_write(bfd);
return rc;
@@ -226,30 +222,25 @@ int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags)
len = sizeof(un_addr);
rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");
LOGP(DDEV, LOGL_ERROR, "Failed to accept a new connection\n");
return -1;
}
if (conn_bfd->fd >= 0) {
LOGP(DMAIN, LOGL_NOTICE,
LOGP(DDEV, LOGL_NOTICE,
"osmo-trx connects but we already have "
"another active connection ?!?\n");
/* We already have one IPC connected, this is all we support */
state->listen_bfd.when &= ~BSC_FD_READ;
osmo_fd_read_disable(&state->listen_bfd);
close(rc);
return 0;
}
conn_bfd->fd = rc;
conn_bfd->when = BSC_FD_READ;
conn_bfd->cb = ipc_chan_sock_cb;
conn_bfd->data = state;
/* copy chan nr, required for proper bfd<->chan # mapping */
conn_bfd->priv_nr = bfd->priv_nr;
osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, ipc_chan_sock_cb, state, bfd->priv_nr);
if (osmo_fd_register(conn_bfd) != 0) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"Failed to register new connection "
"fd\n");
close(conn_bfd->fd);
@@ -257,10 +248,7 @@ int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags)
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
/* send current info */
//IPC_tx_info_ind();
LOGP(DDEV, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
return 0;
}

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef IPC_CHAN_H
#define IPC_CHAN_H

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __cplusplus
extern "C" {
@@ -24,12 +26,15 @@ extern "C" {
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <osmocom/core/panic.h>
#include <debug.h>
#ifdef __cplusplus
}
#endif
#define SAMPLE_SIZE_BYTE sizeof(uint16_t) * 2
#define SAMPLE_SIZE_BYTE (sizeof(uint16_t) * 2)
struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s)
{
@@ -56,52 +61,44 @@ struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s)
struct ipc_shm_io *r = ipc_shm_init_consumer(s);
rv = pthread_mutexattr_init(&att);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_mutexattr_setrobust(&att, PTHREAD_MUTEX_ROBUST);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_mutexattr_setpshared(&att, PTHREAD_PROCESS_SHARED);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_mutex_init((pthread_mutex_t *)&r->this_stream->lock, &att);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
pthread_mutexattr_destroy(&att);
rv = pthread_condattr_setpshared(&t1, PTHREAD_PROCESS_SHARED);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_condattr_setpshared(&t2, PTHREAD_PROCESS_SHARED);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->cf, &t1);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->ce, &t2);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
osmo_panic("%s:%d rv:%d", __FILE__, __LINE__, rv);
}
pthread_condattr_destroy(&t1);
@@ -115,8 +112,7 @@ struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s)
void ipc_shm_close(struct ipc_shm_io *r)
{
if (r) {
if (r->buf_ptrs)
free(r->buf_ptrs);
free(r->buf_ptrs);
free(r);
}
}

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef IPC_SHM_H
#define IPC_SHM_H
@@ -26,7 +28,7 @@ extern "C" {
#endif
struct ipc_shm_io {
volatile struct ipc_shm_raw_stream *this_stream; // plus num_buffers at end
volatile struct ipc_shm_raw_stream *this_stream;
volatile struct ipc_shm_raw_smpl_buf **volatile buf_ptrs;
uint32_t partial_read_begin_ptr;
};

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
@@ -54,7 +56,7 @@ static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
rc = ipc_rx_open_req(&ipc_prim->u.open_req);
break;
default:
LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type 0x%02x\n", msg_type);
rc = -EINVAL;
}
@@ -65,10 +67,9 @@ int ipc_sock_send(struct msgb *msg)
{
struct ipc_sock_state *state = global_ipc_sock_state;
struct osmo_fd *conn_bfd;
//struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;
if (!state) {
LOGP(DMAIN, LOGL_INFO,
LOGP(DDEV, LOGL_INFO,
"IPC socket not created, "
"dropping message\n");
msgb_free(msg);
@@ -76,14 +77,14 @@ int ipc_sock_send(struct msgb *msg)
}
conn_bfd = &state->conn_bfd;
if (conn_bfd->fd <= 0) {
LOGP(DMAIN, LOGL_NOTICE,
LOGP(DDEV, LOGL_NOTICE,
"IPC socket not connected, "
"dropping message\n");
msgb_free(msg);
return -EIO;
}
msgb_enqueue(&state->upqueue, msg);
conn_bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(conn_bfd);
return 0;
}
@@ -92,7 +93,7 @@ void ipc_sock_close(struct ipc_sock_state *state)
{
struct osmo_fd *bfd = &state->conn_bfd;
LOGP(DMAIN, LOGL_NOTICE, "IPC socket has LOST connection\n");
LOGP(DDEV, LOGL_NOTICE, "IPC socket has LOST connection\n");
ipc_exit_requested = 1;
@@ -101,7 +102,7 @@ void ipc_sock_close(struct ipc_sock_state *state)
osmo_fd_unregister(bfd);
/* re-enable the generation of ACCEPT for new connections */
state->listen_bfd.when |= BSC_FD_READ;
osmo_fd_read_enable(&state->listen_bfd);
/* flush the queue */
while (!llist_empty(&state->upqueue)) {
@@ -136,7 +137,7 @@ int ipc_sock_read(struct osmo_fd *bfd)
}
if (rc < (int)sizeof(*ipc_prim)) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"Received %d bytes on Unix Socket, but primitive size "
"is %zu, discarding\n",
rc, sizeof(*ipc_prim));
@@ -171,11 +172,11 @@ static int ipc_sock_write(struct osmo_fd *bfd)
msg = llist_entry(state->upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
osmo_fd_write_disable(bfd);
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"message type (%d) with ZERO "
"bytes!\n",
ipc_prim->msg_type);
@@ -188,7 +189,7 @@ static int ipc_sock_write(struct osmo_fd *bfd)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
osmo_fd_write_enable(bfd);
break;
}
goto close;
@@ -211,12 +212,12 @@ static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
int rc = 0;
if (flags & BSC_FD_READ)
if (flags & OSMO_FD_READ)
rc = ipc_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
if (flags & OSMO_FD_WRITE)
rc = ipc_sock_write(bfd);
return rc;
@@ -234,27 +235,24 @@ int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
len = sizeof(un_addr);
rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");
LOGP(DDEV, LOGL_ERROR, "Failed to accept a new connection\n");
return -1;
}
if (conn_bfd->fd >= 0) {
LOGP(DMAIN, LOGL_NOTICE,
LOGP(DDEV, LOGL_NOTICE,
"ip clent connects but we already have "
"another active connection ?!?\n");
/* We already have one IPC connected, this is all we support */
state->listen_bfd.when &= ~BSC_FD_READ;
osmo_fd_read_disable(&state->listen_bfd);
close(rc);
return 0;
}
conn_bfd->fd = rc;
conn_bfd->when = BSC_FD_READ;
conn_bfd->cb = ipc_sock_cb;
conn_bfd->data = state;
osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, ipc_sock_cb, state, 0);
if (osmo_fd_register(conn_bfd) != 0) {
LOGP(DMAIN, LOGL_ERROR,
LOGP(DDEV, LOGL_ERROR,
"Failed to register new connection "
"fd\n");
close(conn_bfd->fd);
@@ -262,10 +260,7 @@ int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
/* send current info */
//IPC_tx_info_ind();
LOGP(DDEV, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
return 0;
}

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef IPC_SOCK_H
#define IPC_SOCK_H

View File

@@ -4,23 +4,23 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <osmocom/core/talloc.h>
#include "shm.h"
//#define ENCDECDEBUG
#define ENCDECDEBUG(...) //fprintf(stderr, __VA_ARGS__)
/* Convert offsets to pointers */
struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_region *root_raw,
@@ -37,9 +37,7 @@ struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_
stream->buffer_size = stream_raw->buffer_size;
stream->raw = stream_raw;
for (i = 0; i < stream->num_buffers; i++) {
#ifdef ENCDECDEBUG
fprintf(stderr, "decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]);
#endif
ENCDECDEBUG("decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]);
stream->buffers[i] =
(struct ipc_shm_raw_smpl_buf *)(((uint8_t *)root_raw) + stream_raw->buffer_offset[i]);
}
@@ -53,9 +51,7 @@ struct ipc_shm_channel *ipc_shm_decode_channel(void *tall_ctx, struct ipc_shm_ra
chan = talloc_zero(tall_ctx, struct ipc_shm_channel);
if (!chan)
return NULL;
#ifdef ENCDECDEBUG
fprintf(stderr, "decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset);
#endif
ENCDECDEBUG("decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset);
chan->dl_stream = ipc_shm_decode_stream(
chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->dl_buf_offset));
chan->ul_stream = ipc_shm_decode_stream(
@@ -73,9 +69,7 @@ struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_
root->num_chans = root_raw->num_chans;
for (i = 0; i < root->num_chans; i++) {
#ifdef ENCDECDEBUG
fprintf(stderr, "decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]);
#endif
ENCDECDEBUG("decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]);
root->channels[i] = ipc_shm_decode_channel(
root, root_raw,
(struct ipc_shm_raw_channel *)(((uint8_t *)root_raw) + root_raw->chan_offset[i]));
@@ -88,9 +82,7 @@ unsigned int ipc_shm_encode_smpl_buf(struct ipc_shm_raw_region *root_raw, struct
{
unsigned int offset = sizeof(struct ipc_shm_raw_smpl_buf);
offset = (((uintptr_t)offset + 7) & ~0x07ULL);
#ifdef ENCDECDEBUG
fprintf(stderr, "encode: smpl_buf at offset %lu\n", (start - (uint8_t *)root_raw));
#endif
ENCDECDEBUG("encode: smpl_buf at offset %u\n", offset);
offset += buffer_size * sizeof(uint16_t) * 2; /* samples */
return offset;
}
@@ -102,9 +94,7 @@ unsigned int ipc_shm_encode_stream(struct ipc_shm_raw_region *root_raw, struct i
ptrdiff_t start = (ptrdiff_t)stream_raw;
unsigned int offset = sizeof(struct ipc_shm_raw_stream) + sizeof(uint32_t) * num_buffers;
offset = (((uintptr_t)offset + 7) & ~0x07ULL);
#ifdef ENCDECDEBUG
fprintf(stderr, "encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw));
#endif
ENCDECDEBUG("encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw));
if (root_raw) {
stream_raw->num_buffers = num_buffers;
stream_raw->buffer_size = buffer_size;
@@ -125,9 +115,7 @@ unsigned int ipc_shm_encode_channel(struct ipc_shm_raw_region *root_raw, struct
uint8_t *start = (uint8_t *)chan_raw;
unsigned int offset = sizeof(struct ipc_shm_raw_channel);
offset = (((uintptr_t)offset + 7) & ~0x07ULL);
#ifdef ENCDECDEBUG
fprintf(stderr, "encode: channel at offset %lu\n", (start - (uint8_t *)root_raw));
#endif
ENCDECDEBUG("encode: channel at offset %lu\n", (start - (uint8_t *)root_raw));
if (root_raw)
chan_raw->dl_buf_offset = (start + offset - (uint8_t *)root_raw);
offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers,
@@ -152,9 +140,7 @@ unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t
for (i = 0; i < num_chans; i++) {
if (root_raw)
root_raw->chan_offset[i] = (start + offset - (uintptr_t)root_raw);
#ifdef ENCDECDEBUG
fprintf(stderr, "encode: channel %d chan_offset[i]=%u\n", i, ofs);
#endif
ENCDECDEBUG("encode: channel %d chan_offset[i]=%lu\n", i, start + offset - (uintptr_t)root_raw);
offset += ipc_shm_encode_channel(root_raw, (struct ipc_shm_raw_channel *)(start + offset), num_buffers,
buffer_size);
}

View File

@@ -4,19 +4,21 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <stdint.h>
#include <unistd.h>
#include <limits.h>
//#include <pthread.h>
#include <pthread.h>
#include <semaphore.h>
/* RAW structures */
@@ -27,9 +29,9 @@ struct ipc_shm_raw_smpl_buf {
};
struct ipc_shm_raw_stream {
pthread_mutex_t lock;
pthread_cond_t cf;
pthread_cond_t ce;
pthread_mutex_t lock; /* protects this struct */
pthread_cond_t cf; /* signals fill to reader */
pthread_cond_t ce; /* signals empty nbuf to writer */
uint32_t num_buffers;
uint32_t buffer_size; /* In samples */
uint32_t read_next;
@@ -77,8 +79,6 @@ struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_
//////////////////
// Master socket
//////////////////
#define IPC_SOCK_PATH_PREFIX "/tmp/ipc_sock"
#define IPC_SOCK_API_VERSION 1
/* msg_type */

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
extern "C" {
#include <osmocom/core/application.h>
@@ -29,7 +31,6 @@ extern "C" {
#include "../uhd/UHDDevice.h"
#include "uhdwrap.h"
#include "trx_vty.h"
#include "Logger.h"
#include "Threads.h"
#include "Utils.h"
@@ -154,7 +155,7 @@ extern "C" int32_t uhdwrap_write(void *dev, uint32_t num_chans, bool *underrun)
uhd_wrap *d = (uhd_wrap *)dev;
uint64_t timestamp;
int32_t len;
int32_t len = -1;
for (uint32_t i = 0; i < num_chans; i++) {
len = ipc_shm_read(ios_tx_to_device[i], (uint16_t *)&d->wrap_tx_buffs[i].front(), 5000, &timestamp, 1);
if (len < 0)
@@ -176,13 +177,13 @@ extern "C" double uhdwrap_set_freq(void *dev, double f, size_t chan, bool for_tx
extern "C" double uhdwrap_set_gain(void *dev, double f, size_t chan, bool for_tx)
{
uhd_wrap *d = (uhd_wrap *)dev;
// if (for_tx)
// return d->setTxGain(f, chan);
// else
return d->setRxGain(f, chan);
// if (for_tx)
// return d->setTxGain(f, chan);
// else
return d->setRxGain(f, chan);
}
extern "C" double uhdwrap_set_txatt(void *dev, double a, size_t chan)
extern "C" double uhdwrap_set_txatt(void *dev, double a, size_t chan)
{
uhd_wrap *d = (uhd_wrap *)dev;
return d->setPowerAttenuation(a, chan);

View File

@@ -4,12 +4,14 @@
*
* SPDX-License-Identifier: 0BSD
*
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef IPC_UHDWRAP_H
#define IPC_UHDWRAP_H

View File

@@ -23,7 +23,6 @@
#include <map>
#include "trx_vty.h"
#include "Logger.h"
#include "Threads.h"
#include "LMSDevice.h"
@@ -32,6 +31,7 @@
#include <lime/LimeSuite.h>
extern "C" {
#include "trx_vty.h"
#include "osmo_signal.h"
#include <osmocom/core/utils.h>
}
@@ -40,8 +40,6 @@ extern "C" {
#include "config.h"
#endif
using namespace std;
#define MAX_ANTENNA_LIST_SIZE 10
#define GSM_CARRIER_BW 270000.0 /* 270kHz */
#define LMS_MIN_BW_SUPPORTED 2.5e6 /* 2.5mHz, minimum supported by LMS */
@@ -85,27 +83,20 @@ static const std::map<enum lms_dev_type, struct dev_desc> dev_param_map {
};
typedef std::tuple<lms_dev_type, enum gsm_band> dev_band_key;
/* Maximum LimeSuite Tx Gain which can be set/used without distorting the output
* signal, and the resulting real output power measured when that gain is used.
*/
struct dev_band_desc {
double nom_lms_tx_gain; /* dB */
double nom_out_tx_power; /* dBm */
};
typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map {
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_850), { 73.0, 11.2 } },
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_900), { 73.0, 10.8 } },
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1800), { 65.0, -3.5 } }, /* FIXME: OS#4583: 1800Mhz is failing above TxGain=65, which is around -3.5dBm (already < 0 dBm) */
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1900), { 73.0, 1.7 } }, /* FIXME: OS#4583: 1900MHz is failing in all TxGain values */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_850), { 66.0, 3.1 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_900), { 66.0, 2.8 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1800), { 66.0, -11.6 } }, /* OS#4583: Any of BAND1 or BAND2 is fine */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1900), { 66.0, -9.2 } }, /* FIXME: OS#4583: Ensure BAND1 is used at startup */
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_850), { 71.0, 6.8 } },
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_900), { 71.0, 6.8 } },
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1800), { 65.0, -10.5 } }, /* OS#4583: TxGain=71 (-4.4dBm) FAIL rms phase errors ~10° */
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1900), { 71.0, -6.3 } }, /* FIXME: OS#4583: all FAIL, BAND1/BAND2 rms phase errors >23° */
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_850), { 73.0, 11.2, -6.0 } },
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_900), { 73.0, 10.8, -6.0 } },
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1800), { 65.0, -3.5, -17.0 } }, /* FIXME: OS#4583: 1800Mhz is failing above TxGain=65, which is around -3.5dBm (already < 0 dBm) */
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1900), { 73.0, 1.7, -17.0 } }, /* FIXME: OS#4583: 1900MHz is failing in all TxGain values */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_850), { 66.0, 3.1, -6.0 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_900), { 66.0, 2.8, -6.0 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1800), { 66.0, -11.6, -17.0 } }, /* OS#4583: Any of BAND1 or BAND2 is fine */
{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1900), { 66.0, -9.2, -17.0 } }, /* FIXME: OS#4583: Ensure BAND1 is used at startup */
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_850), { 71.0, 6.8, -6.0 } },
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_900), { 71.0, 6.8, -6.0 } },
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1800), { 65.0, -10.5, -17.0 } }, /* OS#4583: TxGain=71 (-4.4dBm) FAIL rms phase errors ~10° */
{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1900), { 71.0, -6.3, -17.0 } }, /* FIXME: OS#4583: all FAIL, BAND1/BAND2 rms phase errors >23° */
};
/* So far measurements done for B210 show really close to linear relationship
@@ -210,7 +201,7 @@ static void print_range(const char* name, lms_range_t *range)
int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::string &args)
{
unsigned int i, j;
std::vector<string> filters;
std::vector<std::string> filters;
filters = comma_delimited_to_vector(args.c_str());
@@ -231,15 +222,10 @@ int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::str
return -1;
}
void LMSDevice::get_dev_band_desc(dev_band_desc& desc)
void LMSDevice::assign_band_desc(enum gsm_band req_band)
{
dev_band_map_it it;
enum gsm_band req_band = band;
if (req_band == 0) {
LOGC(DDEV, ERROR) << "Nominal Tx Power requested before Tx Frequency was set! Providing band 900 by default... ";
req_band = GSM_BAND_900;
}
it = dev_band_nom_power_param_map.find(dev_band_key(m_dev_type, req_band));
if (it == dev_band_nom_power_param_map.end()) {
dev_desc desc = dev_param_map.at(m_dev_type);
@@ -248,8 +234,30 @@ void LMSDevice::get_dev_band_desc(dev_band_desc& desc)
<< ", using LimeSDR-USB ones as fallback";
it = dev_band_nom_power_param_map.find(dev_band_key(LMS_DEV_SDR_USB, req_band));
}
OSMO_ASSERT(it != dev_band_nom_power_param_map.end())
desc = it->second;
OSMO_ASSERT(it != dev_band_nom_power_param_map.end());
band_desc = it->second;
}
bool LMSDevice::set_band(enum gsm_band req_band)
{
if (band != 0 && req_band != band) {
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
<< " different from previous band " << gsm_band_name(band);
return false;
}
band = req_band;
assign_band_desc(band);
return true;
}
void LMSDevice::get_dev_band_desc(dev_band_desc& desc)
{
if (band == 0) {
LOGC(DDEV, ERROR) << "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
assign_band_desc(GSM_BAND_900);
}
desc = band_desc;
}
int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
@@ -561,6 +569,21 @@ double LMSDevice::setRxGain(double dB, size_t chan)
return rx_gains[chan];
}
double LMSDevice::rssiOffset(size_t chan)
{
double rssiOffset;
dev_band_desc desc;
if (chan >= rx_gains.size()) {
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
return 0.0f;
}
get_dev_band_desc(desc);
rssiOffset = rx_gains[chan] + desc.rxgain2rssioffset_rel;
return rssiOffset;
}
double LMSDevice::setPowerAttenuation(int atten, size_t chan)
{
double tx_power, dB;

View File

@@ -52,7 +52,22 @@ enum lms_dev_type {
LMS_DEV_UNKNOWN,
};
struct dev_band_desc;
struct dev_band_desc {
/* Maximum LimeSuite Tx Gain which can be set/used without distorting
the output * signal, and the resulting real output power measured
when that gain is used.
*/
double nom_lms_tx_gain; /* dB */
double nom_out_tx_power; /* dBm */
/* Factor used to infer base real RSSI offset on the Rx path based on current
configured RxGain. The resulting rssiOffset is added to the per burst
calculated energy in upper layers. These values were empirically
found and may change based on multiple factors, see OS#4468.
Correct measured values only provided for LimeSDR-USB so far.
rssiOffset = rxGain + rxgain2rssioffset_rel;
*/
double rxgain2rssioffset_rel; /* dB */
};
/** A class to handle a LimeSuite supported device */
class LMSDevice:public RadioDevice {
@@ -73,6 +88,7 @@ private:
std::vector<double> tx_gains, rx_gains;
enum gsm_band band;
struct dev_band_desc band_desc;
enum lms_dev_type m_dev_type;
@@ -85,7 +101,8 @@ private:
void update_stream_stats_tx(size_t chan, bool *underrun);
bool do_clock_src_freq(enum ReferenceType ref, double freq);
void get_dev_band_desc(dev_band_desc& desc);
bool set_band(enum gsm_band req_band);
void assign_band_desc(enum gsm_band req_band);
public:
/** Object constructor */
@@ -173,6 +190,7 @@ public:
/** return minimum Rx Gain **/
double minRxGain(void);
double rssiOffset(size_t chan);
double setPowerAttenuation(int atten, size_t chan);
double getPowerAttenuation(size_t chan = 0);

View File

@@ -1,7 +1,7 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LMS_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LMS_CFLAGS)
noinst_HEADERS = LMSDevice.h

View File

@@ -1,7 +1,7 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(UHD_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(UHD_CFLAGS)
noinst_HEADERS = UHDDevice.h

View File

@@ -130,29 +130,22 @@ static const std::map<dev_key, dev_desc> dev_param_map {
};
typedef std::tuple<uhd_dev_type, enum gsm_band> dev_band_key;
/* Maximum UHD Tx Gain which can be set/used without distorting the
output signal, and the resulting real output power measured when that
gain is used. Correct measured values only provided for B210 so far. */
struct dev_band_desc {
double nom_uhd_tx_gain; /* dB */
double nom_out_tx_power; /* dBm */
};
typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map {
{ std::make_tuple(B200, GSM_BAND_850), { 89.75, 13.3 } },
{ std::make_tuple(B200, GSM_BAND_900), { 89.75, 13.3 } },
{ std::make_tuple(B200, GSM_BAND_1800), { 89.75, 7.5 } },
{ std::make_tuple(B200, GSM_BAND_1900), { 89.75, 7.7 } },
{ std::make_tuple(B210, GSM_BAND_850), { 89.75, 13.3 } },
{ std::make_tuple(B210, GSM_BAND_900), { 89.75, 13.3 } },
{ std::make_tuple(B210, GSM_BAND_1800), { 89.75, 7.5 } },
{ std::make_tuple(B210, GSM_BAND_1900), { 89.75, 7.7 } },
{ std::make_tuple(B200, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
{ std::make_tuple(B200, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
{ std::make_tuple(B200, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
{ std::make_tuple(B200, GSM_BAND_1900), { 89.75, 7.7, -11.0 } },
{ std::make_tuple(B210, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
{ std::make_tuple(B210, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
{ std::make_tuple(B210, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
{ std::make_tuple(B210, GSM_BAND_1900), { 89.75, 7.7, -11.0 } },
};
void *async_event_loop(uhd_device *dev)
{
set_selfthread_name("UHDAsyncEvent");
OSMO_ASSERT(osmo_cpu_sched_vty_apply_localthread() == 0);
osmo_cpu_sched_vty_apply_localthread();
while (1) {
dev->recv_async_msg();
@@ -247,25 +240,42 @@ uhd_device::~uhd_device()
delete rx_buffers[i];
}
void uhd_device::get_dev_band_desc(dev_band_desc& desc)
void uhd_device::assign_band_desc(enum gsm_band req_band)
{
dev_band_map_it it;
enum gsm_band req_band = band;
if (req_band == 0) {
LOGC(DDEV, ERROR) << "Nominal Tx Power requested before Tx Frequency was set! Providing band 900 by default... ";
req_band = GSM_BAND_900;
}
it = dev_band_nom_power_param_map.find(dev_band_key(dev_type, req_band));
if (it == dev_band_nom_power_param_map.end()) {
dev_desc desc = dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps));
LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device "
LOGC(DDEV, ERROR) << "No Power parameters exist for device "
<< desc.str << " on band " << gsm_band_name(req_band)
<< ", using B210 ones as fallback";
it = dev_band_nom_power_param_map.find(dev_band_key(B210, req_band));
}
OSMO_ASSERT(it != dev_band_nom_power_param_map.end())
desc = it->second;
band_desc = it->second;
}
bool uhd_device::set_band(enum gsm_band req_band)
{
if (band != 0 && req_band != band) {
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
<< " different from previous band " << gsm_band_name(band);
return false;
}
band = req_band;
assign_band_desc(band);
return true;
}
void uhd_device::get_dev_band_desc(dev_band_desc& desc)
{
if (band == 0) {
LOGC(DDEV, ERROR) << "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
assign_band_desc(GSM_BAND_900);
}
desc = band_desc;
}
void uhd_device::init_gains()
@@ -360,6 +370,21 @@ double uhd_device::getRxGain(size_t chan)
return rx_gains[chan];
}
double uhd_device::rssiOffset(size_t chan)
{
double rssiOffset;
dev_band_desc desc;
if (chan >= rx_gains.size()) {
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
return 0.0f;
}
get_dev_band_desc(desc);
rssiOffset = rx_gains[chan] + desc.rxgain2rssioffset_rel;
return rssiOffset;
}
double uhd_device::setPowerAttenuation(int atten, size_t chan) {
double tx_power, db;
dev_band_desc desc;
@@ -1052,16 +1077,12 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan)
return false;
}
if (band != 0 && req_band != band) {
LOGCHAN(chan, DDEV, ALERT) << "Requesting Tx Frequency " << wFreq
<< " Hz different from previous band " << gsm_band_name(band);
if (!set_band(req_band))
return false;
}
if (!set_freq(wFreq, chan, true))
return false;
band = req_band;
return true;
}

View File

@@ -56,7 +56,20 @@ enum uhd_dev_type {
LIMESDR,
};
struct dev_band_desc;
struct dev_band_desc {
/* Maximum UHD Tx Gain which can be set/used without distorting the
output signal, and the resulting real output power measured when that
gain is used. Correct measured values only provided for B210 so far. */
double nom_uhd_tx_gain; /* dB */
double nom_out_tx_power; /* dBm */
/* Factor used to infer base real RSSI offset on the Rx path based on current
configured RxGain. The resulting rssiOffset is added to the per burst
calculated energy in upper layers. These values were empirically
found and may change based on multiple factors, see OS#4468.
rssiOffset = rxGain + rxgain2rssioffset_rel;
*/
double rxgain2rssioffset_rel; /* dB */
};
/*
uhd_device - UHD implementation of the Device interface. Timestamped samples
@@ -100,6 +113,7 @@ public:
double getRxGain(size_t chan);
double maxRxGain(void) { return rx_gain_max; }
double minRxGain(void) { return rx_gain_min; }
double rssiOffset(size_t chan);
double setPowerAttenuation(int atten, size_t chan);
double getPowerAttenuation(size_t chan = 0);
@@ -147,6 +161,7 @@ protected:
std::vector<double> tx_gains, rx_gains;
std::vector<double> tx_freqs, rx_freqs;
enum gsm_band band;
struct dev_band_desc band_desc;
size_t tx_spp, rx_spp;
bool started;
@@ -176,6 +191,8 @@ protected:
uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
bool set_freq(double freq, size_t chan, bool tx);
void get_dev_band_desc(dev_band_desc& desc);
bool set_band(enum gsm_band req_band);
void assign_band_desc(enum gsm_band req_band);
Thread *async_event_thrd;
Mutex tune_lock;

View File

@@ -1,7 +1,7 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(USRP_CFLAGS)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(USRP_CFLAGS)
rev2dir = $(datadir)/usrp/rev2
rev4dir = $(datadir)/usrp/rev4

View File

@@ -174,6 +174,8 @@ private:
/** return minimum Rx Gain **/
double minRxGain(void);
double rssiOffset(size_t chan) { return 0.0f; } /* FIXME: not implemented */
double setPowerAttenuation(int atten, size_t chan);
double getPowerAttenuation(size_t chan=0);

View File

@@ -144,12 +144,8 @@ int makeTransceiver(struct trx_ctx *trx, RadioInterface *radio)
{
VectorFIFO *fifo;
transceiver = new Transceiver(trx->cfg.base_port, trx->cfg.bind_addr,
trx->cfg.remote_addr, trx->cfg.tx_sps,
trx->cfg.rx_sps, trx->cfg.num_chans, GSM::Time(3,0),
radio, trx->cfg.rssi_offset, trx->cfg.stack_size);
if (!transceiver->init(trx->cfg.filler, trx->cfg.rtsc,
trx->cfg.rach_delay, trx->cfg.egprs, trx->cfg.ext_rach)) {
transceiver = new Transceiver(&trx->cfg, GSM::Time(3,0), radio);
if (!transceiver->init()) {
LOG(ALERT) << "Failed to initialize transceiver";
return -1;
}
@@ -181,6 +177,17 @@ static void sig_handler(int signo)
gshutdown = true;
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_trx_ctx, stderr);
talloc_report_full(tall_trx_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_trx_ctx, stderr);
talloc_report_full(tall_trx_ctx, stderr);
@@ -246,10 +253,13 @@ static void setup_signal_handlers()
static void print_help()
{
fprintf(stdout, "Options:\n"
" -h, --help This text\n"
" -C, --config Filename The config file to use\n"
" -V, --version Print the version of OsmoTRX\n"
printf( "Some useful options:\n"
" -h, --help This text\n"
" -C, --config Filename The config file to use\n"
" -V, --version Print the version of OsmoTRX\n"
"\nVTY reference generation:\n"
" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
" --vty-ref-xml Generate the VTY reference XML output and exit.\n"
);
}
@@ -260,16 +270,44 @@ static void print_deprecated(char opt)
<< " All cmd line options are already being overridden by VTY options if set.";
}
static void handle_long_options(const char *prog_name, const int long_option)
{
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
switch (long_option) {
case 1:
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
if (vty_ref_mode < 0) {
fprintf(stderr, "%s: Unknown VTY reference generation "
"mode '%s'\n", prog_name, optarg);
exit(2);
}
break;
case 2:
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
exit(0);
default:
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
exit(2);
}
}
static void handle_options(int argc, char **argv, struct trx_ctx* trx)
{
int option;
unsigned int i;
std::vector<std::string> rx_paths, tx_paths;
bool rx_paths_set = false, tx_paths_set = false;
static int long_option = 0;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"config", 1, 0, 'C'},
{"version", 0, 0, 'V'},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{NULL, 0, 0, 0}
};
@@ -280,6 +318,9 @@ static void handle_options(int argc, char **argv, struct trx_ctx* trx)
print_help();
exit(0);
break;
case 0:
handle_long_options(argv[0], long_option);
break;
case 'a':
print_deprecated(option);
osmo_talloc_replace_string(trx, &trx->cfg.dev_args, optarg);
@@ -346,6 +387,7 @@ static void handle_options(int argc, char **argv, struct trx_ctx* trx)
case 'R':
print_deprecated(option);
trx->cfg.rssi_offset = atof(optarg);
trx->cfg.force_rssi_offset = true;
break;
case 'S':
print_deprecated(option);
@@ -447,6 +489,38 @@ static int set_sched_rr(unsigned int prio)
return 0;
}
static void print_simd_info(void)
{
#ifdef HAVE_SSE3
LOGP(DMAIN, LOGL_INFO, "SSE3 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse3"))
LOGPC(DMAIN, LOGL_INFO, " and supported by CPU\n");
else
LOGPC(DMAIN, LOGL_INFO, ", but not supported by CPU\n");
#else
LOGPC(DMAIN, LOGL_INFO, ", but runtime SIMD detection disabled\n");
#endif
#endif
#ifdef HAVE_SSE4_1
LOGP(DMAIN, LOGL_INFO, "SSE4.1 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse4.1"))
LOGPC(DMAIN, LOGL_INFO, " and supported by CPU\n");
else
LOGPC(DMAIN, LOGL_INFO, ", but not supported by CPU\n");
#else
LOGPC(DMAIN, LOGL_INFO, ", but runtime SIMD detection disabled\n");
#endif
#endif
#ifndef HAVE_ATOMIC_OPS
#pragma message ("Built without atomic operation support. Using Mutex, it may affect performance!")
LOG(NOTICE) << "Built without atomic operation support. Using Mutex, it may affect performance!";
#endif
}
static void print_config(struct trx_ctx *trx)
{
unsigned int i;
@@ -468,8 +542,10 @@ static void print_config(struct trx_ctx *trx)
ost << " Filler Burst TSC........ " << trx->cfg.rtsc << std::endl;
ost << " Filler Burst RACH Delay. " << trx->cfg.rach_delay << std::endl;
ost << " Multi-Carrier........... " << trx->cfg.multi_arfcn << std::endl;
ost << " Tuning offset........... " << trx->cfg.offset << std::endl;
ost << " RSSI to dBm offset...... " << trx->cfg.rssi_offset << std::endl;
ost << " LO freq. offset......... " << trx->cfg.offset << std::endl;
if (trx->cfg.freq_offset_khz != 0)
ost << " Tune freq. offset....... " << trx->cfg.freq_offset_khz << std::endl;
ost << " RSSI to dBm offset...... " << trx->cfg.rssi_offset << (trx->cfg.force_rssi_offset ? "" : " (relative)") << std::endl;
ost << " Swap channels........... " << trx->cfg.swap_channels << std::endl;
ost << " Tx Antennas.............";
for (i = 0; i < trx->cfg.num_chans; i++) {
@@ -554,35 +630,6 @@ int main(int argc, char *argv[])
g_trx_ctx = vty_trx_ctx_alloc(tall_trx_ctx);
#ifdef HAVE_SSE3
printf("Info: SSE3 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse3"))
printf(" and supported by CPU\n");
else
printf(", but not supported by CPU\n");
#else
printf(", but runtime SIMD detection disabled\n");
#endif
#endif
#ifdef HAVE_SSE4_1
printf("Info: SSE4.1 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse4.1"))
printf(" and supported by CPU\n");
else
printf(", but not supported by CPU\n");
#else
printf(", but runtime SIMD detection disabled\n");
#endif
#endif
#ifndef HAVE_ATOMIC_OPS
#pragma message ("Built without atomic operation support. Using Mutex, it may affect performance!")
printf("Built without atomic operation support. Using Mutex, it may affect performance!\n");
#endif
convolve_init();
convert_init();
@@ -629,6 +676,7 @@ int main(int argc, char *argv[])
" but expect your config to break in the future.";
}
print_simd_info();
print_config(g_trx_ctx);
if (trx_validate_config(g_trx_ctx) < 0) {

View File

@@ -69,7 +69,7 @@ bool trxd_send_burst_ind_v0(size_t chan, int fd, const struct trx_ul_burst_ind *
int rc;
/* v0 doesn't support idle frames, they are simply dropped, not sent */
if(bi->idle)
if (bi->idle)
return true;
/* +2: Historically (OpenBTS times), two extra non-used bytes are sent appended to each burst */

View File

@@ -322,6 +322,11 @@ double RadioInterface::setRxGain(double dB, size_t chan)
return mDevice->setRxGain(dB, chan);
}
double RadioInterface::rssiOffset(size_t chan)
{
return mDevice->rssiOffset(chan);
}
/* Receive a timestamped chunk from the device */
int RadioInterface::pullBuffer()
{

View File

@@ -109,6 +109,9 @@ public:
/** set receive gain */
virtual double setRxGain(double dB, size_t chan = 0);
/** return base RSSI offset to apply for received samples **/
virtual double rssiOffset(size_t chan = 0);
/** drive transmission of GSM bursts */
void driveTransmitRadio(std::vector<signalVector *> &bursts,
std::vector<bool> &zeros);
@@ -190,4 +193,5 @@ public:
bool tuneTx(double freq, size_t chan);
bool tuneRx(double freq, size_t chan);
virtual double setRxGain(double dB, size_t chan);
virtual double rssiOffset(size_t chan = 0);
};

View File

@@ -38,6 +38,7 @@ extern "C" {
/* Universal resampling parameters */
#define NUMCHUNKS 24
/* number of narrow-band virtual ARFCNs in this wide-band multi-ARFCN device */
#define MCHANS 4
RadioInterfaceMulti::RadioInterfaceMulti(RadioDevice *radio, size_t tx_sps,
@@ -69,6 +70,10 @@ void RadioInterfaceMulti::close()
channelizer = NULL;
synthesis = NULL;
for (std::vector<signalVector*>::iterator it = history.begin(); it != history.end(); ++it)
delete *it;
mReceiveFIFO.resize(0);
powerScaling.resize(0);
history.resize(0);
@@ -79,6 +84,10 @@ void RadioInterfaceMulti::close()
RadioInterface::close();
}
/*! we re-map the physical channels from the filter bank to logical per-TRX channels
* \param[in] pchan physical channel number within the channelizer
* \param[in] chans total number of narrow-band ARFCN channels
* \returns logical (TRX) channel number, or -1 in case there is none */
static int getLogicalChan(size_t pchan, size_t chans)
{
switch (chans) {
@@ -113,6 +122,9 @@ static int getLogicalChan(size_t pchan, size_t chans)
return -1;
}
/*! do we need to frequency shift our spectrum or not?
* \param chans total number of channels
* \returns 1 if we need to shift; 0 if not; -1 on error */
static int getFreqShift(size_t chans)
{
switch (chans) {
@@ -154,6 +166,7 @@ bool RadioInterfaceMulti::init(int type)
tx_freq_state.resize(mChans);
active.resize(MCHANS, false);
/* 4 == sps */
inchunk = RESAMP_INRATE * 4;
outchunk = RESAMP_OUTRATE * 4;
@@ -431,14 +444,18 @@ bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
double RadioInterfaceMulti::setRxGain(double db, size_t chan)
{
if (chan == 0)
return mDevice->setRxGain(db);
else
return mDevice->getRxGain();
if (chan == 0)
return mDevice->setRxGain(db);
else
return mDevice->getRxGain();
}
double RadioInterfaceMulti::rssiOffset(size_t chan)
{
return mDevice->rssiOffset(0);
}
int RadioInterfaceMulti::setPowerAttenuation(int atten, size_t chan)
{
return RadioInterface::setPowerAttenuation(atten, 0);
return RadioInterface::setPowerAttenuation(atten, 0);
}

View File

@@ -1792,15 +1792,15 @@ static SoftVector *signalToSoftVector(signalVector *dec)
* stages.
*/
static signalVector *demodCommon(const signalVector &burst, int sps,
complex chan, float toa)
const struct estim_burst_params *ebp)
{
signalVector *delay, *dec;
if ((sps != 1) && (sps != 4))
return NULL;
delay = delayVector(&burst, NULL, -toa * (float) sps);
scaleVector(*delay, (complex) 1.0 / chan);
delay = delayVector(&burst, NULL, -ebp->toa * (float) sps);
scaleVector(*delay, (complex) 1.0 / ebp->amp);
if (sps == 1)
return delay;
@@ -1816,13 +1816,13 @@ static signalVector *demodCommon(const signalVector &burst, int sps,
* 4 SPS (if activated) to minimize distortion through the fractional
* delay filters. Symbol rotation and after always operates at 1 SPS.
*/
static SoftVector *demodGmskBurst(const signalVector &rxBurst,
int sps, complex channel, float TOA)
static SoftVector *demodGmskBurst(const signalVector &rxBurst, int sps,
const struct estim_burst_params *ebp)
{
SoftVector *bits;
signalVector *dec;
dec = demodCommon(rxBurst, sps, channel, TOA);
dec = demodCommon(rxBurst, sps, ebp);
if (!dec)
return NULL;
@@ -1835,6 +1835,27 @@ static SoftVector *demodGmskBurst(const signalVector &rxBurst,
return bits;
}
static float computeEdgeCI(const signalVector *rot)
{
float err_pwr = 0.0f;
float step = 2.0f * M_PI_F / 8.0f;
for (size_t i = 8; i < rot->size() - 8; i++) {
/* Compute the ideal symbol */
complex sym = (*rot)[i];
float phase = step * roundf(sym.arg() / step);
complex ideal = complex(cos(phase), sin(phase));
/* Compute the error vector */
complex err = ideal - sym;
/* Accumulate power */
err_pwr += err.norm2();
}
return 3.0103f * log2f(1.0f * (rot->size() - 16) / err_pwr);
}
/*
* Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
* 4 SPS (if activated) to minimize distortion through the fractional
@@ -1845,19 +1866,20 @@ static SoftVector *demodGmskBurst(const signalVector &rxBurst,
* through the fractional delay filters at 1 SPS renders signal
* nearly unrecoverable.
*/
static SoftVector *demodEdgeBurst(const signalVector &burst,
int sps, complex chan, float toa)
static SoftVector *demodEdgeBurst(const signalVector &burst, int sps,
struct estim_burst_params *ebp)
{
SoftVector *bits;
signalVector *dec, *rot, *eq;
dec = demodCommon(burst, sps, chan, toa);
dec = demodCommon(burst, sps, ebp);
if (!dec)
return NULL;
/* Equalize and derotate */
eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
rot = derotateEdgeBurst(*eq, 1);
ebp->ci = computeEdgeCI(rot);
/* Soft slice and normalize */
bits = softSliceEdgeBurst(*rot);
@@ -1869,13 +1891,13 @@ static SoftVector *demodEdgeBurst(const signalVector &burst,
return bits;
}
SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
float toa, CorrType type)
SoftVector *demodAnyBurst(const signalVector &burst, CorrType type,
int sps, struct estim_burst_params *ebp)
{
if (type == EDGE)
return demodEdgeBurst(burst, sps, amp, toa);
return demodEdgeBurst(burst, sps, ebp);
else
return demodGmskBurst(burst, sps, amp, toa);
return demodGmskBurst(burst, sps, ebp);
}
bool sigProcLibSetup()

View File

@@ -134,7 +134,7 @@ int detectAnyBurst(const signalVector &burst,
struct estim_burst_params *ebp);
/** Demodulate burst basde on type and output soft bits */
SoftVector *demodAnyBurst(const signalVector &burst, int sps,
complex amp, float toa, CorrType type);
SoftVector *demodAnyBurst(const signalVector &burst, CorrType type,
int sps, struct estim_burst_params *ebp);
#endif /* SIGPROCLIB_H */

View File

@@ -34,6 +34,8 @@ AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign subdir-objects])
CFLAGS="$CFLAGS -std=gnu11"
dnl Linux kernel KBuild style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -80,19 +82,10 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
# Check if gettid is available (despite not being documented in glibc doc, it requires __USE_GNU on some systems)
# C compiler is used since __USE_GNU seems to be always defined for g++.
save_CPPFLAGS=$CPPFLAGS
AC_LANG_PUSH(C)
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
AC_CHECK_FUNCS([gettid])
AC_LANG_POP(C)
CPPFLAGS=$save_CPPFLAGS
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.5.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
@@ -184,7 +177,7 @@ AS_IF([test "x$with_lms" = "xyes"], [
PKG_CHECK_MODULES(LMS, LimeSuite)
])
AS_IF([test "x$with_uhd" != "xno"],[
AS_IF([test "x$with_uhd" = "xyes"],[
PKG_CHECK_MODULES(UHD, uhd >= 003.011,
[AC_DEFINE(USE_UHD_3_11, 1, UHD version 3.11.0 or higher)],
[PKG_CHECK_MODULES(UHD, uhd >= 003.009,
@@ -243,7 +236,7 @@ AS_IF([test "x$osmo_cv_cc_has___sync_fetch_and_and" = "xyes" && test "x$osmo_cv_
AC_DEFINE(HAVE_ATOMIC_OPS, 1, [Support all required atomic operations], [AC_MSG_WARN("At least one aotmic operation missing, will use mutex")])
])
AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" != "xno"])
AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" = "xyes"])
AM_CONDITIONAL(DEVICE_USRP1, [test "x$with_usrp1" = "xyes"])
AM_CONDITIONAL(DEVICE_LMS, [test "x$with_lms" = "xyes"])
AM_CONDITIONAL(DEVICE_IPC, [test "x$with_ipc" = "xyes"])

View File

@@ -85,11 +85,10 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
export PATH="$inst/bin:$PATH"
CONFIG="--enable-sanitize --enable-werror --with-uhd --with-usrp1 --with-lms $INSTR"
CONFIG="--enable-sanitize --enable-werror --with-uhd --with-usrp1 --with-lms --with-ipc $INSTR"
# Additional configure options and depends
if [ "$WITH_MANUALS" = "1" ]; then
osmo-build-dep.sh osmo-gsm-manuals
CONFIG="$CONFIG --enable-manuals"
fi
@@ -107,12 +106,18 @@ autoreconf --install --force
$MAKE $PARALLEL_MAKE
$MAKE check \
|| cat-testlogs.sh
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE distcheck \
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE maintainer-clean
$MAKE $PARALLEL_MAKE maintainer-clean
# Verify distro-specific package patches apply:
for patch in debian/patches/*.patch; do
patch --dry-run -p1 < "$patch"
done
osmo-clean-workspace.sh

View File

@@ -34,10 +34,10 @@ BuildRequires: pkgconfig(LimeSuite)
BuildRequires: pkgconfig(usrp) >= 3.3
%endif
BuildRequires: pkgconfig(fftw3f)
BuildRequires: pkgconfig(libosmocoding) >= 1.3.0
BuildRequires: pkgconfig(libosmocore) >= 0.12.0
BuildRequires: pkgconfig(libosmoctrl) >= 0.12.0
BuildRequires: pkgconfig(libosmovty) >= 0.12.0
BuildRequires: pkgconfig(libosmocoding) >= 1.5.0
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
BuildRequires: pkgconfig(libusb-1.0)
BuildRequires: pkgconfig(uhd)
%{?systemd_requires}
@@ -149,6 +149,16 @@ connect mobile phones to the mobile network.
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
%package ipc-test
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (IPC) driver test utility
Group: Productivity/Telephony/Servers
%description ipc-test
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:
This package include the test tools for osmo-trx-ipc
%prep
%setup -q
@@ -234,9 +244,11 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files ipc
%{_bindir}/osmo-trx-ipc
%{_bindir}/ipc-driver-test
%dir %{_sysconfdir}/osmocom
# FIXME: missing: osmo-trx-ipc.cfg
%config(noreplace) %{_sysconfdir}/osmocom/osmo-trx-ipc.cfg
%{_unitdir}/osmo-trx-ipc.service
%files ipc-test
%{_bindir}/ipc-driver-test
%changelog

154
debian/changelog vendored
View File

@@ -1,3 +1,157 @@
osmo-trx (1.3.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* Make logging category DLMS generic and reusable for other backends
* uhd: Use DEVDRV log category and support UHD >=3.11 logging framework
* uhd: Improve some logging lines printing UHD pretty-print output
* doc: clarify number of channels on B210 with multi-arfcn enabled
* radioInterfaceMulti: Fail to tune on freq not following multi-arfcn restrictions
* doc: Update vty reference xml file
* lms: Move initialization of field started to constructor
* lms: Drop unused define
* smpl_buf: Fix str_code() param and print unknown error val
* lms: Improve smpl_buf error logging
* lms: Change radioDevice constructor arg name to avoid masking instance attr
* lms: Make reference to std::vector unambiguous
* lms: Move rx_buffers allocation to constructor
* lms: Store device type specific parameters in one place
* lms: Make ts_offset and smpl rate coefs device-specific
* lms: Initial multi-arfcn support
* contrib/jenkins.sh: Reorder sanity checks
* debug.h: Avoid printing pthread_t type
* debug.h: Fix print format of chan in CLOGCHAN
* cosmetic: fix several typos found by codespell
* radioDevice: Drop unused RSSI param from readSamples API
* radioDevice: Drop unused isControl param from WriteSamples API
* Use OSMO_FD_READ instead of deprecated BSC_FD_READ
* Transceiver: Fix extra space in RSP NOISELEV error
* Transceiver: Implement TRXC cmd NOMTXPOWER
* UHDDevice: Implement getNominalTxPower() based on TxFrequency
* radioInterface: Operate on real Tx power attenuation rather than on device specific gains
* UHDDevice: Compute TxGain on UHD API based on expected Tx output power
* proto_trxd: Fix UndefinedBehaviorSanitizer from ubsan
* Transceiver: Allow sending negative nominal tx power in RSP NOMTXPOWER
* LMSDevice: Compute TxGain on LimeSuite API based on expected Tx output power
* Drop old TxGain APIs from parent radioDevice abstract class
* {UHD,LMS}Dervice: Log expected resulting TxPower when setting device specific TxGain
* cosmetic: trx_rate_ctr: Fix whitespace
* trx_rate_ctr: Fix immediate rescheduling on per-sec thresholds
* Rename device specific rate counter multi-thread helpers
* Introduce rate counter tx_stale_bursts
* TransceiverState: Initialize ctrs field in constructor
* doc/manuals: Update thread documentation after dropping CTRL sock threads
* trx_rate_ctr: Fix locking wrong mutex
* Introduce rate counters to detect issues in received Dl bursts from TRXD
* Transceiver: Fix race condition obtaining Dl burst from Upper layer
* Add rate counter for missing Txbursts when scheduled towards the radioInterface
* Transceiver: Provide initial value for TransceiverState::mFiller in constructor
* Transceiver: Use already obtained value from Rx msg structure
* Transceiver: Restrict conditions where FN gaps are detected
* trx_rate_ctr: Lower some log levels
* Introduce CTR log category
* Transceiver: Lower some log levels which have an associated counter
* Transceiver: Check log level before generating burst str representation
* Transceiver: Add several rate_ctr for rx error conditions
* Use new libosmovty cpu sched config features
* debian: Update debian8 osmo-trx specific patch
* jenkins.sh: Verify distro-specific patches apply
* ipc: fix var declaration in for loop
* Add support for TRXC MUTE command
* arch: x86: Fix convolve optimizations breaking signal
* contrib/jenkins: Enable parallel make in make distcheck
* Transceiver: Pass config struct instead of large list of params
* Calculate RSSI offset based on RxGain configuration
* main: generate coredump and exit upon SIGABRT received
* ipc: Fix wrong reference to BTS in log line
* ipc-driver-test: Allow setting dir prefix for UD socket
* radioInterfaceMulti: Fix memory leak upon close()
* ChannelizerBase: Fix memory leak
* Threads.cpp: Use already existing gettid wrapper function
* Replace my_gettid with libosmocore osmo_gettid API
* tests: Explicitly drop category from log
* tests: Replace deprecated API log_set_print_filename
[ Philipp Maier ]
* debug: use LOGL_NOTICE for log category DDEV
* doc: do not set the base-port of the trx
* doc: apply an rssi-offset of 28 by default.
* doc: switch log levels to notice
* Transceiver: Log when sending of CLK indications begins
* vty: add attributes to VTY commands indicating when they apply
* osmo-trx: add commandline option --vty-ref-xml
[ Eric ]
* configure.ac: fix libtool issue with clang and sanitizer
* transceiver: check the right vector
* transceiver: get rid of the ctrl threads
* add kernel style .clang-format with 120 chars per line limit
* devices: reset internal smart sample buffers upon stop
* transceiver: optimize code if optimizations are enabled
* transceiver: initialize reorder flag so we don't miscount
[ Harald Welte ]
* PRBS tool sending PRBS sequence to TRX
* prbs-tool: Add error simulation capabilities
* utils: Ensure content of this directory is included in 'make dist'
* prbs-tool: Don't require C99
* RPM spec file: Require uhd-firmware for osmo-trx-uhd
* osmo-trx.spec.in: Use %config(noreplace) to retain current config file
* Fix build on Debian8
* [cosmetic] radioInterfaceMulti: More comments
* [cosmetic] radioIntefaceMulti: Fix whitespace / indent
* ipc: Use OSMO_FD_* instead of deprecated BSC_FD_*
* Use osmo_fd_setup() wherever applicable
* Use osmo_fd_*_{disable,enable}
* README update
* manual: Fix typo OsmTRX -> OsmoTRX
[ Oliver Smith ]
* contrib: import RPM spec
* contrib: integrate RPM spec
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
* contrib/jenkins: don't build osmo-gsm-manuals
* configure.ac: set -std=gnu11
[ Vadim Yanitskiy ]
* UHDDevice: catch LookupError/IndexError in set{Rx,Tx}Antenna()
* debian/control: change maintainer to the Osmocom team / mailing list
* proto_trxd: cosmetic: 'if' is not a function, add space
* vty: add multi-ARFCN specific warning for chan N > 0
* radioDevice: fix set_antennas(): consider MULTI_ARFCN mode
* device/lms: fix: 'trx_vty.h' header requires C linkage
* device/lms: fix missing semicolon in LMSDevice::assign_band_desc()
* device/lms: get rid of 'using namespace std'
* device/common/Makefile.am: remove $(LMS_CFLAGS) from AM_CXXFLAGS
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
* device: drop unreasonable LIBOSMO{CTRL,VTY}_{CFLAGS,LIBS}
* Transceiver: use size_t and ARRAY_SIZE() in constructor
* Transceiver: explicitly init m{Rx,Tx}LowerLoopThread
* vty: fix documentation for 'swap-channels (disable|enable)'
* vty: fix documentation for 'egprs (disable|enable)'
* vty: fix documentation for 'rx-sps (1|4)' and 'tx-sps (1|4)'
* vty: cosmetic: use VTY_IPV4_CMD in 'bind-ip' / 'remote-ip'
* vty: fix documentation for 'multi-arfcn (disable|enable)'
* vty: remove groundless statement about filler type 'dummy'
* vty: auto-generate cmd and doc strings for cfg_filler_type_cmd
* vty: fix documentation for 'ext-rach (disable|enable)'
* main: use logging API to print SIMD info instead of printf()
* doc/manuals: generate XML VTY reference at build-time
* vty: fix swapped documentation for 'filler type' command
* Transceiver: fix integer division in addRadioVector()
* Transceiver: use proper factor for amplitude scaling
* Add a (hidden) VTY parameter for Rx/Tx freq. shifting
[ Eric Wild ]
* osmo-trx-ipc
[ Alexander Couzens ]
* osmo-trx.spec: move ipc-driver-test into package ipc-test
[ Sylvain Munaut ]
* sigProcLib: fix C/I computation for 8-PSK modulated bursts
-- Pau Espin Pedrol <pespin@espeweb.net> Tue, 23 Feb 2021 14:27:15 +0100
osmo-trx (1.2.0) unstable; urgency=medium
[ Pau Espin Pedrol ]

23
debian/control vendored
View File

@@ -14,7 +14,7 @@ Build-Depends: debhelper (>= 9),
libtalloc-dev,
libusrp-dev,
liblimesuite-dev,
libosmocore-dev (>= 1.3.0),
libosmocore-dev (>= 1.5.0),
osmo-gsm-manuals-dev
Standards-Version: 3.9.6
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
@@ -30,7 +30,7 @@ Package: osmo-trx-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), ${misc:Depends}
Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), osmo-trx-ipc (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the osmo-trx-*
Make debugging possible
@@ -91,6 +91,25 @@ Description: SDR transceiver that implements Layer 1 of a GSM BTS (LimeSuite)
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-ipc
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SDR transceiver that implements Layer 1 of a GSM BTS (generic IPC)
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:
.
TS 05.01 "Physical layer on the radio path"
TS 05.02 "Multiplexing and Multiple Access on the Radio Path"
TS 05.04 "Modulation"
TS 05.10 "Radio subsystem synchronization"
.
In this context, BTS is "Base transceiver station". It's the stations that
connect mobile phones to the mobile network.
.
3GPP is the "3rd Generation Partnership Project" which is the collaboration
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-doc
Architecture: all
Section: doc

4
debian/osmo-trx-ipc.install vendored Normal file
View File

@@ -0,0 +1,4 @@
etc/osmocom/osmo-trx-ipc.cfg
lib/systemd/system/osmo-trx-ipc.service
/usr/bin/osmo-trx-ipc
/usr/share/doc/osmo-trx/examples/osmo-trx-ipc/osmo-trx-ipc.cfg /usr/share/doc/osmo-trx/examples/osmo-trx-ipc/

View File

@@ -1,5 +1,5 @@
diff --git a/debian/control b/debian/control
index 8ff59f0..126c16a 100644
index 12d9af5..27b9d60 100644
--- a/debian/control
+++ b/debian/control
@@ -13,7 +13,6 @@ Build-Depends: debhelper (>= 9),
@@ -7,15 +7,15 @@ index 8ff59f0..126c16a 100644
libtalloc-dev,
libusrp-dev,
- liblimesuite-dev,
libosmocore-dev (>= 1.3.0),
libosmocore-dev (>= 1.5.0),
osmo-gsm-manuals-dev
Standards-Version: 3.9.6
@@ -30,7 +29,7 @@ Package: osmo-trx-dbg
Architecture: any
Section: debug
Priority: extra
-Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), ${misc:Depends}
+Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), ${misc:Depends}
-Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), osmo-trx-ipc (= ${binary:Version}), ${misc:Depends}
+Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-ipc (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the osmo-trx-*
Make debugging possible
@@ -42,19 +42,19 @@ index 8ff59f0..126c16a 100644
- between different telecommunication associations for developing new
- generations of mobile phone networks. (post-2G/GSM)
-
Package: osmo-trx-doc
Architecture: all
Section: doc
Package: osmo-trx-ipc
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
diff --git a/debian/rules b/debian/rules
index 627c0c8..d9285e2 100755
index 5795643..5937c17 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,7 +9,7 @@ override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
override_dh_auto_configure:
- dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
+ dh_auto_configure -- --with-uhd --with-usrp1 --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
- dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-ipc --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
+ dh_auto_configure -- --with-uhd --with-usrp1 --with-ipc --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
override_dh_strip:
dh_strip --dbg-package=osmo-trx-dbg

2
debian/rules vendored
View File

@@ -9,7 +9,7 @@ override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
override_dh_auto_configure:
dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-ipc --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
override_dh_strip:
dh_strip --dbg-package=osmo-trx-dbg

View File

@@ -14,6 +14,10 @@ if DEVICE_LMS
OSMOCONF_FILES += osmo-trx-lms/osmo-trx-lms.cfg
endif
if DEVICE_IPC
OSMOCONF_FILES += osmo-trx-ipc/osmo-trx-ipc.cfg
endif
osmoconf_DATA = $(OSMOCONF_FILES)
EXTRA_DIST = $(OSMOCONF_FILES)

View File

@@ -0,0 +1,32 @@
log stderr
logging filter all 1
logging color 1
logging print category 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty
no login
!
cpu-sched
policy rr 18
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
! 28 dB offset below is valid only for the B2xx in 1800 MHz band, see
! https://osmocom.org/issues/4468 for more details
rssi-offset 28.000000
tx-sps 4
rx-sps 4
clock-ref external
egprs disable
ext-rach disable
dev-args ipc_msock=/tmp/ipc_sock0
multi-arfcn disable
chan 0
tx-path TX/RX
rx-path RX2
chan 1
tx-path TX/RX
rx-path RX2

View File

@@ -15,9 +15,6 @@ trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
egprs disable
! 28 dB offset below is valid only for the B2xx in 1800 MHz band, see
! https://osmocom.org/issues/4468 for more details
rssi-offset 28.000000
tx-sps 4
rx-sps 4
clock-ref external

View File

@@ -1,6 +1,5 @@
EXTRA_DIST = osmotrx-usermanual.adoc \
osmotrx-usermanual-docinfo.xml \
osmotrx-vty-reference.xml \
chapters \
vty
@@ -9,8 +8,24 @@ if BUILD_MANUALS
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
VTY_REFERENCE = osmotrx-vty-reference.xml
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
VARIANTS = $(NULL)
if DEVICE_UHD
VARIANTS += uhd
endif
if DEVICE_USRP1
VARIANTS += usrp1
endif
if DEVICE_LMS
VARIANTS += lms
endif
if DEVICE_IPC
VARIANTS += ipc
endif
# This is a significantly modified, multi-target adopted copy of
# $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
include $(srcdir)/vty/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-trx
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc

View File

@@ -1,4 +1,4 @@
== Configuring OsmTRX
== Configuring OsmoTRX
OsmoTRX will read the configuration at startup time and configure the
transceiver accordingly after validating the configuration.

View File

@@ -0,0 +1,37 @@
DOCBOOKS = $(foreach v,$(VARIANTS),vty/osmotrx-$(v)-vty-reference.xml)
DOCBOOKS_DEPS = $(DOCBOOKS) $(addsuffix .inc,$(DOCBOOKS))
INC_DIR = $(abspath $(builddir)/vty)
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.docbook.inc
CLEAN_FILES += $(DOCBOOKS_DEPS)
CLEAN_FILES += $(addsuffix .inc.gen,$(DOCBOOKS))
CLEAN_FILES += $(addsuffix .inc.merged,$(DOCBOOKS))
$(INC_DIR):
mkdir -p $@
vty/osmotrx-%-vty-reference.xml: $(top_builddir)/Transceiver52M/osmo-trx-% $(INC_DIR)
sed -e "s|@@GENERATED@@|$@.inc|" \
-e "s|@@VARIANT@@|$(notdir $<)|" \
-e "s|@@REV_NUMBER@@|$(VERSION)|" \
-e "s|@@REV_DATE@@|$(shell date +"%dth %B %Y")|" \
-e "s|@@CR_YEAR@@|$(shell date +"%Y")|" \
$(srcdir)/vty/osmotrx-vty-reference.xml > $@
vty/osmotrx-%-vty-reference.xml.inc: $(top_builddir)/Transceiver52M/osmo-trx-% \
$(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
$(OSMO_GSM_MANUALS_DIR)/common/chapters/vty.xml \
$(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl \
$(srcdir)/vty/*.xml $(INC_DIR)
# a) Invoke osmo-trx-% to generate the list of commands first
$< --vty-ref-mode default --vty-ref-xml > "$@.gen"
# ... filter garbage potentially printed by libraries to stdout
sed -i '/^<vtydoc/,$$!d' "$@.gen"
# b) Merge the result of a) with global and local additions
$(OSMO_GSM_MANUALS_DIR)/build/vty_reference_combine.sh \
$(realpath $(OSMO_GSM_MANUALS_DIR)/merge_doc.xsl) "$@.gen" \
$(OSMO_GSM_MANUALS_DIR)/common/vty_additions.xml \
$(srcdir)/vty/*additions*.xml > "$@.merged"
# c) Convert the result of b) into a valid docbook
xsltproc $(OSMO_GSM_MANUALS_DIR)/vty_reference.xsl "$@.merged" > $@

View File

@@ -6,7 +6,7 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
<!ENTITY sections-vty SYSTEM "generated/docbook_vty.xml" >
<!ENTITY sections-vty SYSTEM "@@GENERATED@@" >
]>
<book>
@@ -18,12 +18,19 @@
<authorinitials>pe</authorinitials>
<revremark>Initial</revremark>
</revision>
<revision>
<revnumber>v2</revnumber>
<date>@@REV_DATE@@</date>
<authorinitials>s.f.m.c.</authorinitials>
<revremark>Automatic build (@@REV_NUMBER@@)</revremark>
</revision>
</revhistory>
<title>OsmoTRX VTY Reference</title>
<subtitle>@@VARIANT@@</subtitle>
<copyright>
<year>2018</year>
<year>@@CR_YEAR@@</year>
</copyright>
<legalnotice>

File diff suppressed because it is too large Load Diff

View File

@@ -59,8 +59,10 @@ int main(int argc, char *argv[])
osmo_init_logging2(tall_ctx, &linfo);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_filename(osmo_stderr_target, 0);
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
log_set_print_level(osmo_stderr_target, 1);
log_set_print_category(osmo_stderr_target, 0);
log_set_print_category_hex(osmo_stderr_target, 0);
Log(MYCAT, LOGL_FATAL, __BASE_FILE__, __LINE__).get() << "testing the logger.";
Log(MYCAT, LOGL_ERROR, __BASE_FILE__, __LINE__).get() << "testing the logger.";