Compare commits

...

457 Commits

Author SHA1 Message Date
Oliver Smith
7cc7e3de99 contrib/osmo-trx.spec.in: add osmo-trx-ipc
Change-Id: Ib57980e8e102d6f77d0bffa47faafd929c82a288
2020-05-27 14:10:04 +02:00
Oliver Smith
0f00e676f2 contrib/systemd/osmo-trx-ipc.service: new file
Change-Id: Ic2ba7616c6909bd0a7e642554ecffa4939935b01
2020-05-27 14:00:05 +02:00
Oliver Smith
8b9ec56e5d IPCDevice.h: remove limesuite include
Change-Id: I3808dcc69dd3ccc8372852c622660b7056c1be8a
2020-05-27 14:00:05 +02:00
Oliver Smith
106347dc31 configure.ac: add --with-ipc
Change-Id: Ie7b1b07479b81366cebaa081d80917ae868992b4
2020-05-27 14:00:05 +02:00
Oliver Smith
14ee5eacb5 gitignore: add new binaries
Change-Id: I9fd0b6cdb0b9d66b37e813cc8d35a28b9c9dc539
2020-05-27 14:00:05 +02:00
Eric
803a90028c ipc: add master socket number/path parameters
osmo-trx-ipc needs to know which master socket it should talk to, so
pass this path in the config device args like this:
dev-args ipc_msock=/path/to/socket

Additionally, add a master socket suffix number parameter to the ipc
backend,
ipc-driver-test -n 0 to start serving /tmp/ipc_sock0

Change-Id: I24857fbb74e5fc808b2a218957c723291de2ba04
2020-05-27 14:00:05 +02:00
Eric
bd8ca9f95e shm: fix alignment
Change-Id: I8b593d792a992973e76dd19f7b678c9caa9c5e16
2020-05-27 14:00:05 +02:00
Eric
aec2c35861 ipc: gain setting
Change-Id: I674d51fdcab2691853681f661b441364ed75207a
2020-05-27 14:00:05 +02:00
Eric
c53a7fb4f4 ipc: make ipc server uhd output more verbose
Change-Id: I9f2c15adff96e71a806ef09f17152c11d7c043aa
2020-05-27 14:00:05 +02:00
Eric
420e5f6112 ipc: print received path delay value
Change-Id: Ib072b01451084e055882d2867b558a5f8ede95ea
2020-05-27 14:00:05 +02:00
Eric
453c32c091 ipc: adjust over/underflow reporting
Change-Id: Iec2ca94ed8b6cf96d8797540cff43af6542e6437
2020-05-27 14:00:05 +02:00
Eric
c3299d945a ipc: remove intermediate class used for debugging
Change-Id: I2e8a93389cf2f6fc0b9a591f800c019427cf37e6
2020-05-27 14:00:05 +02:00
Eric
ac037980d7 ipc: update the licenses
Change-Id: If523884e76166c11e88944bb7633ff3b54a3a88b
2020-05-27 14:00:05 +02:00
Eric
ebc9e07476 v1
Change-Id: I057e272623b41421f442206f550bcc8c60f4a747
2020-05-27 14:00:05 +02:00
Eric
58425b9653 scaling val
Change-Id: I6ddfd792ea42655e12fae0b195e362c98792b96f
2020-05-27 14:00:05 +02:00
Eric
b36c69d102 add kernel style .clang-format with 120 chars per line limit
Change-Id: I1dc6610d7adfa1a52f3d41ad04544806c2be2c39
2020-05-27 14:00:05 +02:00
Eric
4d2e2a9e83 spawn the client as a thread
Change-Id: I86cd659e74ebdbf43c4352e83e5adb78f8fe6de5
2020-05-27 14:00:05 +02:00
Eric
3eede6b455 silence warnings
Change-Id: I01b2dce8e04cdc21872e5bbc3eec7e0a5e3d1b0b
2020-05-27 14:00:05 +02:00
Eric
3b35c447e1 no undefined behavior by adding/substracting values != 0 from null ptr
Change-Id: Id2dc21e884991b3cca9f617aece12ac35959c1b2
2020-05-27 14:00:05 +02:00
Eric
162ea392c3 shm: fix warnings
Change-Id: I0e56539f699c39ab6e3546c96973184552da4d5f
2020-05-27 14:00:05 +02:00
Eric
036b85e85a ipc: fix shm size calculation
Total size was previously only as large as sizeof(struct
ipc_shm_raw_stream) + sizeof(uint32_t)*num_buffers....

Change-Id: I1205b56a4b11bdf32fbdbfb82b67da36965a7981
2020-05-27 14:00:05 +02:00
Pau Espin Pedrol
9eff30845b WIP: comments
Change-Id: Ia2631a869e23af520b9eade192dfdb032174c689
2020-05-27 14:00:05 +02:00
Pau Espin Pedrol
cf66e6a45e WIP: osmo-trx-ipc
Change-Id: Ice63d3499026293ade8aad675ff7a883bcdd5756
2020-05-27 14:00:05 +02:00
Philipp Maier
fdefbfac39 Transceiver: Log when sending of CLK indications begins
When the logging category TRXCLK is set to info osmo-trx prints a
logline that informs about the sending of clock indications. In practice
this those log lines are often used to identify that osmo-trx and
osmo-bts are running properly, so it would be helpful, even in
productive use, if there would be an information in the log that the
sending of clock indications has begun. However, the regular printing of
the clock indication log line would soon flood the log. So, lets have an
addional log line that logs only once when the transceiver starts and
quickly informs at loglevel NOTICE that clock indications are now sent.

Change-Id: I6aa88943b76c9a2bf7aed60d6a3d325c1f27820a
Related: OS#2577
2020-05-26 22:49:02 +02:00
Philipp Maier
5e16f79f0f doc: switch log levels to notice
Some of the example configs have loglevels set to info. This is too
verbose, lets make sure all loglevels are set to notice

Change-Id: Ief82b85d9ff0e0e94eaabd255ebea961396fff32
2020-05-23 11:50:47 +00:00
Oliver Smith
f3155e33b9 Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
Change-Id: Ie192c9b516ff98f2b1ab8e7927da55a0c1e9eb56
2020-05-22 13:48:11 +02:00
Oliver Smith
7bbe19ee9d contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to @VERSION@, make it build
with CentOS 8 etc.

Disable lms, usrp1 for CentOS 8.

Related: OS#4550
Change-Id: Ie27fcc4f9033f0049507d9dcc295541ac0744c73
2020-05-19 17:05:30 +02:00
Oliver Smith
f669bf43e7 contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: I694fcd888778ab68d13165f4d0bf65e5d6870fb4
2020-05-19 17:04:19 +02:00
Pau Espin Pedrol
4a575b02b5 Use OSMO_FD_READ instead of deprecated BSC_FD_READ
New define is available since libosmocore 1.1.0, and we already require
1.3.0, so no need to update dependenices.
Let's change it to avoid people re-using old BSC_FD_READ symbol when
copy-pasting somewhere else.

Change-Id: I868baf575b77c448b3115701e70d439de89b0fb3
2020-05-09 18:54:20 +02:00
Harald Welte
cf35c37c94 prbs-tool: Don't require C99
from a Debian8 build:

[  256s] prbs-tool.c: In function 'apply_errors_prbs':
[  256s] prbs-tool.c:190:2: error: 'for' loop initial declarations are only allowed in C99 or C11 mode
[  256s]   for (int i = 0; i < sizeof(pchan->prbs_u)-4; i++) {
[  256s]   ^

Change-Id: I8541fce50405525efffb12210a269e0ab8a687ab
2020-05-07 23:55:56 +02:00
Harald Welte
6e369348b0 utils: Ensure content of this directory is included in 'make dist'
The python + matlab should be part of every source release

Change-Id: I9814a9a352dbee03177ef9e8dfd19bc2baf0ca07
2020-05-02 22:34:27 +02:00
Harald Welte
546516d79c prbs-tool: Add error simulation capabilities
The tool can now simulate:
* lost bursts on the TRX->BTS interface
* zeroed/overwritten bursts on the TRX->BTS interface
* errors in the TCH codec frames before passing them to the encoder

Change-Id: I0b52c2af6d973669ac233bf9868400e497496460
TODO: Ability to introduce errors in certain classes of the bits only.
2020-05-02 22:32:51 +02:00
Harald Welte
6879bb0db9 PRBS tool sending PRBS sequence to TRX
Change-Id: I2300f909bbfda10a7053320edfd1deaea763759a
2020-05-02 22:32:34 +02:00
Eric
a7143bf7a1 transceiver: get rid of the ctrl threads
There is no need to have n threads handle n ctrl sockets, since they all
will immediately respond to commands, so handle them from the existing
main osmo select loop.

Care must be taken to ensure that calls from within the command handler
do not block, or at least don't block too long, which currently is the
case.

Change-Id: I642a34451e1825eafecf71a902df916ccee7944c
2020-04-14 19:10:51 +00:00
Philipp Maier
4ffdca10d4 doc: apply an rssi-offset of 28 by default.
Set an rssi offset of 28 in the example configs to make sure that the
power control loop gets RSSI values that match at least half way the
reality when the 1800 Mhz band is used. For other bands the value will
be different (See also related osmocom ticket)

Change-Id: I62725fe454f54e2c7cb7550dadb1e6fc94337d78
Related: OS#4468
2020-04-14 17:16:23 +00:00
Eric
1a26b4f085 transceiver: check the right vector
Change-Id: I03800ae094c35c306fa4ca29f84e71d958ffdbdc
2020-04-14 13:17:25 +00:00
Eric
c5d5586fbd configure.ac: fix libtool issue with clang and sanitizer
As pointed out at https://github.com/libexpat/libexpat/issues/312
libtool does not play nice with clang sanitizer builds at all.
For those builds LD shoud be set to clang too (and LDFLAGS needs the
sanitizer flags as well), because the clang compiler driver knows how
linking to the sanitizer libs works, but then at a later stage libtool
fails to actually produce the shared libraries and the build fails. This
is fixed by this patch.

Addtionally LD_LIBRARY_PATH has no effect on conftest runs during
configure time, so the rpath needs to be set to the asan library path to
ensure the configure run does not fail due to a missing asan library,
i.e.:

SANS='-fsanitize=memory -fsanitize-recover=all -shared-libsan'
export CC=clang-10
ASANPATH=$(dirname `$CC -print-file-name=libclang_rt.asan-x86_64.so`)
export LDFLAGS="-Wl,-rpath,$ASANPATH $SANS $LDFLAGS"

Change-Id: If3d9465068b2c654b935fc3d9ab41d799d5e02e8
2020-04-11 18:33:42 +00:00
Philipp Maier
cc971aa1a6 doc: do not set the base-port of the trx
In current config files a base port for osmo-trx is set. Lets remove
this setting so that compiled-in default (which is the same value)
is used.

Change-Id: I105d1c51424836daa6893e83a81c83cc7ac6afd4
2020-04-01 10:21:50 +00:00
Philipp Maier
748d8edbf8 debug: use LOGL_NOTICE for log category DDEV
The log category DDEV ueses LOGL_INFO as debug level. This is too
verbose, lets use LOGL_NOTICE instead

Change-Id: I56d45ce5c3f55574491ffa6e4d902d6ba7499d46
Related: OS#2577
2020-03-25 12:36:15 +01:00
Pau Espin Pedrol
dfc6e5ffc7 radioDevice: Drop unused isControl param from WriteSamples API
The out "isControl" parameter is only used by internal callers of
USRPDevice, and not used at all by any user of the generic API
(radioInterface*.cpp). Hence, we can get rid of it and keep it as a flag
for an internal API of USRPDevice.

Change-Id: I843384e24b76cdd28a95f9ee4e95e6157098e4a3
2020-03-12 19:35:47 +01:00
Pau Espin Pedrol
f8c0c464b8 radioDevice: Drop unused RSSI param from readSamples API
The out "RSSI" parameter is only filled by USRPDevice, and not used at
all by any user of the API (radioInterface*.cpp).

RSSI seems to be computed nowadays in the common path in
Transceiver::pullRadioVector().

Change-Id: I06c2ea5a9891d170bc468f952bbf2a7e64d95784
2020-03-12 19:34:28 +01:00
Pau Espin Pedrol
93707d0227 cosmetic: fix several typos found by codespell
Change-Id: Id1f6766572fd313463201e6d03964965f227db25
2020-02-25 17:03:00 +01:00
Pau Espin Pedrol
5291e8a654 debug.h: Fix print format of chan in CLOGCHAN
Under armv7l arch, size_t is actually an unsigned int and not a long
unsigned int, and compiler errors:

CommonLibs/debug.h:28:24: error: format ‘%lu’ expects argument of type
‘long unsigned int’, but argument 8 has type ‘size_t {aka unsigned int}’ [-Werror=format=]

Change-Id: I7f6ded5a984570b5267916d6c84eb7d019db73a8
2020-02-19 18:08:20 +01:00
Pau Espin Pedrol
7a07de1efd debug.h: Avoid printing pthread_t type
Using %lu for pthread_t was wrong on armv7l arch. Even worse, according
to pthread_self() man page, pthread_t cannot be assumed to be of a simple
type and hence printable:
"""
POSIX.1 allows an implementation wide freedom in choosing the type used
to represent a thread ID; for example, representation using either an
arithmetic  type  or a structure is permitted.
"""

Let's use gettid() instead. According to glibc documentation:
"""
The pid_t data type is a signed integer type which is capable of
representing a process ID. In the GNU C Library, this is an int.
"""
It may not be the same on other libc's though, so let's better cast to a
long int just in case.

Accordign to gettid() man, the libc function was only added recently
during glibc 2.30, however the system call has been around for quite
some time (linux 2.4.11). Let's accomodate use udner non-glibc or older
versions of it by having a direct syscall fallback.

Change-Id: I40265fd4c62e550014ba3ff3335ca053c5bc01f2
2020-02-19 18:08:20 +01:00
Pau Espin Pedrol
fd67262df8 contrib/jenkins.sh: Reorder sanity checks
Change-Id: Idfe12148aa7a8030bdaf56d11c1547ebc3f56d14
2020-02-19 11:53:30 +01:00
Pau Espin Pedrol
0569845a08 lms: Initial multi-arfcn support
With current state multi-arfcn can be used (eg. I can place a call
between 2 phones using TRX1 and sustain for as long as wanted), but from
time to time (around every 20seconds), a burst of Tx packed dropped
events from LimeSuite appears.

LimeNet-micro coefficients have yet not been tested.

Related: OS#4362
Change-Id: I7e67d90a8126546eeeeba376f816ec5d158d4712
2020-01-15 15:46:14 +01:00
Pau Espin Pedrol
c69b87f9bd lms: Make ts_offset and smpl rate coefs device-specific
Right now the values are the same for all devices, but they will differ
in forthcoming commits once multi-arfcn support is added.

Change-Id: I262d3a71848fc3070473e29e42820848e7591d02
2020-01-15 15:46:14 +01:00
Pau Espin Pedrol
a7bf6cd8a4 lms: Store device type specific parameters in one place
Add an enum containing each supported device type (LimeSDR-USB,
LimeSDR-Mini and LimeNet-Micro) plus "unknown", to leave some room for
yet-to-come devices to run with some generic parameters without
rebuilding osmo-trx.

Each device type is assigned a dev_desc structure, and all of them are
put in HashMap, similar to what's already done in UHDDevice.cpp.

Device type is infered from string provided by LMS_GetDeviceInfo(), as
it was already done before in several places. From now on, we only need
to parse the string once since we store the device type after first
during open time.

Later on, more fields will be moved to device-type specific structure,
such as Tx timing offset, clock rate, etc.

Change-Id: I7658615787c5bc41c365bab9c11733b701ac2ae5
2020-01-15 15:45:29 +01:00
Pau Espin Pedrol
e7f6a27ab6 lms: Move rx_buffers allocation to constructor
Release is done in destructor, so let's move allocation to constructor
since there's really no need to have them in open() which is already
quite complex and large.

Change-Id: I8a4fd973590c4c165abd8f2837b2da8fc14a2066
2020-01-15 15:35:01 +01:00
Pau Espin Pedrol
a979f5f32b lms: Make reference to std::vector unambiguous
Change-Id: Ieebdbd3d5082a02aea2441e6737783370511cbc1
2020-01-15 15:34:49 +01:00
Pau Espin Pedrol
b0e54265ad lms: Change radioDevice constructor arg name to avoid masking instance attr
channel number mangling based on multi-arfcn feature being enabled was
moved to generic radioDevice() to reuse code. Hence, the generic parent
constructor sets this->chans to 1 if multi-arfcn feature is requested.
However, LMSDevice constructor argument had same name as the class
instance attribute, taking preference. As a result, if multi-arfcn is
enabled in LMSDevice, the generic constructor first sets this->chans=1
but afterwards LMSDEvice constructor keeps calling .resize() with the
argument value "chans" instead of using this->chans.

Let's rename the argument in all radioDevice child class constructors to
avoid potential future bugs in all of them.

Change-Id: Id6c837e9133f22783dd92a81dfcc493e51bf2d21
2020-01-13 16:13:28 +01:00
Pau Espin Pedrol
62c9280590 lms: Improve smpl_buf error logging
Change-Id: I511abe2c333443b978a3767bd7b7e320e07c4930
2020-01-13 14:35:06 +01:00
Pau Espin Pedrol
1421adbc61 smpl_buf: Fix str_code() param and print unknown error val
Change-Id: I95fadac15b9ad337ebc7cfb44a20dcf803ff8a47
2020-01-13 14:34:19 +01:00
Pau Espin Pedrol
dccc82491c lms: Drop unused define
Change-Id: Iaf3361ed29dd552e5e52b62bc738fa20c6b583fe
2020-01-07 16:21:12 +01:00
Pau Espin Pedrol
bf58370675 lms: Move initialization of field started to constructor
Change-Id: I135a2ff4a419775169452be1128c7b30f7d638ad
2020-01-07 16:10:34 +01:00
Pau Espin Pedrol
7c84925ea4 doc: Update vty reference xml file
Change-Id: Ib2707204cbba6df813ffc08d7098093cf4393da0
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
fd99c6ce05 radioInterfaceMulti: Fail to tune on freq not following multi-arfcn restrictions
multi-arfcn feature uses a hardcoded disposition of logical channels on
a physical channel. Logical channels in the phisical channel are
separated by MCBTS_SPACING Hz, that is 4 GSM ARFCNs.

As a result, multi-arfcn restricts the TRX ARFCN setup to the following:
ARFCN(TRX0)=N, ARFCN(TRX1)=N+1*4, ARFCN(TRX2)=N+2*4, ...

Let's make sure radioInterfaceMulti verifies the requested Rx/Tx
frequencies for each logical channel over TRXC match the restriction
explained above. It will check freq going to be set is indeed separated
by MCBTS_SPACING from already set channels, making sure the ARFCN series
is consistent.

Otherwise, before this patch, one could set in osmo-bsc:
ARFCN(TRX0)=N, ARFCN(TRX1)=N+2

and osmo-trx would silently ack the related Rx/TxTUNE TRXC commands, but
actually still transmit on ARFCN N+4 instead. As a result, in this
scenario TRX!=0 were unusable with multi-arfcn.

Related: OS#4207
Change-Id: I2f3d66a611d3a489b3e4d9431994f4ec77b4460f
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
e947db8d98 doc: clarify number of channels on B210 with multi-arfcn enabled
Change-Id: I082d4d8c346f1be1569fe63baa856029e439cb2c
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
9279e0e123 uhd: Improve some logging lines printing UHD pretty-print output
Change-Id: If5aba28aaf8a3312d89b3e963184f9f20966d199
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
84231bd8b7 uhd: Use DEVDRV log category and support UHD >=3.11 logging framework
Change-Id: I36f1ff7d425a2144fb512ff393af02741eb4a3d4
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
aebbfe0ee7 Make logging category DLMS generic and reusable for other backends
Make sure old configs using "logging level lms <level>" are still accepted.
Initialization order of VTY componenets need to be resorted since newly
introduced command requires logging VTY node to be already setup
beforehand.

Change-Id: Ia195a74a62a8a3dd6267fb1359acaa5628208d8e
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
da7fee8ea8 Bump version: 1.1.1.38-9f2b-dirty → 1.2.0
Change-Id: I9009eb44e7d8100294da139300480fc3a2f6b616
2020-01-03 19:54:00 +01:00
Pau Espin Pedrol
9f2baf3e04 Transceiver.cpp: Introduce and use new logging categories
Take the chance to clean up logging lines in this file:
* Use LOGCHAN in more places where chan is useful
* Replace inherited (old osmo-trx) categories such as WARNING with
osmocom ones.

Change-Id: Ic8c218f050f35d48046ccf1561fb0bfc505d4f63
2019-12-20 14:19:35 +01:00
Pau Espin Pedrol
0a2a40f43c uhd: use value already cached in tmp variable
Change-Id: I4568eaed6db3da12f83f2f503a50032f7bfb482c
2019-12-19 13:52:57 +01:00
Harald Welte
501d053b70 trx: exit() on unsupported positional arguments on command line
Change-Id: Ifeea65a359e9ca307efb2c721fd0fb6f0959e976
2019-12-03 21:41:38 +01:00
Pau Espin Pedrol
0fafe03199 Transceiver: Fix wrong response upon CMD HANDOVER failure
Change-Id: I9d3f120b1696a9ce92c81097d04e81dbb717287d
2019-11-27 13:17:59 +01:00
Alexander Chemeris
9a87d90c1e vty: Simplify filler burst settings and improve help and readability.
In the command line options time, filler table/filer burts settings
were a bit difficult to undertand because the number of one-letter
settings was limited. Now, with VTY configuration, there is no reason
to keep it so difficult.

Also, after the previous commit it was no longer posible to enable
random 8-PSK filler bursts. With this patch you can configure all
supported filler bursts in a simple and logical way.

Change-Id: I752eb2c1162d084e8769181f2fcd6c0877663448
2019-10-21 08:41:07 +00:00
Martin Hauke
066fd04f47 Fix common misspellings and typos
Change-Id: I4ec7accb1912c052b446be7c399bed32a8c62253
2019-10-17 08:06:19 +00:00
Alexander Chemeris
aeaba02e02 vty: Don't enable random filler bursts automatically with EDGE.
The EGPRS switch in the VTY config enables 8-PSK burst detection on
uplink. Enabling it shouldn't turn on filler bursts.

Change-Id: I2786c768e038b769a80c8b78fe58cfa09eb322a9
2019-10-15 12:00:55 +00:00
Pau Espin Pedrol
b7e992703c Use new libosmocore logging lock API
Since libosmocore Id7711893b34263baacac6caf4d489467053131bb, a new API
log_enable_multithread() is available which takes care of protecting
logging infrastructure from us (and actually does it correctly since we
cannot protect internal libosmocore structures from osmo-trx).

Let's drop all mutex related code from osmo-trx logging infra and simply
rely on libosmocore's.

Related: OS#4088
Change-Id: I519d0f30bce871005ca26b90177ea4aa4839360a
2019-10-09 19:15:49 +02:00
Pau Espin Pedrol
928141b7d6 radioInterfaceMulti: write frequency offset direction (rx/tx) in log line
Change-Id: I7b89426e5d7d5e7570d4ef800a30c7b74bd09b82
2019-09-30 12:18:31 +02:00
Pau Espin Pedrol
e503c988d8 radioInterface: Atomically fetch and change underrun variable
Otherwise, it could happen that underrun events are lost:
TxLower (isUnderrun):	RxLower (pullBuffer):
read(underrun)
			read(underrun)
			write(underrun, |val) [maybe underrun becomes TRUE]
write(underrun, false)

Similary, it could happen the other direction if atomic was only applied
to isUnderrun:
TxLower (isUnderrun):	RxLower (pullBuffer):
			read(underrun) -> true
read(underrun)-> true
write(underrun, false)
			write(underrun, true|val) where val=false

So in here isUnderrun would return true twice while it should only
return one.

Change-Id: I684e0a5d2a9583a161d5a6593559b3a9e7cd57e3
2019-09-20 19:17:22 +02:00
Pau Espin Pedrol
ee2ba19cec Move multi-ARFCN chan amount modification from UHDDevice to parent class
This way switch is applied correctly to parent structures and features
can be used later by other children classes (other devices).

Change-Id: I24d6c66bb3195ba2513b4a67daa14cdfbacdce6d
2019-09-20 19:17:22 +02:00
Pau Espin Pedrol
80d053acb9 radioInterface: Mark setRxGain as virtual
Otherwise the parent function is always called even if the iface is
radioInterfaceMult.

Change-Id: Ie41efab1e60b88677bbd1ec333ea656794503a5a
2019-09-20 19:17:22 +02:00
Timo Jacobus
18a615176e Transceiver: Fixed copying of history into and from channelizer buffer.
In multi arfcn mode, osmo-trx would drop some bursts because it couldn't detect it
and would emit idle burst instead. Specificaly detection of peak in correlation
vector failed. Correcting copying of history in pullBuffer method fixes this issue.

[Re-worked by Pau Espin Pedrol <pespin@sysmocom.de>]

Fixes: 57df2362f0eca0a330aad3e18906046dfadb9c8b
Change-Id: I93e43f6868cd67e69fc59d2980a03550d2505bf8
2019-09-20 19:17:22 +02:00
Pau Espin Pedrol
25383a3610 radioInterface{Multi,Resamp}: Fix successful writeSamples() masking underrun from readSamples()
The only who should be setting class instance value "underrun" to false
is isUnderrun().
Similar fixes were already applied lately to radioInterface.cpp.

Change-Id: I3239b1df4536c080365106b3e4daa523b57f5dff
2019-09-13 18:53:29 +02:00
Pau Espin Pedrol
e2ac20a96e UHDDevice: Drop unneeded MULTI_ARFCN checks
After previous changes, radioInterfaceMulti is expected to handle channel
conversion correctly, so it will always use chan 0 for all these
functions. This simplifies code in radioDevice avoiding need to add
checks to all devices supporting multi-arfcn in the future.

Change-Id: Ib2cd50a6ceaeedc6aaf3e1bb51d33b52911b6eba
2019-09-13 17:54:27 +02:00
Pau Espin Pedrol
62845241a2 radioInterfaceMulti: Override setTxGain() to avoid chan!=0 calls
Change-Id: I7e67f660c3b0b009db59b405de603f6058021802
2019-09-13 17:50:10 +02:00
Pau Espin Pedrol
2ab921812e radioDevice: Introduce getTxGain() API
It will be used in later commits by radioInterfaceMulti.

Change-Id: Ie3caca8971ed1e5370dfed6fb60716a24e7d82a5
2019-09-13 17:34:46 +02:00
Pau Espin Pedrol
752055c7c1 radioInterface: Remove unusued getRxGain()
Only the radioDevice->getRxGain() is called from inside
radioInterfaceMulti, so the API in radioInterface is not used at all.

Change-Id: Icc4e9a7ebfdafe7c72c535752a5e379d12592c9a
2019-09-13 17:34:46 +02:00
Pau Espin Pedrol
705a348326 LMSDevice: Return previous txGain/rxGain if setting value failed
Change-Id: I11e853e11bec99fc88e81642f9b2cd87d5815398
2019-09-13 17:33:14 +02:00
Pau Espin Pedrol
331c88ae82 USRPDevice: Return previous txGain if setting value failed
Change-Id: I0d8fd51586ef01141d4e5896f0fc3029a22743f8
2019-09-13 17:33:14 +02:00
Pau Espin Pedrol
ca0892d822 USRPDevice: Fix setRxGain return on error and getRxGain() returning always 0
field rxGain is set to 0 during constructor and never set after that
point.

Change-Id: I7fae7a315e5ab98a15c27628a88a92226ef89469
2019-09-13 17:32:03 +02:00
Pau Espin Pedrol
17e6cd0394 radioInterfaceMulti: Check equals zero explicitly
It's not a pointer check or a boolean expression, in here we really
check chan index is 0, so it's more clear doing so this way like it's
done in all other places.

Change-Id: I83b14487d14ba8272f58796f640f58a88891e532
2019-09-13 16:20:46 +02:00
Pau Espin Pedrol
a801ae5d94 radioInterface: Rename mRadio to mDevice
Previous naming is ready confusing, because "Radio" is actually the
common term between radioInterface and radioDevice, and it looks like
it's referring to radioInterface rather than radioDevice. On the other
hand, mDevice cleary states it refers to the radioDevice item.

Change-Id: I708bb1992a156fb63334f5590f2c6648ca27495e
2019-09-13 15:59:31 +02:00
Pau Espin Pedrol
923b4bc9a2 Transceiver: Don't stop TRX if pulling from OFF timeslot
BTS may have any timeslot disabled, or may have not yet sent initial
SETSLOT cmd to properly configure the timeslot.

Change-Id: Icf62e5d1200c7a440f255bb46023cdbf61532b7f
2019-09-09 10:27:04 +02:00
Pau Espin Pedrol
0d56d75dbb Transceiver: pullRadioVector(): Fix use of uninitialized value bi->tn
Change-Id: Ia0f2b5a51040663d7e8219e6ed51e0513b876548
2019-09-09 10:20:58 +02:00
Pau Espin Pedrol
94c5241403 Transceiver: Log error condition no burst in pullRadioVector()
Change-Id: I4f180cc852582b131ba28a8139215335f7ba567d
2019-09-06 14:37:36 +02:00
Pau Espin Pedrol
e3a2516280 Transceiver: Use LOGCHAN in logRxBurst to unify log format
Change-Id: Iec33ab73a9bf90fd0bff9ba453c32ea11bf0670e
2019-09-06 14:37:36 +02:00
Pau Espin Pedrol
1fba10409b Transceiver: Fix logging TN and version
Since tn is declared as uint8_t, it's actually a char, and by default
c++'s ostream& operator<<(ostream&, unsigned char) tries to print chars
with its ASCII visible character instead of numeric value.

Change-Id: I534158e8e1719ad19a9cde7c747a8f8ad5a01a2b
2019-09-06 14:33:59 +02:00
Pau Espin Pedrol
77f3396d04 device: Use LOGCHAN in set_antennas()
Change-Id: I3099498e3a3f26b53d55a96a36cc056f7b25b27a
2019-08-26 17:13:23 +02:00
Pau Espin Pedrol
e0010fa425 lms: Log available antennas if requested antenna fails
Related: OS#3343
Change-Id: Icd328e85b0a75ef67f371a7ed72638053b1854f9
2019-08-26 17:13:17 +02:00
Pau Espin Pedrol
bfc1d0bed7 Transceiver: Enable EDGE detection only on PDCH timeslots
Related: OS#3664
Change-Id: Id16248a1c03f9bc9f323c707857cdf3bf34c4e3e
2019-08-26 16:34:49 +02:00
Pau Espin Pedrol
76ff96e210 Transceiver: exit process when BTS drops connection
We don't want to keep osmo-trx running in a started state once the BTS
controlling it becomes unavailable. If a socket towards the BTS fails,
it means the BTS is gone and the best thing to do is to stop the process
(alternatively we could go back to stopped state instead, and wait for
BTS to re-connect, fur so far this action is good enough).

Related: OS#4170
Change-Id: I2ccbe3c17b39fb792ea7810f840235c348054d66
2019-08-26 15:55:49 +02:00
Pau Espin Pedrol
4e6ec4554d Transceiver: Fix idle ul burst indications being dropped
pullRadioVector() should return true on idle frames because those
indications may be handled by upper layers (TRXDv1). Clarify return code
in function documentation.

Change-Id: If592ed1c04cf7e995f656b313f60edd4d40d1bfd
2019-08-26 15:45:56 +02:00
Pau Espin Pedrol
e4166be76f Transceiver: Clean up receival of downlink bursts
Use a packed structure to clearly indicate what is contained in the
received buffer.

Change-Id: I4d8c0e3c0c717699889f79e50c778d14b6058f2d
2019-08-26 14:34:09 +02:00
Pau Espin Pedrol
e7195ac7d0 Transceiver: Check return value when binding IP addr for clock socket
No need to continue further since anyway we'll end up exiting.

Change-Id: Id8b38b40df5744beb705d560defb06532cf0fd44
2019-08-26 10:55:08 +02:00
Pau Espin Pedrol
ca6a78e193 Transceiver: fix segfault during init if IP addr binding fails
If osmo-trx is started and IP addr binding fails (ie because the IP
address is not assigned in the system), it will try to access a
heap-allocated Thread instance which was not initialized (because init()
function returned earlier).

Fixes: OS#4147
Change-Id: I19f9745cd026c0ff6581895a66bf91b40113b07d
2019-08-26 10:50:20 +02:00
Pau Espin Pedrol
67aa91b2c0 Drop old setPriority related code
This code is not needed anymore since we are setting SCHED_RR scheduler
with a real time priority in main thread during startup, so all threads
will inherit same rt priority, which should be enough to keep the
process working reliably even on high system loads (from non rt
processes).

osmo-trx was tested to be reliable during test with stress-ng as
explained in related ticket below.

Related: OS#2344
Change-Id: I3a88946dd71e9aeeaac9d19d396e2236c302b608
2019-08-21 13:00:41 +02:00
Pau Espin Pedrol
3eed8ebb0d osmo-trx: log to stderr on signal received
Since osmo-trx it's a big multithreaded process and shutdown sequence
can be complex, better use stderr to log signal received events to make
sure log is outputted straigh away and not buffered. In general stdout
is usually line-buffered, but buffering strategy can be more
conservative if output is for instance redirected to a file.

Change-Id: I70ba86919d1f7df41ef3db4916317d27697a025c
2019-08-14 16:26:47 +02:00
Pau Espin Pedrol
d0cbb16a93 Bump version: 1.1.0-dirty → 1.1.1
Patch release to have debian/patches/build-for-debian8.patch applying
correctly again.

Change-Id: I27caf077abc400e9661549886bb8f7827dd299bb
2019-08-08 13:00:06 +02:00
Pau Espin Pedrol
e774d52504 Bump version: 1.0.0.104-72a7 → 1.1.0
Change-Id: Ifd5abfb03015e9233814eb9d843ce2e218987283
2019-08-07 21:12:56 +02:00
Pau Espin Pedrol
72a75f3e43 Require newer version of libosmocore to avoid build failure
Older commit started using osmo_timerd_* APIs which are only available
starting libosmocore 0.12.0, but configure.ac still states 0.11.0 is
accepted, which is incorrect.

Fixes: 4456b6f132
Change-Id: I71743b8a10edb10af51ad8e9289c53e432199b97
2019-08-07 21:11:47 +02:00
Pau Espin Pedrol
27424a39ee Transceiver: Add missing include netinet/in.h
Previous commit started using IPPROTO_UDP without including required
include. Newer versions of libosmocore's osmocom/core/socket.h include
that header so the define is present, but older versions of libosmocore
(such as 0.12.0) don't, so let's include it explicitly (the correct
thing to do).

Fixes: b9d2515704
Change-Id: I67ddf550f3a7fc6a650e1e1d9bde0bbb28785104
2019-08-07 21:10:47 +02:00
Pau Espin Pedrol
c7ac63afa5 Drop old README information, provide new updated README
Previous content in README file is actually a description of the TRXD
and TRXC protocols, and it has already been moved to the User Manual
some time ago. INSTALLATION contained README related information, but it
was really out of date.

So this commit basically drops those two files and provides a new
README.md with content taken from Osmocom's OsmoTRX project wiki page.

Change-Id: I3df00799ce80aa4af43225e69a408ba2cbc444db
2019-08-01 15:17:30 +00:00
Pau Espin Pedrol
cbc02086d5 Move std_inband.rbf under device/usrp1/ dir
This file is only used by USRP1, so let's move it there and avoid
processing it in Makefiles if build for USRP1 is not requested at
configure time.

Change-Id: Ibb40ba487581e76d2ae3e8a420d631670f876cf0
2019-08-01 13:46:00 +02:00
Pau Espin Pedrol
3d29b4d5b0 Move README.DFEsymbolspaced to utils/matlab
Change-Id: Icccc18688ee54e669cf3452b08747b3509042fa2
2019-08-01 13:46:00 +02:00
Pau Espin Pedrol
06d3ba0445 Move Transceiver52/README to UserManual
Change-Id: Ib5a56cfe0c27d027bc0c60abda89e646a80849de
2019-08-01 13:46:00 +02:00
Pau Espin Pedrol
8a784c7145 Move matlab files under utils/matlab
Change-Id: I15b687fbf436d662b264cb00f72b367ccd64b962
2019-08-01 13:46:00 +02:00
Pau Espin Pedrol
7758542087 Move inband-signaling-usb documentation to UserManual
Change-Id: I4d6ef1f54f3d6c5a73ce00dc4640bd698f96842b
2019-08-01 13:46:00 +02:00
Pau Espin Pedrol
68a78099a0 lms: Drop rx_underruns rate ctr, add tx_drop_* rate ctr
After discussion in [1] and further look at the code, it became obvios
rx_underrun events are not happening in general for any SDR (don't
exist), so let's drop that counter. Instead, add Tx Dropped Packet counters,
which were not accounted prior to this commit.

[1] bde55afd29

Change-Id: Iff1535c219a4695a511d383d7c4b06ef6eff959d
2019-08-01 13:45:55 +02:00
Pau Espin Pedrol
50c78dfe85 jenkins.sh: Workaround libusrp build race conditon
When submitting patches to osmo-trx in gerrit, sometimes the jenkins job
fails due to libusrp failing to build. I never have this issue in on my
workstation.

Let's disable parallel make and see if we can avoid it for now.

Related: OS#3970
Change-Id: I24bc54f5872e8edb9fab5b88055a00cebe1a6911
2019-07-30 15:06:24 +02:00
Pau Espin Pedrol
207911bcde usrp1: don't check for non-null underrun pointer
The pointer can't never be null, so avoid checking it.

Change-Id: I12e14641713a6494bc89570f02cecfc6f8fd4b5e
2019-07-29 20:42:56 +02:00
Pau Espin Pedrol
2c673e0f3e radioInterface: Clarify how underruns are handled driving a radioDevice
The underrun parameter in radioDevice's readSamples() is not a "Rx
Underrun" event, but rather it's used to retrieve a "Tx Underrun" which
on some SDRs (like USRP1) seems to be (so far) available only at
readSamples() times.

Thus, underrun parameter for both readSamples() and writeSamples() is
actually flagging the same event, and should be ORed in pushBuffer() as
it's already done in pullBuffer(). Otherwise if implementation is
setting the underrun pointer to false, it could erase the flag being
marked by the counterpart function before isUnderrun() is called (which
is the one responsible to clear the flag).

Change-Id: Id549489fc1485e0d762818c8e682aaddd5041f1c
2019-07-29 20:42:56 +02:00
Pau Espin Pedrol
b4c749b32b Remove unused autogen.sh
autoreconf is used instead, as done in all of the osmocom projects.

Change-Id: I87676cdf6818b4250f478962baf96ad5f28564d5
2019-07-29 15:50:59 +02:00
Pau Espin Pedrol
c641f781dc Remove empty ChangeLog fnd NEWS files
We already have debian/changelog for same purpose. This file is empty
and doesn't exist on other osmocom projects.

Change-Id: I5a90107476ca116bebc8569f4eb1db0fa25807a6
2019-07-29 15:50:46 +02:00
Vadim Yanitskiy
6b30ab0c34 manuals/configuration.adoc: fix copy-paste error in config example
Change-Id: If9de32eed8170038c8c177c8996c78846dddb624
2019-07-24 23:08:19 +07:00
Pau Espin Pedrol
720b912ba9 Transceiver: Clean up code passing parameters to threads
TransceiverChannel naming was misleading there. It's simply a data type
used to pass 2 parameters through the void* of the thread entry
function, so let's clearly specify is a storage for thread params.
Furthermore, we don't need a full C++ class for that, let's simply use a
struct.

Change-Id: I6e3898a8a66520cc5b2a7df9b9ae01b0b272387f
2019-07-23 09:06:01 +00:00
Pau Espin Pedrol
c3325b9aeb Transceiver: Store TRXD version per channel
The setting is negotiatied by osmo-bts-trx on each channel, so let's
keep and use state per channel instead of overwriting the state from
different channels.
Take the chance to change related log lines to also print the channel
number.

Change-Id: If9cf95e89d38d0155ab48b8c0977ca5f381c2aad
2019-07-23 09:06:01 +00:00
Pau Espin Pedrol
88f86a14ba Bind CTRL port to IP addr specified in VTY config
Before this commit, osmo-trx was always setting its CTRL socket to
listen on 127.0.0.1.

Change-Id: I61a06c1b9c20a906e7030f824a93370d041be7b9
2019-07-22 22:15:24 +00:00
Pau Espin Pedrol
21d03d3912 Add SPDX annotation
Related: OS#3515
Change-Id: I3719bd8dc015569ecd81928fc079e27593cdca09
2019-07-22 12:06:26 +02:00
Pau Espin Pedrol
bdb970e495 cosmetic: Fix trailing whitespace in several files
Change-Id: Ifafb68353960fc5046661854ccfb8d783b0efb14
2019-07-22 12:03:39 +02:00
Pau Espin Pedrol
e6319ed32a debian/copyright: Add missing file Utils.* to LGPL-2.1+ list
Change-Id: I36b8b8be48ae8676688786f39008d08b61011ede
2019-07-22 11:59:53 +02:00
Pau Espin Pedrol
1830705e67 debian/copyright: Update wrong paths in license list
Those paths were moved into a subdir a while ago, but this file was not
updated at the time.

Change-Id: I1857338b7a19e2a37f62386ceb4a1fad988272ba
2019-07-22 11:22:48 +02:00
Pau Espin Pedrol
46d0be06ab debian/copyright: Remove non existent radioInterfaceDiversity.cpp from list
Change-Id: I5cfbbafd411e580421f86df6817f91261aceda7e
2019-07-22 11:21:28 +02:00
Harald Welte
2896cecefb radioInterface.cpp: Fix missing member initialization of RadioInterface()
Change-Id: I7264ef35dbe6d3522858eae5b47d150aa1ffe334
Closes: CID#169594
2019-07-21 15:46:06 +00:00
Harald Welte
5c6ca1739f CorrelationSequence: fix initialization of class members
Change-Id: Ia72395f8805e9e2cd700ad1e559a8aa62124aaec
Closes: CID#149371
2019-07-21 15:46:04 +00:00
Harald Welte
80ca1de44a ChannelizerBase: fix initialization of class members
Change-Id: I8c047c8f98e928a62dca1d7b8c003502727c086e
Closes: CID#149374
2019-07-21 15:46:01 +00:00
Harald Welte
2a3d8ba71a Timeval: Restore output stream flags after changing them
Change-Id: I866505f29ed56d8f3ba3aaba70c0d82479987c64
Closes: CID#149361
2019-07-21 15:45:58 +00:00
Vadim Yanitskiy
6fa906c280 trxd_fill_common(): fix TRXD header version coding
The header version field is 4 bit long, so the mask 0x07 == 0b111
is wrong, it should actually be 0x0f == 0b1111.

Change-Id: I290931559ce01cf6e43470b18855c46808d6c2a5
2019-07-20 19:39:18 +07:00
Harald Welte
a7ba484fb2 proto_trxd.c: Use bit-wise AND, not boolean AND
Change-Id: I974c91be7cc119b44c2fb0c53d08009c87de7bf1
Related: CID#202038
2019-07-20 10:13:18 +02:00
Pau Espin Pedrol
758381bad4 Transceiver: Initialize mExtRACH in constructor
Doing so should make Coverity happy:
>>>     CID 200212:  Uninitialized members  (UNINIT_CTOR)
>>>     Non-static class member "mExtRACH" is not initialized in this constructor nor in any functions that it calls.

The current status is actually harmless since the field will be set
during init() time, and the variable is never used before init() is
called.

Fixes: Coverity CID#200212
Change-Id: I17286570a9a6db695a75147e5cbb18c9da7d0fe6
2019-07-19 14:58:32 +02:00
Vadim Yanitskiy
56c5f2959b driveTxPriorityQueue(): enrich logging message
Change-Id: If25c2171f7d1ab98d65f0dbf93d0d8a5a635caf7
2019-07-19 14:58:32 +02:00
Vadim Yanitskiy
dd571c6db1 driveTxPriorityQueue(): check if message header format is supported
Change-Id: I17abf95f5e23236abccc50476cd59931580f5cd3
2019-07-19 14:58:32 +02:00
Vadim Yanitskiy
b31232537a driveTxPriorityQueue(): use trxd_hdr_common for message parsing
Change-Id: If6a93e2b7fc9ada55edbdd16352cd4f7040e3d2a
2019-07-19 14:58:32 +02:00
Vadim Yanitskiy
8d771d24e7 driveTxPriorityQueue(): cosmetic: use proper type for TDMA TN
Change-Id: I8396004616754f84fb465c972fde9e91b18cc49b
2019-07-19 14:58:32 +02:00
Pau Espin Pedrol
cf6113b2fe Transceiver: Support TRXD v1
Related: OS#4006
Change-Id: I53db2678458a7377c87875b58b58b76a1b900517
2019-07-19 14:58:29 +02:00
Pau Espin Pedrol
13c81098f8 Transceiver: Support SETFORMAT command
Only old v0 is supported so far.

Related: OS#4006
Change-Id: If9fc22f9987238a5ff870df7718de4efc9e04289
2019-07-19 11:44:13 +00:00
Pau Espin Pedrol
15fa64bce4 Transceiver: Move out TRXD socket send code to prepare for TRXDv1
Only old v0 is supported so far. TRXD protocol related data/logic is
moved to its own file out of Transceiver class. Code is refactored so it
can be re-used later by TRXDv1.

Related: OS#4006
Change-Id: I5786dd44b076202c6f1a6e82405670e8605797ed
2019-07-19 11:44:13 +00:00
Pau Espin Pedrol
c9202ab0be Logger: global Log mutex is now available from C code
This way the C++ logging API can still be used while allowing for C
files to use the same mutex.

Change-Id: I473e57479f8ae98a84ad00b76ff338f79f732236
2019-07-19 11:44:13 +00:00
Sylvain Munaut
b49a42e70b sigProcLib: Add C/I (Carrier-to-Interference ratio) computation
Related: OS#4006
Change-Id: Ib4ceec553f2e5f77bf3f6777724968456a180f5e
2019-07-19 11:44:13 +00:00
Pau Espin Pedrol
c3d68c159f sigProcLib: detectAnyBurst(): make TSC used to detect burst available to caller
This value will be sent in TRXDv1 protocol.

Related: OS#4006
Change-Id: I603b7b52f957cf897b036dbaeb22c01a55de08c3
2019-07-19 11:44:13 +00:00
Pau Espin Pedrol
7ee2d10113 sigProcLib: detectAnyBurst() family: Use struct to gather all out params
Currently we have 2 out parameters, but in forthcoming commits will add
a third one. All those functions already have too many parameters, so
let's put together all the output params in a struct to pass them easily
and make it easier to understand they are the estimated output values.

Related: OS#4006
Change-Id: I05cfa0ceaa2e633a5e6e404e2eae497ff4442dea
2019-07-19 11:44:13 +00:00
Ruben Undheim
252564b50e Fix spelling discovered by lintian
Change-Id: I5ab9b9c7c47d0d6e674c1f5242e2b3a05006293e
2019-07-17 10:58:22 +00:00
Oliver Smith
2ded53c440 contrib/jenkins.sh: run "make maintainer-clean"
Related: OS#3047
Change-Id: I6d541b47e68f5a8a61ac139a3ea85a9cb33856c1
2019-07-10 13:26:21 +02:00
Pau Espin Pedrol
95c8318d5d Transceiver: Support pulling idle frames in pullRadioVector()
This logic will be used once we support TRXDv1, where idle indications
are sent through the socket.

Related: OS#4006
Change-Id: I46404f6e4055b6d3af3afffb0dfe4a19502917aa
2019-07-03 16:03:21 +02:00
Pau Espin Pedrol
9bb24a1103 Transceiver: pullRadioVector(): Move initialization of var to start of function
This will be needed upon forthcoming refactor to support idle frames,
which will add a goto return. Otherwise compiler complains:

error: jump to label ret_idle [-fpermissive]
note:   crosses initialization of unsigned int max_toa

Change-Id: Icd2793adc7b73a795184639b95fb5da336909b59
2019-07-03 15:49:38 +02:00
Pau Espin Pedrol
d6dbb1b987 Transceiver: Simplify code on early error return when calling detectAnyBurst
We get rid of one branch and simplify code logic.

Change-Id: I026e35262bfe42c3d23ebdc06d84e4908a8380e2
2019-07-03 15:49:38 +02:00
Pau Espin Pedrol
be9cd66020 Transceiver: Avoid noise calculation formula in 2 branches in pullRadioVector
Makes code easier to follow and will help in forthcoming refactoring
once idle frames are supported.

Change-Id: I56c84e9684ca460efd6c983d7e95d8e455bcac69
2019-07-03 15:49:38 +02:00
Pau Espin Pedrol
b9d2515704 Transceiver: replace UDPSocket with libosmocore socket API
We have a good socket API in libosmocore, let's drop osmo-trx socket API
and use libosmocore's one instead of maintaining the two of them.

Change-Id: Ib19856a3e0a7607f63436c4a80b1381a3f318764
2019-07-02 15:07:25 +02:00
Pau Espin Pedrol
7dc07b9425 Transceiver: Get rid of SoftVector in struct trx_ul_burst_ind
Make the interface using trx_ul_burst_ind more implementation agnostic
as well as easier to use. For instance, we don't care about SoftVector
size one returned from pullRadioVector(); we want to use nbits instead.
As a result, we no longer spend time normalizing guard periods. While at
it, change vectorSLicer to return void since it always returns true.

Change-Id: I726e5a98a43367a22c9a4ca5cbd9eb87e6765c7a
2019-07-02 15:05:17 +02:00
Pau Espin Pedrol
07ddce5c1f Transceiver: Drop use of GSM::Time from trx_ul_burst_ind
Use of that class is really not needed since we don't need to do any
calculation with those values, so we can simply store the final values
in the struct.

Related: OS#4006
Change-Id: Iadf2683d7f52138a2248598641f3b702252f325d
2019-07-02 15:05:17 +02:00
Pau Espin Pedrol
25ae190dc6 Transceiver: Move soft bits normalization to pullRadioVector()
That's where all the filling logic happens, while in driveReceiveFIFO we
mostly want to take the burst, generate a message and sent it over the
socket.

Related: OS#4006
Change-Id: Ibfb48877af4ff5ef0f56390901669c8353beaf48
2019-07-02 15:05:10 +02:00
Pau Espin Pedrol
607a414967 Transceiver: Move calculation of normalized values (rssiOffset) to pullRadioVector()
That's where all the filling logic happens, while in driveReceiveFIFO we
mostly want to take the burst, generate a message and sent it over the
socket.
In pullRadioVector this way we always provide normalized values based on
user configuration (VTY rssi-offset).

Related: OS#4006
Change-Id: I1ee28daf21dc287bec564d45d58086d63655c0f6
2019-07-02 15:04:40 +02:00
Pau Espin Pedrol
0e67cf24eb Transceiver: Move nbits burst size calculation to pullRadioVector()
That's where all the filling logic happens, while in driveReceiveFIFO we
mostly want to take the burst, generate a message and sent it over the
socket.

Related: OS#4006
Change-Id: Ib1df10c40d737954904290f57d58b1c77d65f82e
2019-07-02 15:04:29 +02:00
Pau Espin Pedrol
ff6aeb7f62 Transceiver: Drop unused rssi_valid struct field
That field is actually never used. Furthermore, if pullRadioVector()
returns false, then the caller should consider the 'trx_ul_burst_ind'
structure as uninitialized. Moreover, RSSI is mandatory - we cannot send
burst indications without it.

Related: OS#4006
Change-Id: Ia109298aebe8ba4750a39338ba7962555903cd82
2019-07-02 15:04:24 +02:00
Pau Espin Pedrol
ddd18a5e33 Transceiver: refactor: gather uplink burst parameters in struct
A new struct trx_ul_burst_ind is introduced, which will handle
information filled by lower layers upon decoding of uplink bursts.

Methods pullRadioVector() and logRxBurst() are adapted to use that
struct. This way it's easier to understand in/out parameters and it's
also easier to add further parameters to be filled in in the future.

Related: OS#4006
Change-Id: I7e590fb1c0901de627e782f183251c20f4f68d48
2019-07-01 16:13:21 +02:00
Pau Espin Pedrol
778b30a530 Introduce structs to encode TRXD packets
This will ease adding new protocol versions in the future.

Related: OS#4006
Change-Id: I67ffede171eddde436f9057191ed76015a8ea6eb
2019-07-01 16:13:10 +02:00
Pau Espin Pedrol
e9ce77b871 trx_{vty,rate_ctr}: Set proper license AGPLv3+
Take the chance to improve text with author, SPDX tag and fix incorrect
copyright dates.

Related: OS#3515
Change-Id: Ic745312ed07db205b1cdc0f2fa130000319354c5
2019-06-25 12:40:17 +02:00
Pau Espin Pedrol
c27d9f88df Remove AUTHORS file
License of this file doesn't match the license stated in COPYING and in
most source code files (GPLv3 vs AGPLv3). Furthermore, we don't really
maintain this file, so let's drop it to avoid non-up-to-date content
which may introduce confusion.

Related: OS#3515
Change-Id: I536a145cb7696af8e9dbd3065ee5e5f493217ac6
2019-06-25 12:40:17 +02:00
Eric Wild
ac0487eb66 Add option to set stack size in config file, default == 0 == OS default
Change-Id: Id752f6b5ce9a96a67cd1ff835687ce0e03d3a50d
2019-06-17 14:41:34 +02:00
Pau Espin Pedrol
6a305feb0f Add VTY commands to set error ctr thresholds
osmo-trx will validate over time that those thresholds are not reached.
If they are reached, osmo-trx will die. As a result, osmo-bts-trx will
notice and will end up notifying the BSC about it (for instance because
it will also restart its process).

For instance:
"""
ctr-error-threshold rx_drop_events 2 minute
ctr-error-threshold rx_underruns 10 second
"""

In those cases above, osmo-trx will die if rate_ctr rx_drop_events went
to a value higher than 2 per minute, or it will die to if rx_underruns
went higher than 10 per second.

Change-Id: I4bcf44dbf064e2e86dfc3b8a2ad18fea76fbd51a
2019-06-11 14:28:17 +00:00
Pau Espin Pedrol
bde55afd29 lms: Fix stream_stats checks with overrun/underrun
It was initially thought that underruns/overrun fields were
increasing-over-time values.
However, after reading LimeSuite code, it seems overrun and
underrun fields are actually reset upon every call to
LMS_GetStreamStatus().

Related: osmo-trx.git 9281771256
Related: https://github.com/myriadrf/LimeSuite/issues/265
Change-Id: I677232a7b12ee83d26aa34d92f76a91d4b5a63a6
2019-06-09 06:55:13 +00:00
Pau Espin Pedrol
4c50bf435b lms: Drop unusued variable masterClockRate
Change-Id: I19192925d008046f474615a0476b52ddee9a9d78
2019-06-06 19:44:22 +00:00
Pau Espin Pedrol
63e872a701 doc: vty: Update trx_vty_reference.xml
Change-Id: I2587cd47ee48e979de447f7a0f4d79bb5fac0592
2019-06-05 12:50:38 +02:00
Pau Espin Pedrol
b426e4abb4 Rename and move STOP signal from Transceiver to main
The callback actually belongs there, since it's the code/thread in main the one
actually in charge of stopping everything. It simplifies current code,
and more important, allows for new clients of this signal to use it.
This callback will also be used in forthcoming commits by code
controlling rate_ctr thresholds to stop the process if the VTY
configured threshold is used.

Change-Id: Id4159e64225c6606fef34a74b24f37c3a071aceb
2019-06-05 12:50:38 +02:00
Pau Espin Pedrol
4456b6f132 Add rate_ctr support to store/retrieve SDR errors through VTY
Introduce a unified implementation-agnostic interface for radioDevice to
signal SDR error counters to upper layers and manage them.
This patch only implements counters for osmo-trx-lms (other devices will
show all counters unchanged during time).

Sample use through VTY:
"""
OsmoTRX> show rate-counters
osmo-trx statistics 0:
   device:rx_underruns:          0 (0/s 0/m 0/h 0/d) Number of Rx underruns
    device:rx_overruns:          0 (0/s 0/m 0/h 0/d) Number of Rx overruns
   device:tx_underruns:          0 (0/s 0/m 0/h 0/d) Number of Tx underruns
 device:rx_drop_events:          4 (0/s 2/m 3/h 0/d) Number of times Rx samples were dropped by HW
device:rx_drop_samples:        513 (0/s 196/m 425/h 0/d) Number of Rx samples dropped by HW
"""

Change-Id: I78b158141697e5714d04db8b9ccc96f31f34f439
2019-06-05 12:50:38 +02:00
Oliver Smith
76a5013c91 debian: create -doc subpackage with pdf manuals
I have verified, that the resulting debian packages build in my own OBS
namespace (see the -doc packages):
https://download.opensuse.org/repositories/home:/osmith42/Debian_9.0/all/
https://build.opensuse.org/project/show/home:osmith42

Depends: Ib7251cca9116151e473798879375cd5eb48ff3ad (osmo-ci)
Related: OS#3899
Change-Id: I34858a18a34fc467f274ac164697a242f4cf0df8
2019-05-29 12:14:24 +02:00
Pau Espin Pedrol
9281771256 lms: Fix stream_stats checks with droppedPackets
Existing code had a typo (value was assigned from wrong variable).
Furthermore, it was experimentally found that:
while underrun/overrun are documented as "FIFO overrun
count" in LimeSuite.h, it seems droppedPackets ("Number of dropped
packets by HW") is not actually an incrementing counter like the others,
but simply a value set every time LMS_RecvStream() is called. Since we
are actually interested in keeping the count over time, adjust code to
achieve that.

Change-Id: Id93d33400e11360b9536f56a31904328549cfbbf
2019-05-24 17:01:13 +02:00
Pau Espin Pedrol
dcbcfa58e4 lms: Use smpl_buf to recover from timestamp jumps
Also take the chance to make sure we handle properly short reads (keep
reading again).

Both scenarios can be tested by running osmo-trx-lms and then using
on a terminal:
sudo kill -STOP `pidof osmo-trx-lms`; sleep 0.5; sudo kill -CONT `pidof osmo-trx-lms`

Fixes: OS#3339
Change-Id: Idfc4e69acc30afb11440b6b9cbdcfa09ff920265
2019-05-06 11:23:36 +02:00
Pau Espin Pedrol
b5def414b8 smpl_buf: Move it to device/common and create libdevice_common.la
Since in next commit osmo-trx-lms starts using smpl_buf.cpp, it seems
some automake step doesn't like including a cpp file twice from a
different directory, since race conditions can occur building it.
Instead we define the dependency by first building a static lib and then
using it on each libdevice.la (one per device type).

We already do the similar under arch/ subdir, where we have a common/
subdir and then one subdir and lib per architecture.

Change-Id: I465ad0f6d5569bb3006d711c8fd0df14391fcf35
2019-05-06 11:23:18 +02:00
Pau Espin Pedrol
fc73c073a1 Introduce LOGCHAN macro to standarize logging channel info
Change-Id: I67d869499aa16af58c863ca7b74c356bcd979936
2019-05-06 11:21:43 +02:00
Pau Espin Pedrol
a7919265f5 smpl_buf: Remove dbg log line with duplicated info
Change-Id: Ia2423707210a364fa6827b92cca087ced99b088b
2019-05-04 20:36:07 +02:00
Pau Espin Pedrol
9b394e0cc0 smpl_buf: Remove unused clk_rt variable (fixup)
Last commit removed use of the clkr_rt variable but forgot to remove the
variable itself.

Fixes: 580c48b7d5
Fixes: Coverity CID 198370
Change-Id: Ida1fc5b7b338fbeb2a7c6258f36b02da93ff2186
2019-05-04 20:05:06 +02:00
Pau Espin Pedrol
580c48b7d5 smpl_buf: Remove unused clk_rt variable
During 87b7d098e5 we dropped support for
UHD specific functionalitites, and so clk_rt is not needed anymore.

Change-Id: I37403e085ed6a541bbdecf64f1f9a821ff2753a4
2019-05-03 14:38:51 +02:00
Pau Espin Pedrol
7214fde085 device: Drop unused numberRead/numberWritten APIs
It's really not used, so let's drop unused code and simplify work for
new to come device drivers implementation.

Change-Id: I0d18f9c2584771e2f7b3d5c6b016e764e02855ff
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
51509b3895 Move smpl_buf out of uhd dir to re-use it in other devices
Change-Id: I39ac8435072cff8d4dac786b31ff4af9b61a77fe
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
ef192d303c uhd: Avoid reallocation of buffers every read
Buffer size is based on num of chans and rxBuffer size is based on num
of chans and rx_spp, and both are available and set during open(), so no
need to waste time allocating and freeing them everytime we read from
the device.

Change-Id: I8c881c9c303c80f323825d85a924d74b76d2ce47
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
ac927b2690 cosmetic: uhd: Use loglevel ERROR instead of ERR
ERR is osmo-trx legacy level, which actually converts to osmocom's
ERROR, so let's use that one directly.

Change-Id: I82f6f89a725bea7f7acfa455c20cf922cc3f8a00
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
3e9179a55e uhd: smpl_buf: Use TIMESTAMP type in str_status
Other related functions use "TIMESTAMP timestamp" so let's use same
stuff in that function.

Change-Id: I016b1a7f8db379caebc1409ca11e5ae8b759d2d4
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
87b7d098e5 uhd: smpl_buf: Drop UHD specifics out back to UHDDevice
This way smpl_buf can be re-used later by other non-UHD drivers.

Change-Id: I94061328d46a550d4147121d85baffa29c700c45
2019-05-03 13:50:50 +02:00
Pau Espin Pedrol
7bef2346c4 cosmetic: uhd: Move smpl_buf out of UHDDevice, move UHDDevice class definition to .h
* move class definition to .h file, like we do for other devices.
* move smpl_buf class to a different file inside uhd/.
* Preparation work to have smpl_buf being used in a generic way for
devices other than UHD (LMS).

Change-Id: Ib4594320da9bb7f6e9f52e7d70d11ecd11106aae
2019-05-03 13:50:47 +02:00
Pau Espin Pedrol
2876785f50 lms: Catch and log dropped packets by HW during recv
Change-Id: I23554d95b0aff585024610fc12920c9da4f3ba9e
2019-04-25 20:16:10 +02:00
Pau Espin Pedrol
713b4d81cd lms: Remove unused var m_last_tx_overruns
Change-Id: I2104205b2af7cd6c86075d5cc4f0f36bde5e5311
2019-04-25 20:16:10 +02:00
Pau Espin Pedrol
b96d9ddee3 lms: Remove references to ALERT loglevel
ALERT log level is not Osmocom standard level, it's just a define in
osmo-trx to keep compatibility with old code.

Same goes for one reference to "ERR" intead of "ERROR".

Change-Id: I0e171a8ac8a8bfa804ac97fba3d73efcfa6424b4
2019-04-25 20:16:10 +02:00
Pau Espin Pedrol
048c3ba300 lms: Log underrun/overrun events
Change-Id: I8c6b1d3e8515153e5d4079cc6620901ef8ce2449
2019-04-25 20:16:10 +02:00
Pau Espin Pedrol
75cb0b9dd6 Move duplicated thread_enable_cancel to CommonLibs
Change-Id: I1a479b59bdda01233273dfa919bd678edbe34708
2019-04-25 19:33:58 +02:00
Pau Espin Pedrol
46324d3597 cosmetic: Threads.h: Remove trailing whitespace
Change-Id: I0ae6e435a7f0480c3eaa08dccfe824456f33b015
2019-04-25 19:33:11 +02:00
Pau Espin Pedrol
bab1583a2c lms: Improve log during flush recv error
Change-Id: Id45d42599738efd6a5d89787c75779838a979330
2019-04-25 19:26:24 +02:00
Pau Espin Pedrol
541496b65b lms: flush_recv: alloc buf on stack instead of heap
No need to use the heap here since buffer is only used as a temporary
trash. Using the stack is quicker.

Change-Id: Iede8dc0903ee3865a52c8e2fd811bcde444fee33
2019-04-25 19:22:11 +02:00
Joachim Steiger
c785fb130a lms: properly call close if set_antennas() fails, add some comments
Change-Id: I9ebe986ee3a15842a15853424ee98e9a2fa6a5df
2019-04-17 18:24:11 +00:00
Joachim Steiger
2875290d95 lms: add device type detection and device specific gains
add device dependant max gain setup - limesdr mini and limenet micro need slightly reduced maximum gains to get a PASS on phase error measurements
rework clock reference setup - external clock needs to be selected before calling LMS_Init(), internal can only be set after.
remove now unused compat_LMS_VCTCXO* functions - we do not set the VCTXCO directly anymore

Change-Id: I3cf905b0a84bc1ec200891762a6646141ee37181
2019-04-17 18:24:11 +00:00
Joachim Steiger
4ce4555d0e lms: move LMS_GetLPFBWRange and LMS_Calibrate calls from open to start
bandwidth, freqency, gain stages need to be set before calibration can be successful

Change-Id: I1090effdf0f43e5183a402e4c1a1ffe5abdefd37
2019-04-17 18:24:11 +00:00
Joachim Steiger
2d130fb15d lms: move LMS_EnableChannel from Start/Stop to Open/Close device
move enable: it is important that channels are actually enabled before applying any configuration (besides external clock)
move disable: move to close, so channels are not disabled and not enabled again while osmotrx is active.

Change-Id: I82878913254ce15a85db8d006e13d5eb639793e9
2019-04-17 18:24:11 +00:00
Joachim Steiger
6c5f4bae46 lms: Remove wrong unused code copied from -uhd
Change-Id: I2bc7fcfa429d1f82c2d8e95d31dfed367f2b3f9d
2019-04-17 18:24:11 +00:00
Harald Welte
71df42550a use BSC_FD_READ and not OSMO_FD_READ
We haven't even released any tagged version of libosmocore yet which
includes support for the renamed OSMO_FD_READ constant.  Let's avoid
any breakage and use the new constants only with considerable delay,
at the very least only when released libosmocore versions provide it.

Change-Id: Idb57077b2a4b2a71dd5d75a24ded8bb5887da188
2019-04-16 17:18:58 +02:00
Vadim Yanitskiy
24f05ea1f7 doc/configuration.adoc: fix incorrect number of physical RF channels for B210
Change-Id: I58e2bf5dd99e1655ebd2ad80f6ed2bb178f0e88d
2019-04-11 07:34:04 +00:00
Tom Tsou
d280045884 multi-ARFCN: fix maximum number of carriers limitation
Maximum number of carriers is fixed to 3 channels on a single
physical RF channel in multi-ARFCN mode. For some reason, it
was limited to 5.

Let's fix this, and also follow this limitation in the
following VTY command handlers:

  - cfg_multi_arfcn_cmd,
  - cfg_chan_cmd.

Change-Id: I66a1462f368458afd313ee6f0bc0abc496dde817
2019-04-11 07:33:40 +00:00
Pau Espin Pedrol
5e6f3e0cad osmo-trx: Check return code of osmo_fd_register
Fixes Coverity CID 197513.
Change-Id: I93fbcb062439a547379aaecba283d107fdc9cb59
2019-04-02 11:45:06 +02:00
Pau Espin Pedrol
21032b75c0 osmo-trx: Use signalfd to serialize signals in main thread ctx
This should avoid prolematic scenarios where different signal handlers
are running on different thread in parallel. Furthermore, we make sure
those signals are always run by main loop thread.

Change-Id: I9b9d9793be9af11dbe433e0ce09b7ac57a3bdfb5
2019-03-29 19:20:08 +01:00
Pau Espin Pedrol
d01c7b98b6 osmo-trx: Avoid handling signals after shutdown triggered
Recently a blocked osmo-trx process was found after ending SIGTERM to
it.
Apparently one thread was handling SIGTERM and calling fprintf()
(grabbing libc lock) while another thread was handling another signal
and also grabbing similar lock. Both thread looked deadlocked there.
Probably this change doesn't fix the block on its own, but at least
simplifies scenarios inside signal ctx which can go wrong.

Change-Id: If91621913b8b03d8a0f4c863be0b0d479f97e8a1
2019-03-29 18:51:28 +01:00
Sylvain Munaut
158ea5bc66 tests: Re-enable the convolve_test by default
Change-Id: Ia26ef75bb11482fc0db3b790db1c93c8b74229d1
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2019-01-24 20:02:54 +00:00
Sylvain Munaut
3733ed5097 tests: Rework the convolve_test
Besides just general cleanup, the major changes are :
 - Fully internal generation of reference data that doesn't
   depend on glibc or even on any floating point math
 - Golden results are included in a .h
   Due to varying precision of different implementation or
   architecture, any kind of textual compare is impossible, so
   we include golden values and compare results of both the
   'base' implementation the potentially 'optimized' one again
   this set of values with a small error tolerance

Change-Id: I4e203d2c4b778af77d630ed15d4cef6b0c0eb76d
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2019-01-24 20:02:46 +00:00
Vadim Yanitskiy
a8b3565246 VTY: add extended (11-bit) RACH detection toggle
Since I838c21db29c54f1924dd478c2b34b46b70aab2cd we have both TS1
and TS2 synch. sequences, in addition to "default" TS0. Let's
finally introduce the VTY configuration parameter, that can
be used to toggle optional detection of both TS1 and TS2.

Note: we keep this optional because of potentially bad impact on
performance. There's no point in paying the performance penalty
unless upper levels (BTS, PCU) actually make use of it.

Change-Id: I1aee998d83b06692d76a83f79748f9129a2547e8
Related: OS#3054
2019-01-24 15:47:48 +01:00
Sylvain Munaut
a3934a11a4 convolve: Remove support for step, offset parameters
- Those are not used any where
 - Those are not supported by the sse/neon accelerated versions
 - And I see very little use cases for those.

Change-Id: Ic850269a0ed5d98c0ea68980afd31016ed555b48
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2019-01-21 10:34:51 +01:00
Sylvain Munaut
acf804c034 arm/convolve: Fix the vfp4 real convolution for h_len=12
Change-Id: Ic73f0746edd3f1f22bb1d79d4c64aa740691dd48
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2019-01-21 10:34:51 +01:00
Harald Welte
d20b7fa579 Bump version: 0.4.0.125-7c78 → 1.0.0
Change-Id: Ibb888f55a1ab27088d5f21ee8ad699f4f747abde
2019-01-20 20:54:40 +01:00
Harald Welte
77e18352fb cosmetic: Don't call the SDR "USRP" in error message
Transceiver.cpp is used for all SDR hardware we support, not just USRP.

Change-Id: I9b7ddb0d679f111407704048ef3ddd964db49441
2019-01-11 22:42:29 +01:00
Harald Welte
f97d75b355 usrp1: Fix formatting of log message (missing space)
Change-Id: I378a8081a224acda3ee2af9b6aa0d680de884695
2019-01-11 22:42:29 +01:00
Harald Welte
a944001873 usrp1: Remove uninitialized skipRx logic
There appears to have been some logic to operate a USRP1 in
transmit-only GSM mode.  This is achieved using the skipRx member
of the transceiver object.  However, there's nobody that ever
initializes it properly, and hence the feature is not possible to
use anyway.

I don't think this has any valid use case, so let's remove it.

Change-Id: I616193f1e9aaefbf4ceb26761657811093f28b6f
2019-01-11 21:46:45 +01:00
Oliver Smith
42c165605a LMSDeviceTest: fix link errors on OBS
Link LMSDeviceTest against LMS_LIBS, so it does not only compile on
Debian, but also on Ubuntu and openSUSE. Thanks to roox for figuring
this out.

Related: OS#3654
Change-Id: I6980d4290f623485a77db10fea6d17de0321c092
2018-12-17 09:43:45 +00:00
Pau Espin Pedrol
affd351787 configure.ac: check boost only if USRP1 support is enabled
boost is only used in USRPDevice class.

It looks like it can be removed entirely quite easily, since only
boost::shared_ptr is used for 2 variables. That's left for somebody with
the device and willingness to test the changes.

Change-Id: I4c3fa3ff58fd552d0cb4c4cf2033615d84c07c96
2018-12-14 20:05:36 +00:00
Pau Espin Pedrol
03b11620d9 lms: Fix build against LimeSuite > 18.10
LimeSuite dc124e4e2ed9b549b142410af172f0592f9f0c23 > 18.10 broke API
compatibility.

OS#3729
Change-Id: Idf500a5b39a857233f728c6a4316c00a99374556
2018-12-14 13:30:07 +01:00
Pau Espin Pedrol
25185886f0 TimevalTest: Make test deterministic with fake time
Change-Id: I74e577a0142fb6d1ef3630e02aff9910b191bff9
2018-12-13 13:58:24 +00:00
Pau Espin Pedrol
47031405f5 Timeval: Move to osmo_clock_gettime
Change-Id: I24da3e1136c5396062662be1d10b07b4d97cfc2e
2018-12-13 13:58:24 +00:00
Pau Espin Pedrol
0646b3ce75 Timeval: Move implementation to use clock_gettime and timespec
According to gettimeofday manual:
"Applications should use the clock_gettime() function instead of the
obsolescent gettimeofday() function."

Furthermore, it may be desirable in the future to use other clocks such
as monotonic.

Change-Id: I2286998c5eefbf3c3dfb105c223daec7a1083803
2018-12-13 13:58:24 +00:00
Pau Espin Pedrol
46cf9efc8e Timeval: passed() returns true if time is equal
Change-Id: I96a9d26657f85447609693bc6932d218d354b84a
2018-12-13 13:58:24 +00:00
Oliver Smith
871713bf6a LMSDevice: make use of dev-args in osmo-trx.cfg
Allow selecting a specific LimeSDR device by setting dev-args in the
config file. Split up the given dev-args address by comma and select
the device where all substrings can be found.

I could not test this with real hardware, but I have added a test case
to make sure this works as expected.

Related: OS#3654
Change-Id: Ib9aaa066a01bf9de3f78234d7ada884d6f28c852
2018-12-13 11:07:02 +01:00
Oliver Smith
8d9a05ce5b osmo-trx.cpp: move comma_delimited_to_vector() to Utils.cpp
Make the "opt" argument const. This function will also be used by
LMSDevice.cpp in a follow-up commit.

Related: OS#3654
Change-Id: If3f0f682ca453c2b0a06175ec9626567932cfce6
2018-12-12 17:26:32 +01:00
Pau Espin Pedrol
fe865f45d7 lms: Do {under,over}run checks even if LMS_RecvStream fails
Under failure, it could still be that stream status is updated, so let's
father that in all cases.

Change-Id: I4e2b8be06d2993db1bab233948a8ee774b8ac4ee
2018-12-07 11:18:32 +01:00
Pau Espin Pedrol
e5b6664419 lms: Move {under,over}run checks into separate method
Change-Id: I7f450aa79f6285d14826c40ecfdd9490d00509ef
2018-12-07 11:18:28 +01:00
Pau Espin Pedrol
1595ddaa5f transceiver: Log TRXCTRL iface responses towards osmo-bts-trx
Change-Id: I8128c42e63ab1fcd2a58812f3b7cf94435b5bbd8
2018-12-07 11:15:10 +01:00
Pau Espin Pedrol
441d82add9 Add TRXCTRL log category
This log category is applied to messages related to TRX CTRL socket
interface, and it's printed in yellow, same color used in osmo-bts-trx
for TRX category (so same messages are printed with same color in both
sides).

Change-Id: I98ec5e416272783ad3fbadf70478a4e48ae64983
2018-12-07 11:15:02 +01:00
Oliver Smith
867cea575b contrib: fix makedistcheck with disabled systemd
EXTRA_DIST files need to be distributed, no matter if the systemd option
is configured or not.

Change-Id: I2e417f4c453987df1ac04f0ff41bf000da4b5c49
2018-12-06 16:31:30 +00:00
Pau Espin Pedrol
2f53ea4cf2 transceiver: log chan on CTRL command received
Change-Id: Ia3b2a35e03a8aaddd6efebc8db2ccca872f51f20
2018-12-05 19:43:46 +00:00
Pau Espin Pedrol
138caaf09d lms: Improve Set{Rx,Tx}{Gain,Freq} logging
Change-Id: I6713a27c5f74beb7fcfdd712fcf695afccbc3d76
2018-12-05 19:43:46 +00:00
Pau Espin Pedrol
3fadcad33e lms: Allow setting Tx/RxFreq for lchan!=0
Related: OS#3346
Change-Id: I9dd0bb41d1863111d28947fc0d7c7e7ecfaf5fa8
2018-12-05 19:43:46 +00:00
Pau Espin Pedrol
eaa0144dcb lms: Allow setting Tx/RxGain for chan!=0
Related: OS#3346
Change-Id: I5fae92a7ed5e2d92be12b9dfd33fc56195030c0b
2018-12-05 19:43:46 +00:00
Pau Espin Pedrol
f7331764ac SigProcLib: Improve Vector buffer allocation mess
Original issue: In order to use SSE instructions, 16-byte aligned memory
chunks are needed, and C++ version < C++11 doesn't provide for a native
new/delete store. For that reason, memalign() must be used in the
implementation of convolve_h_alloc() for some buffers.
On the other side, The C++ code relies on C++ "new T[]" operator to
allocate a chunk of memory containing an array of class instances. As
classes are complex types, they cannot be allocated through C structures
(calling malloc). Experimentally can be seen too that it's unreliable
and the process will crash during startup if malloc() is used and then a
Complex<> deferred from it.

Previous implementation allowed for use of convolve_h_alloc or new[]
based on how the (signal)Vector is called, because then the buffer is
not going to be managed internally. But that's unreliable since resize()
calling resize() on it could use "delete" operator on a malloc'ed
buffer, and end up having a new new[] allocated buffer. It was also
found that some of the callers were actually leaking memory through ASan (because the
buffer is not managed by the Vector instance).

IMHO best option would be to rewrite all this code using C structures
and malloc/free exclusively, since it would make all this cod eeasier to
maintain.

But for now, let's extend the Vector class to allow specifying an
external alloc/free function and let the Vector instance take care of
the ownership of the buffer in all scenarios.

Change-Id: Ie484a4762a7f77fe1b105188ea03a6f025730b82
2018-12-05 19:41:34 +00:00
Oliver Smith
800c029c70 jenkins.sh: run "make distcheck"
Run distcheck in CI to be consistent with other Osmocom projects.

Change-Id: I7d3fa0fe12e13ca13d3330158425718e5c34d00d
2018-12-05 16:26:35 +01:00
Oliver Smith
522cbe91d3 contrib/jenkins.sh: build and publish manuals
Add new environment variables WITH_MANUALS and PUBLISH to control if
the manuals should be built and uploaded. Describe all environment vars
on top of the file.

When WITH_MANUALS is set, install osmo-gsm-manuals like any other
dependency and add --enable-manuals to the configure flags (for "make"
and "make distcheck"). Add the bin subdir of the installed files to
PATH, so osmo-gsm-manuals-check-depends can be used by ./configure.

Related: OS#3385
Change-Id: I54fdd18e405b2c84762ea06d91359867ceec8184
2018-12-05 13:10:38 +01:00
Pau Espin Pedrol
ed361f9912 lms: Close device on LMS_Init failure
Change-Id: I0b307452a9e122a0ea39a46f096423c9a5293d30
2018-12-04 15:57:37 +00:00
Pau Espin Pedrol
2d085e290b osmo-trx: Change some lines to use libosmocore logging instead of cout
Change-Id: I66e3c37014ba12cd002e5b678bc0a6026f5dfc7e
2018-12-04 15:57:37 +00:00
Pau Espin Pedrol
5cea18e5cb lms: Make sure LMS_Close is called when Device is torn down
This change fixes lots of memory leaks inside libLimeSuite as
announced by ASan after exiting the osmo-trx process (throgh
CTRL+C for instance).

This way also we make sure libLimeSuite can communicate with the HW and
close whatever subsystems were enabled during LMS_Open time.

Change-Id: I56ffb87079e34aa2d0322fd2ca6429742f9f7640
2018-12-04 15:57:37 +00:00
Oliver Smith
4adc4eb8d0 Fix DISTCHECK_CONFIGURE_FLAGS override
Set AM_DISTCHECK_CONFIGURE_FLAGS in Makefile.am instead of
DISTCHECK_CONFIGURE_FLAGS. This is the recommended way from the
automake manual, as otherwise the flag can't be changed by the user
anymore.

Related: OS#3718
Change-Id: I725026cd2dda333085a263c503058aac4305197d
2018-12-04 15:41:40 +01:00
Pau Espin Pedrol
41c68aa41c PointerFIFO: Fix memleak of ListNode
Found by ASan. when PointerFIFO::release() is called, alloicated node
being released is actually stored into an internal list for later-reuse
without having to access memory allocator. However, nodes from this
list are never freed.

Change-Id: I40e5e28603cde67005d9d92772967b05465ea2b8
2018-12-03 12:59:12 +00:00
Pau Espin Pedrol
39e0bbacca radioInterface: Fix memleak during close()
destructors of pointers created through "new" must be destroyed manually
through "delete".

Change-Id: I10d37579f16bec89cc762f200a8951218305c708
2018-12-03 12:20:07 +01:00
Pau Espin Pedrol
b4ea7b5211 lms: Destroy streams on device stop
They are recreated during start(). Actually, if they are not stopped
here, during start() after stop(), LMS_SetupStream() will fail because
it will detect the streams are already opened.

Change-Id: I70d47c287aabdabc5dc1304a942d130aeb10bdc5
2018-12-03 11:34:25 +01:00
Pau Espin Pedrol
69869bd58f lms: Fix start after stop of device
Change-Id: I56358a1d1601853bc6dd2e6bb5f80798d0ba84b2
2018-12-03 11:19:52 +01:00
d0gtail
ebb37693a5 UHDDevice: log exception information on device open failure
Change-Id: Ia84ddcf50cc83f9326b22bfdfb4f259b4e0bc5f1
2018-12-02 20:01:26 +00:00
Harald Welte
55928f23cb lms: Set Rx gain to midpoint, as comment suggests.
So far, the Rx gain was set to 34 dB, wile the comment stated it
would be set to half-point, which is 73/2=36dB.  Let's adjust the
code to match the comment.

Change-Id: Idc646def53b83faf4e6c011fb595fa436e223b32
2018-11-29 13:26:37 +01:00
Harald Welte
0277b58f6d lms: User correct scale factor for transmit samples
Due to (I believe) a copy+paste mistake from the USRP1 code,
we were using only a scale range of up to 9830 when transmitting
samples, rather than the full 16 bit signed integer range up to
32767.

As a result, we were loosing almost two bits (MSBs) of resolution
as well as a lot of transmit power.

This changes the scale factor to 0.707 (1/sqrt(2)).

Please note that the much higher DAC output level means that the analog
gain should be reduced.  The theoretic range of up to 73dB should not
be used, but Lime Microsystems suggest a value of 61..67 dB.  This can
be achieved by using a "osmotrx tx-attenuation" value of 6..12 inside
the osmo-bts-trx configuration file.

Related: OS#3341
Related: OS#3342
Change-Id: I71702feaa11f53e7614a6938a984dd748405474a
2018-11-29 13:23:08 +01:00
Oliver Smith
be8a83f681 build manuals moved here from osmo-gsm-manuals.git
Moved to doc/manuals/, with full commit history, in preceding merge commit.
Now incorporate in the build system.

Build with:

$ autoreconf -fi
$ ./configure --enable-manuals
$ make

Shared files from osmo-gsm-manuals.git are found automatically if
- the repository is checked out in ../osmo-gsm-manuals; or
- if it osmo-gsm-manuals was installed with "make install"; or
- OSMO_GSM_MANUALS_DIR is set.

Related: OS#3385
Change-Id: I2762171af0bf719a34ba12a0c2e4dcc206098beb
2018-11-27 18:36:41 +01:00
Neels Hofmeyr
d9a460dce9 Merge history from osmo-gsm-manuals.git 2018-11-27 18:36:29 +01:00
Pau Espin Pedrol
f570b4af62 osmotrx: Introduce code architecture chapter
Change-Id: I21084e6315d79a1adcb305e12343da218837dc31
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
46560ea254 osmotrx: Create a common chapter for section documenting backends
Change-Id: I6bea1ccca4ce72b92641a36f9f5894ac9a6cae72
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
038ab45137 osmotrx: configuration: Add section to document multi-arfcn feature
Change-Id: Id04c7f7c36d8a8be8145ef8009ece26ef1a7cdff
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
6b50b62b12 osmotrx: Write initial documentation for several supported devices
Change-Id: I902b01ca661416eb9705afac8a34ec8d2fb13789
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
3984256273 osmotrx: Split Device specific section from backend one
Device specific sections will be added to this new chapter.

Change-Id: Id96cbf857e2ef92d9ad2cb58fd18132f981447d7
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
d06172ce32 trx: Add Hardware device support section
Change-Id: I87fc54cf1751f31a3e92d6503625e984f9a6130f
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
762c951faa trx: Add Hardware architecture support section
Change-Id: I38388bcb2ea7c0481052d3bca589cb34965ea7fa
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
e47d7e964a trx: Add reference to project wiki page in overfiew section
Change-Id: I83cbd67909c42f4ed4857834e23c07ad4e2e22aa
2018-11-27 18:36:18 +01:00
Harald Welte
3cee25ac68 vty-ref: Update URI of docbook 5.0 schema
... to match the /etc/xml/catalog file on debian (no "www" in hostname)

Change-Id: Id9f3579c7f2bc3af13fe30b5268f249b6f59ed0d
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
0bd0782a39 Introduce chapter trx_if.adoc and add it to OsmoTRX and OsmoBTS
This chapter defines the protocol used between osmo-trx and
osmo-bts-trx.

Most of the text comes originally from osmo-trx.git/README, as it's the
only known documentation of the protocol other than the code itself.

Change-Id: I56c418eef0f826ae1aadbed5b151fbed241c7885
2018-11-27 18:36:18 +01:00
Pau Espin Pedrol
8072650406 Introduce OsmoTRX manual
Change-Id: I19ee9d6cda02fb7200c96c0ac129e69825b096cd
2018-11-27 18:36:18 +01:00
Neels Hofmeyr
c6541e6c26 Importing history from osmo-gsm-manuals.git 2018-11-27 18:36:03 +01:00
Pau Espin Pedrol
1e2c0105e2 lms: Apply LMS->OSMO log level conversion
Change-Id: I3a8fbcc7cacebc7038c60175a8ae43b21f713cbb
2018-11-23 14:39:51 +01:00
Pau Espin Pedrol
32b3c2e4b2 lms: Use LimeSuite.h log level defines instead of hardcoded values
Change-Id: Iee693da1a0fa1db23deafa8d3845c04171e24799
2018-11-23 14:39:06 +01:00
Pau Espin Pedrol
1c4bbadda6 UHDDevice: setRxGain on chan 0 when using multi-arfcn
When using multi-arfcn feature, several logical channels (arfcn) are multiplxed
into one physical transceiver, as can be seen in
uhd_device::set_channels.

As a result, when multi-arfcn is enabled some properties are actually
shared for those logical channels, and internally mapped to the first
(only existing) channel, and per-channel internal array variables are allocated
accordingly (size() == 1).

When setting RxGain, we need to set the correct existing physical
channel. Same check is done in getRxGain, and then we apply the RxGain correctly and
we avoid outputing an error "Requested non-existent channel" immediatelly after.

Change-Id: I5b02bb1ef6450dc48be7b8058d96a5691847d3cc
2018-11-19 11:47:37 +01:00
Pau Espin Pedrol
08dfe237c8 ChannelizerBase: Fix ASan alloc-dealloc-mismatch
Fixes following Adress Sanitizer warning:
=================================================================
==27120==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs operator delete) on 0x60c00003d900
    #0 0x7f2f216de421 in operator delete(void*, unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:151
    #1 0x561641ce18b7 in ChannelizerBase::~ChannelizerBase() (/build/new/out/bin/osmo-trx-uhd+0x4a8b7)
    #2 0x561641ce1cad in Channelizer::~Channelizer() (/build/new/out/bin/osmo-trx-uhd+0x4acad)
    #3 0x561641cd5160 in RadioInterfaceMulti::close() (/build/new/out/bin/osmo-trx-uhd+0x3e160)
    #4 0x561641cd5047 in RadioInterfaceMulti::~RadioInterfaceMulti() (/build/new/out/bin/osmo-trx-uhd+0x3e047)
    #5 0x561641cd5093 in RadioInterfaceMulti::~RadioInterfaceMulti() (/build/new/out/bin/osmo-trx-uhd+0x3e093)
    #6 0x561641ca3fdd in trx_stop() (/build/new/out/bin/osmo-trx-uhd+0xcfdd)
    #7 0x561641ca4b32 in main (/build/new/out/bin/osmo-trx-uhd+0xdb32)
    #8 0x7f2f1f555222 in __libc_start_main (/usr/lib/libc.so.6+0x24222)
    #9 0x561641ca195d in _start (/build/new/out/bin/osmo-trx-uhd+0xa95d)

0x60c00003d900 is located 0 bytes inside of 128-byte region [0x60c00003d900,0x60c00003d980)
allocated by thread T0 here:
    #0 0x7f2f216dcf19 in operator new[](unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:93
    #1 0x561641ce142d in ChannelizerBase::init() (/build/new/out/bin/osmo-trx-uhd+0x4a42d)
    #2 0x561641cd5865 in RadioInterfaceMulti::init(int) (/build/new/out/bin/osmo-trx-uhd+0x3e865)
    #3 0x561641ca1cb7 in makeRadioInterface(trx_ctx*, RadioDevice*, int) (/build/new/out/bin/osmo-trx-uhd+0xacb7)
    #4 0x561641ca44c6 in trx_start(trx_ctx*) (/build/new/out/bin/osmo-trx-uhd+0xd4c6)
    #5 0x561641ca4b05 in main (/build/new/out/bin/osmo-trx-uhd+0xdb05)
    #6 0x7f2f1f555222 in __libc_start_main (/usr/lib/libc.so.6+0x24222)

SUMMARY: AddressSanitizer: alloc-dealloc-mismatch /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:151 in operator delete(void*, unsigned long)
==27120==HINT: if you don't care about these errors you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
==27120==ABORTING

Change-Id: Ib7c98ae478f319573dd86a0d2cb264f676bb3859
2018-11-01 18:23:32 +01:00
Vadim Yanitskiy
444ff34396 sigProcLib: add a CorrType for extended (11-bit) RACH
This is a preparatory change that enables a possibility to choose
the amount of synch. sequences to be used for Access Burst (RACH)
detection. The VTY flag will be introduced in further changes.

There are two correlation types now:

  - RACH (default) - TS0 only;
  - EXT_RACH - all TS0, TS1, and TS2 together.

Change-Id: Ia4f20524350bb8c380d7e10360758eddae8b03e9
Related: OS#3054
2018-10-24 19:28:47 +00:00
Vadim Yanitskiy
a79bc70737 sigProcLib: introduce both TS1 and TS2 RACH synch. sequences
According to 3GPP TS 05.02, section 5.2.7, there are three
synch. sequences for Access Bursts:

  - TS0: GSM, GMSK (default),
  - TS1: EGPRS, 8-PSK,
  - TS2: EGPRS, GMSK.

Let's prepare everythyng to be able to detect all TS0-3 synch.
sequences, but keep detection of both TS1 and TS2 disabled
until the corresponding VTY option is introduced.

Change-Id: I838c21db29c54f1924dd478c2b34b46b70aab2cd
Related: OS#3054
2018-10-24 19:28:47 +00:00
Oliver Smith
a439fed166 Add long parameters (--help, --version, ...)
Makes osmo-trx-* more consistent with other Osmocom programs, and
allows an unified test for not having "UNKNOWN" in --version.

Related: OS#3578
Change-Id: I90cf01d972aa10b48c59b67a1e7f82a4255ef526
2018-10-23 11:34:43 +00:00
Harald Welte
8fb0c3dce4 trx_validate_config(): Fix validation of rx_sps
Change-Id: I7e932cff59335add09c76caba6f9ac1e7cf69022
Fixes: Coverity CID#188871
2018-10-21 13:48:26 +02:00
Harald Welte
f5e1cf8790 SocketsTest.testReaderIP(): Zero terminate received buffer
Change-Id: Icd144e672ab15cfb0955897dd6eb529c56908eba
2018-10-21 12:14:55 +02:00
Pau Espin Pedrol
e7d267f178 jenkins.sh: Enable build of osmo-trx-lms
Change-Id: Idfa7ce566ad69b181bcadeee7ff023c77ecd4d6b
2018-10-09 14:08:41 +02:00
Pau Espin Pedrol
06f3b622b8 examples: Use logging level 'set-all' instead of 'all'
Change-Id: Ic52ce0defc774acb8e24947ed22cf2a56b8b0bb0
2018-10-05 16:49:23 +02:00
Pau Espin Pedrol
74bcc562a9 Transciever: Log values causing Tx underrun
Change-Id: I68e18075eade55034567d96fc774d00a794afeeb
2018-10-02 17:30:28 +02:00
Pau Espin Pedrol
55dd2aa5ab CommonLibs/Makefile.am: Specify libcommon_la_LIBADD
This way the dependencies are passed after the .la object, which seems
to be the correct order. Some setups may fail to find some symbols from
libosmocore otherwise (OBS i586).

Change-Id: I22c80055bcffd4179a0a8ca76533ba7aaa38c859
2018-10-02 09:34:55 +02:00
Pau Espin Pedrol
5b60c98769 Use pthread_setname_np to name threads
osmo-trx can start a considerable amount of threads that can make
debugging it challenging at least. By using phtread_setname_np, the
system sets a meaningful name to the thread which can be seen while
debugging with gdb or by printing /proc/$pid/task/$tid/comm.

Now we also log system TID when setting the name so we can identify
different tasks in /proc even if pthread_setname_np fails.

Change-Id: I84711739c3e224cb383fd12b6db933785b28209e
2018-09-28 23:17:57 +00:00
Harald Welte
207d8a2624 ensure well-formed example config files
Change-Id: I9be2bab3b88a96e94e463e5ab22f9814bd6de950
2018-09-25 18:51:51 +00:00
Vadim Yanitskiy
92fc186450 device/lms/LMSDevice.cpp: fix compilation warning
The following warning was observed with GCC 4.8.5:

  make[4]: Entering directory `.../osmo-trx/Transceiver52M/device/lms'
    CXX      LMSDevice.lo
  LMSDevice.cpp: In member function 'LMSDevice::writeSamples()':
  LMSDevice.cpp:582:22: warning: 'rc' may be used uninitialized
                        in this function [-Wmaybe-uninitialized]
    samplesWritten += rc;

Let's fix this by zero-initializing 'rc'.

Change-Id: I4b4a061fc12e5fd1db8d1087d8e0c46ff1e23412
2018-09-20 16:17:19 +07:00
Pau Espin Pedrol
4d179abfd0 cosmetic: Use proper whitespace in several for loops
Change-Id: I82bdeb8a3fa38f3d125e8cbccc3eddbf2b8d8f58
2018-09-13 14:27:48 +00:00
Pau Espin Pedrol
6fdfb68b9e Install sample cfg file to /etc/osmocom
Change-Id: Ib871a3cd14386ef6e6b512a3d66e7e7a839295a5
2018-09-12 20:51:29 +02:00
Pau Espin Pedrol
5ac2cb3662 Install systemd services with autotools
Change-Id: Ia1a4fb62dee35737ece1f3501f352501eba2449e
2018-09-12 14:17:26 +02:00
Pau Espin Pedrol
f4ee021b8c jenkins.sh: Add --enable-werror flag to osmo-trx configure step
This way we catch newly introduced compilation warnings in osmo-trx.

Change-Id: I7effaf243fd6e7fe69728cfce5f97e0b5bd4743c
2018-09-10 10:33:39 +02:00
Pau Espin Pedrol
e62555370e Vector: Copy arrays in a sane way for non-trivially copyable types
Avoids this type of compilation warnings:
‘void* memcpy(void*, const void*, size_t)’ writing to an object of non-trivially copyable type ‘class Complex<float>’; use copy-assignment or copy-initialization instead [-Werror=class-memaccess]

Change-Id: I9724454dfb7b87f74f39074e4004580ac3b5fe5c
2018-09-10 10:33:34 +02:00
Pau Espin Pedrol
1f15152968 radioInterfaceMulti:pullBuffer: Sanely convert float array to complex array
Fixes this type of compilation warning:
‘void* memcpy(void*, const void*, size_t)’ writing to an object of non-trivially copyable type ‘class Complex<float>’; use copy-assignment or copy-initialization instead [-Werror=class-memaccess]

Change-Id: Ibb2380a0a335ce798fe87221519fbbebade53054
2018-09-10 10:30:06 +02:00
Pau Espin Pedrol
21ce05c54f cosmetic: Fix trailing whitespace in several files
Change-Id: Ibf5a69f0a3a309e87814635fd903b114fe68890c
2018-09-10 10:30:06 +02:00
Pau Espin Pedrol
5e68cde779 SigProcLib: Use available copyTo Vector API instead of memcopy
This change allows to remove some wrong use of code as per compilation
warning:
osmo-trx/Transceiver52M/sigProcLib.cpp:1266:40: error:
‘void* memcpy(void*, const void*, size_t)’ writing to an object of non-trivially copyable type ‘class Complex<float>’; use copy-assignment or copy-initialization instead [-Werror=class-memaccess]
   midMidamble->size() * sizeof(complex));

Change-Id: Id446711349bec70fa4e7c8efe0f7f9faf7e4f277
2018-09-10 10:30:06 +02:00
Pau Espin Pedrol
1f4a009c67 UHHDDevice: Replace deprecated header uhd/utils/thread_priority.hpp
Fixes compilation warning:
In file included from osmo-trx/Transceiver52M/device/uhd/UHDDevice.cpp:31:
/usr/include/uhd/utils/thread_priority.hpp:10:17: note: #pragma message: This header is deprecated - please use <uhd/utils/thread.hpp> instead.

Header was moved in uhd.git c33928d2bbdd27688c3475e77fc461e7d16eba5a.

Change-Id: I6299df48a5e14c54eaa07288d166c705eb9ebdbe
2018-09-10 10:30:06 +02:00
Harald Welte
544ce0d6b7 update git-version-gen to generate proper version numbers
We don't want the version of the last tagged version, but the version
number uniquely representing the current HEAD.  Use the script from
libosmocore.

I suspect that this somehow got broken in commit 00d5114717

Related: OS#3517
Change-Id: Iba3212aa417dce4240c5c27eb4f12afcd9c95e5b
2018-09-04 18:01:35 +00:00
Pau Espin Pedrol
b148d05542 configure.ac: Specify default language as C++
This is useful if we add more AC_CHECK_HEADER or similar configure tests including
C++ header files or required C++ features, since otherwise gcc is used
by default and test fail.

Change-Id: Iee757c78b72290c5d2a4c31339800a4e72b6be23
2018-09-04 18:00:57 +00:00
Pau Espin Pedrol
970096932e radioInterface: Fix variable storing integer return value
Change-Id: I0a0a06a6d16a228cfcb7bd746bab2d79f10ce244
2018-09-04 16:35:27 +02:00
Pau Espin Pedrol
db936b9b55 osmo-trx: Add osmo_signal to stop whole transceiver chain correctly on error
Transceiver::stop() can only be called from either CTRL iface thread or
from main thread (running osmocom loop). That's because stop attempts to
cancel and then join all the other threads, which would then lock if
attempting to stop from some of them.
As a result, the best option is to indicate to the user of the
transceiver option (osmo-trx.cpp) to stop it in a correct fashion by
destroying the object from the main thread.

Change-Id: Iac1d2dbe2328e735db2d4b933cb67b1af1babca1
2018-09-04 16:35:23 +02:00
Pau Espin Pedrol
49ad759072 lms: Return error on device read timeout
If LImeSDR device is unplugged or its fw crashes during operation,
reading from the device will fail and will first receive short reads and
finally 0 byte reads. Let's quickly notify these events to upper layers
instead of trying to process the buffer and checking timestamps for
something we know it's already not useful.

Related: OS#3340
Change-Id: Ib1af8cdd6cdadf581b039882add4049eea45a0f7
2018-09-03 18:53:52 +02:00
Pau Espin Pedrol
8e498bfd35 radioInterface: forward errors from RadioDevice to Transceiver in recv path
Change-Id: Id7b08b19d6575c79b4d57db656a17ff05bb61ee9
2018-09-03 18:53:52 +02:00
Pau Espin Pedrol
46444637c6 cosmetic: Fix trailing whitespace
Change-Id: Ia647cfed0acb35adeb9b3b7824170d06c0369ef7
2018-09-03 18:53:41 +02:00
Pau Espin Pedrol
86be40b4eb Logger: Disable pthread cancel point inside Logger destructor
pthread_cancel is implemented in c++ using exception handlers. In
destructor of Log object, the log function is called which will
eventually call fputs() to write to a file. Since that function is
considered a cancelation point, if pthread_cancel has been called the
exception handler will start unstacking frames and calling destructors
in the process. At some point this will cause a runtime exception in c++
which will call std::terminate() to abort the process.

The solution is thus to avoid starting the cancellation process inside the
destructor.

This behavior was spotted while calling the destructor of Transceiver
object in forthcoming patches.

See a more detailed example here:
https://skaark.wordpress.com/2010/08/26/pthread_cancel-considered-harmful/

Change-Id: I71ca90f3fbc73df58b878a03361f7b7831d838b4
2018-09-03 15:22:53 +02:00
Pau Espin Pedrol
288d8af070 configure.ac: Add --enable-werror option
Change-Id: Ib2782aecd400398bf36427f255c2a427ef781e06
2018-08-30 17:30:15 +02:00
Pau Espin Pedrol
aae403f0c9 vty: Fix typo in gpsdo clock reference type
Change-Id: I3f553c2cec9689524728cacb15b7daaff8166925
2018-08-27 16:50:19 +02:00
Harald Welte
5cc8858d8f logging: Introduce new "DDEV" category for device-specific code
The DMAIN category got too overloaded.  Let's have the code in
Transceive52M/device/* use the new DDEV category.

Also, in some cases the log levels have been adjusted to ensure
that enabling INFO level should not result in a complete overflow
of messages during normal operation.

Change-Id: I844fe4a75bf277cd3cc5bd8fa06e06ad97b2ea95
2018-08-17 19:57:40 +02:00
Pau Espin Pedrol
70d0344b31 configure.ac: Fix typo in with-lms help string
Change-Id: I7777d027fffa50dddf3f0a3c0bf2173aa8497be3
2018-08-17 17:17:05 +02:00
Alexander Couzens
62002fb8ac debian: add patches for debian8
The osmocom-nightly/release can create debian8 package by patching
rules and control files

Change-Id: I261302d2ed16e76540073589504e7426e23d00a1
2018-08-09 05:02:36 +02:00
Harald Welte
03b3c30533 Fix config file saving of {tx,rx}-path VTY config strings
We were missing one indent level when writing the rx-path and tx-path

Change-Id: I5d5b02c71d39220cabc2a23d059908ef3c6350e0
Closes: OS#3435
2018-07-31 15:48:18 +02:00
Pau Espin Pedrol
a4b569d936 debian: Explicitly enable osmo-trx-uhd build
osmotrxuhd is already being built since it's enabled by default, but
let's make it more explicit that we are building it too.

Change-Id: Ie9c224485cce047cd3ee4600ff7fbdb082355cdc
2018-06-25 17:02:22 +02:00
Pau Espin Pedrol
eb0945d85d debian: Enable build of osmo-trx-lms
Change-Id: I4711e97c844e582601a588fdc359fc020bcee001
2018-06-25 16:09:25 +02:00
Pau Espin Pedrol
f968507912 Use correct paths when installing example files
Fixes: c7756e73b7
Change-Id: If55d14768727c7119d86da60413861674dd3538b
2018-06-25 12:57:17 +02:00
Pau Espin Pedrol
58c89fb8d6 lms: Allow values diff than 34dB to be set by setRxGain()
Until now, setRxGain in LMSDevice did not take into account the setter
parameter and was always using hardcoded 34dB, which was experimentally
found to be a good default value.

Let's force that value during initialization, but still allow the upper
layers (controlled by BTS) to set different values. osmo-bts only sends
a SETRXGAIN command (which calls setRxGain in osmo-trx) if a value is
explicitly set in its VTY config, so we are on the safe side if the user
doesn't explicitly configure a desired dB.

Change-Id: I5684e675281a3f581855dbb56d199a6fe238a712
2018-06-20 07:41:16 +00:00
Pau Espin Pedrol
16e7e20f85 Add -V param to print version
Change-Id: I9f2d6c4b1a508aceb1ccc0559f0902eedf2ec5af
2018-06-20 07:38:36 +00:00
Pau Espin Pedrol
c7756e73b7 debian: Add cfg file examples for osmo-trx-{lms,uhd}
Sort cfg files according to their osmo-trx binary.
Install them during make install.
Add the installed cfg files to related debian packages.

Change-Id: I905cdac30b441e4df0a3f5c0924d1637b9f67b90
2018-06-19 11:31:45 +02:00
Pau Espin Pedrol
7ed686b223 contrib: Add systemd services for all backends
Change-Id: I38a7ff7b9dafc3d6aa0426777036e3d7666045a7
2018-06-19 11:05:04 +02:00
Pau Espin Pedrol
2ab6ddb0de debian: Add package osmo-trx-lms
Change-Id: I3213c66907fbf0c7e531835b4993fa1bdc89edc3
2018-06-19 11:05:04 +02:00
Harald Welte
b229439b31 usrp1: Fail in case of unsupported configuration
There might be some configuration that's not supported by osmo-bts-usrp1,
and we should reject that properly.

Change-Id: Ic7308ce0c57439fe97668bd31801c4bf76b797ad
Closes: OS#3348
2018-06-14 12:38:09 +02:00
Harald Welte
ffb3301bd8 lms: Fail in case of unsupported configuration
There might be some configuration that's not supported by osmo-bts-lms,
and we should reject that properly.

Change-Id: I6f82edce589030a4407f6150fb7e8abe6417c1f2
Closes: OS#3347
2018-06-14 12:38:09 +02:00
Harald Welte
62b7900fd7 lms: Fix coding style
In Change-Id Ib2fca81b76d027b08e2891056fa076d071597783 we introduced
some coding style violations.  Let's make newly-added code follows
standard Osmocom coding style.

Change-Id: Ib7ddd275014f03a2eed3cddc02b1356e2b00c0bc
2018-06-14 12:38:09 +02:00
Harald Welte
61707e8b23 radioDevice: better encapsulation in base class
It's not good style to have the derived classes initialize members
inherited from the base class using "this->foo = bar".  Rather, let's
make the base class have a constructor, and call that constructor to
initialize the members of the base class.

While doing this
* rename 'offset' to 'lo_offset' to avoid confusion with timestamp offset
* move 'InterfaceType' into the base class
* move 'chans' into the base class
* move 'rx_sps' into the base class
* mark base class members as 'protected'

Change-Id: Ib885675a7612a392aa7f75fca81269ddcff2f6ab
2018-06-14 12:38:04 +02:00
Harald Welte
ce70ba529c radioDevice: Move tx_sps from derived into base class
All three derived classes use a tx_sps member, let's move this into
the base class.

Change-Id: I73b4aa2705c5049561e2d7b21301a0d2b3c96ced
2018-06-13 23:46:27 +02:00
Harald Welte
cfb9dac70d lms: Call set_antennas() during open() method
Without this call, the antenna/path configuration is not applied.

Change-Id: I0bca58266b59f1315ec72b6407fe4f4495aff678
2018-06-13 23:46:27 +02:00
Harald Welte
105a61e689 lms: Fix support for rx_paths / tx_paths
Before this patch, any configuration in osmo-trx.cfg regarding the rx
and tx "antenna" (path) would have been completely ignored, as the
radioDevice::make() function would simply drop those arguments to the
floor.

Change-Id: Ie50f854abbc9dcf351cddc052d10206382e1d5d3
2018-06-13 23:46:27 +02:00
Harald Welte
2407314f2e move set_antennas() from UHD to generic radioDevice base class
Change-Id: I806143e9db21f0be4dcc6a376b3a630be7aeb3ba
2018-06-13 23:46:27 +02:00
Zydrunas Tamosevicius
ff4418539c lms: Reduce Rx gain from 47 to 34 dB
Initially, Rx gain was hardcoded to be 47. This was too high for our
setup and we were constantly getting "clipping detected" messages.

Reducing Rx gain to 34 solved the issue. However, it looks like gains
should be controlled through configuration files.

Change-Id: I30580f18c4ad630c09f725b1d24c125fc3119809
2018-06-13 21:45:32 +00:00
Zydrunas Tamosevicius
0494d05916 lms: fix LMS_StartStream() handling for multiple channels
LMS_StartStream() (in LMSDevice::start()) was moved to separate loop. It
is because LMS_SetupStream() would fail for second channel if streaming
has already been started (LMS_StartStream()) for single channel
configuration.

Change-Id: I6704bb92864aa81417507c4ae24a22f41dc529c1
2018-06-13 21:45:32 +00:00
Zydrunas Tamosevicius
fd268b6f5a lms: Reduce log level of "send buffer of len ..."
Log level of "send buffer of len ..." messages was changed as it was
causing problems on some machines.

Change-Id: I605d50e81966c7bd169b27788d62af6fb54c84e1
2018-06-13 21:45:32 +00:00
Zydrunas Tamosevicius
43f3678b40 lms: Use same timestamp offset like when using LimeSDR via UHD
The tx timestamp offset was not set. We set it to the same value as it
was in UHD interface for LimeSDR

Change-Id: I78bc40cd575097f71a5f82b63467fa81c3f8d837
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
6493dc838b lms: Check LPBFW to set is within supported range
As of LimeSuite 618fbb9c3188b36d75ad5785a97b8887dcc468f6, it seems 5e6
is within the returned range, but LMS_SetLPFBW fails anyway.

See for more information: https://github.com/myriadrf/LimeSuite/issues/184

Change-Id: I967e7da7c0e3e8138b76733ee4a0e6311d20b62e
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
f7905ac548 lms: Makefile.am: Reorder params to fix link issue
It seems the order in which static code and -lfoo is passed to the
linker matters.

This commit is a lms specific follow-up of commit
2a8183bdf0.

Change-Id: I59c20d268ecac4c22689124165c47295bd9176d4
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
0c27938d44 LMSDevice: Fix setup failure with LimeSuite > 18.04.1
Fixes: https://github.com/myriadrf/LimeSuite/issues/184

Change-Id: Ia9f37995cd10d19d6820e3e12b8ee8f3efbff5d4
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
587916e810 LMSDevice: Set correct values for Max{Tx,Rx}Gain
Change-Id: I3b3a7080a69e15d8d6770186810d922227439099
2018-06-13 21:45:32 +00:00
Harald Welte
79024867de LMSDevice: Reduce Rx logging verbosity: Only log unexpected timestamps
Change-Id: I06b35efb7368616b9f4d348da574cd524ffe3ea6
2018-06-13 21:45:32 +00:00
Harald Welte
4aec1f1cf5 LMS_Device: Set ts_offset to 0.
I'm not quite sure what the ts_offset is for, but by using "0"
we are now receiving exactly the timestamp that we're expecting:

LMSDevice.cpp:486 [tid=140576250332928] chan 0 recv buffer of len 2500 expect 305ed0 got 305ed0 (305ed0) diff=0

Change-Id: I270c94945b1af9662cfc468cfda1ae3af3ac0a27
2018-06-13 21:45:32 +00:00
Harald Welte
68f054169b LMSDevice: Fix initial timestamp offset of 2500
ts_initial must not point to the timestamp of the first sample
in the last "flush" sample buffer, but to the first timestamp we
expect in the next buffer.

Change-Id: I23af62870544d4c6cf5f6e2d6578936603bceb91
2018-06-13 21:45:32 +00:00
Harald Welte
ea8be22e50 LMSDevice: Set low-pass filters to smallest possible option
Rx 1.4 MHz, Tx 5MHz.  Both massively too wide for GSM, but there's
no smaller band-width available.

Change-Id: I9723c9a2ea77f65bfa9d796d7c44adc2417e89cf
2018-06-13 21:45:32 +00:00
Harald Welte
a5054b398b LMSDevice: Typo fix: s/Internal/External
Change-Id: Icacfe6da90a89c7f00d62c580948fb913998eaa7
2018-06-13 21:45:32 +00:00
Harald Welte
a438114173 LMSDevice: Print sample rate range + actual sample rate after setting it
Change-Id: I19c1a5b2d2431b8d39e277244e313f6e559e4d25
2018-06-13 21:45:32 +00:00
Harald Welte
9cb4f27112 LMSDevice: Call LMS_Init() before setting sample rate
LMS_Init() will override basically all device settings with their
default value, including the sample rate.  We hence have to make sure
to call it before any other API function that changes the device config
such as sample rate, frequency, filter bandwidth, ...

Change-Id: I4cdbae8406b5e1e93da491e90f8bad41d4be748b
2018-06-13 21:45:32 +00:00
Harald Welte
c38e45e9dc update .gitignore to include osmo-trx-lms
Change-Id: I52efd2f71eb61baa80427ab9f7b518f17d514792
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
1f50fedb5f build: Add support for LimeSuite device backend
Change-Id: I239e1b37263a62b374d84974c9347e3654072e87
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
c7a0bf1ffc lms: Several improvements and compilation/runtime fixes
Continuation of initial work done on LimeSuite support from Harald.

Change-Id: Ib2fca81b76d027b08e2891056fa076d071597783
2018-06-13 21:45:32 +00:00
Harald Welte
940738e86a Initial work towards direct LimeSuite support in OsmoTRX
This is work in progress towards a direct LimeSuite driver in OsmoTRX,
bypassing the currently rather complex stack of wrappers by going
through UHD, SoapyUHD, SoapySDR and LimeSuite.

Change-Id: Iaef29c4c2585ef8c2f94866c9591919f538c1a2d
2018-06-13 21:45:32 +00:00
Pau Espin Pedrol
8c1e2bddff examples: Set rt-prio 18 and print file basename
Change-Id: I16fbdd46f2d9b6f3e79a4bb357f6a7fbed14244a
2018-06-12 18:23:40 +02:00
Vadim Yanitskiy
01eea0aa42 trx_vty.c: fix: use CONFIG_NODE as parent by default
There are some configuration nodes, which are handled by extenral
libraries, such as libosmoctrl. So, when switching back to the
parent node, this should be kept in mind.

Instead of aborting, let's got to the CONFIG_NODE by default.

Fixes: OS#3250
Change-Id: Ia0600a46d19825806e5aed9257b6c57c3907808b
2018-05-09 15:19:56 +07:00
Pau Espin Pedrol
55df1e43e3 UHDDevice: Fix setup failure with LimeSuite > 18.04.1
Fixes: https://github.com/myriadrf/LimeSuite/issues/184

Change-Id: I48ead8b8996981263297b66c0c7d3d0972261316
2018-05-08 20:49:04 +02:00
Pau Espin Pedrol
e9424e241f doc: examples: Add umtrx sample config
Change-Id: Id38de0bbbe75e5e6bbb0de2eecb7d1984786d528
2018-05-04 14:01:50 +00:00
Pau Espin Pedrol
d0ac926b56 Bump version: 0.3.0-dirty → 0.4.0
Change-Id: Ifc469bce89d52012e1f876c847b4535360a602ad
2018-05-03 16:23:30 +02:00
Pau Espin Pedrol
00d5114717 git-version-gen: Take into account tags not in master
Latest tag 0.3.0 was created in a release branch instead of master. As a
result, git describe doesn't show them. Let's instead reuse git command used in
osmo-ci to get latest tag from tag list when OBS latest repository is
built.

Change-Id: I3e461d4270b5e6d4c42126df4deef5651dca1e27
2018-05-02 21:29:05 +00:00
Philipp Maier
3a496f3b8a doc: add example config for usrp B200 series
Change-Id: I1a80ddd9ca9b143e9c89618616f30fe3f3547d7b
2018-05-02 18:41:34 +02:00
Harald Welte
fad2e09840 osmo-trx: s/GSM Core Address/GSM BTS Address/
The TRX connects to the BTS, not to the "Core".  The Core network
is miles away...

Change-Id: I6de2f708fc7a7df7dea16314b7dfa4ab82f15b2c
2018-04-28 21:43:40 +02:00
Harald Welte
e09e80f5ee update .gitignore for new executable names
Change-Id: Id698024485176e5201ca92c72b1bd1d5914aff32
2018-04-28 21:43:36 +02:00
Harald Welte
2e276e7edd debian/control: Add build dependency to libusrp-dev
Change-Id: I9593c9e45d304b7ffc94474e94450da418838513
2018-04-28 14:38:16 +02:00
Harald Welte
dffc21725c debian: Ensure USRP1 firmware is part of osmo-trx-usrp1
The std_inband.rbf files are required to operate USRP1 with timestamps

Change-Id: I9b3e937ea1941953dcdcaf57cfec9575cd5a8a9c
2018-04-28 14:22:57 +02:00
Harald Welte
96f0f2cf7e debian/rules: Make sure we always require libusrp
Change-Id: Id9c9188a24617f83efa0e1fcf54f9e0dd223e365
2018-04-28 14:21:14 +02:00
Harald Welte
225b16d48e debian/control: Remove "Maintainer" from binary package section
This resolves the following warning:
dpkg-source: warning: unknown information field 'Maintainer' in input data in package's section of control info file

Change-Id: I7a8d8c54eabccc5cedf7ad0a2bccf91f32f1bfdf
2018-04-28 14:21:14 +02:00
Harald Welte
0ebbb2ed2e Revert "debian: Remove osmo-trx-usrp1 until we can build libusrp1.deb"
This reverts commit 295b938d51, as we now
have libusrp built in OBS

Change-Id: Ia1311f1e236e6aea4acc08d3f234d53e46789cf9
2018-04-28 14:21:14 +02:00
Pau Espin Pedrol
2fea950644 build: Fix OBS build for ARM
Change-Id: Ic6b408d684e2bb58af71ec04ced7e73e0d38ffcd
2018-04-28 01:44:39 +02:00
Pau Espin Pedrol
d0a97a5f73 debian: Fix OBS build
osmo-trx is a metapackage, no need for .install file.
Debug files are always put into osmo-trx-dbg, no osmo-trx-*-dbg.

Change-Id: I160dd83b265dcda52762a9f9c7eac9337928da35
2018-04-28 01:38:30 +02:00
Pau Espin Pedrol
295b938d51 debian: Remove osmo-trx-usrp1 until we can build libusrp1.deb
Change-Id: I43163755a29014fe1f098e994f8df79d853c90f8
2018-04-28 01:38:30 +02:00
Pau Espin Pedrol
e8605202ab jenkins.sh: Enable build of osmo-trx-usrp1
Change-Id: I44a978fdd7fac683520be3586d84783e5e13de5f
2018-04-28 01:38:30 +02:00
Pau Espin Pedrol
2a8183bdf0 build: More OBS build failure fixes
It seems the order in which static code and -lfoo is passed to the
linker matters.

Change-Id: I3b25be0154053ae8eb5f0a24c39fb9a229130fcf
2018-04-28 01:38:30 +02:00
Pau Espin Pedrol
478f82f47e build: Fix make distcheck
Change-Id: I1fa5e34b44331cd56408ea7ad4483dcf6443b259
2018-04-27 11:34:11 +02:00
Pau Espin Pedrol
f37b0ad652 Transceiver: log timing info of stale bursts
Change-Id: I043fd8199253bdf3912c7aec2ccf98f8cbe54251
2018-04-25 20:14:55 +02:00
Pau Espin Pedrol
3b78cbfdc1 Logger: Print correct source file and line number
Before this commit, always Logger.cpp:53 was being printed.

Change-Id: Ie5c64b4961c7c41d23484784a93eda5e08331f08
2018-04-25 16:45:34 +02:00
Pau Espin Pedrol
f3d7f443a0 Build one osmo-trx binary for each device support enabled
Same way as we do in osmo-bts. After this commit, osmo-trx no longer
exists. Instead, osmo-trx-uhd and osmo-trx-usrp1 are generated based on
configure flags enabled.

A new flag --with(out)-uhd has been added to enable/disable build of
osmo-trx with UHD backend. It is left enabled by default to keep
compatibility with older build scripts. Binary with USRP1 backend must
still be manually enabled with --with-usrp1 flag.

Change-Id: Iea8c0d7434762713a53440d29bf3ebd84accb262
2018-04-24 19:17:22 +02:00
Pau Espin Pedrol
e564f0fd84 Transceiver: Move device specific code to radioDevice class
Change-Id: Ibcf258d8bf8595e286682e0bc59391b239ea7642
2018-04-24 18:46:48 +02:00
Pau Espin Pedrol
0fc20d14b3 Move device specific code out of radioInterface
This way code of radioInterface is independent of the device and doesn't
need to be rebuild for each device.

Change-Id: Id104e1edef02f863b6465ced5b4241050dc188f9
2018-04-24 18:46:48 +02:00
Pau Espin Pedrol
a4316ee4c5 Change configure define USRP1 to DEVICE_USRP1
Similar as we do for ARCH_*, it's easier to find those are related to
device support features.

Change-Id: Iba238bff689b8f944af76120402c0fa2e29a70de
2018-04-24 18:46:48 +02:00
Pau Espin Pedrol
2128a308eb Move device specific files to device subdir
Change-Id: Ib42fef14bf4c7b779f44d99711a35c18b32a4c21
2018-04-24 18:46:48 +02:00
Pau Espin Pedrol
43fedb656b Move arch specific fiels to arch subdir
Take the chance to update some includes using files available in that
subdir to have them ina more uniform way.

Change-Id: Ibda3c54fd4dc3f6b845cc373f1a1e6b758c1ea82
2018-04-24 15:22:59 +02:00
Pau Espin Pedrol
53bdb7f82a configure.ac: Add --enable-sanitize option
Change-Id: I1b5154a47bb2f66103ac254a0f422e8a80b2d3e0
2018-04-16 15:17:48 +00:00
Pau Espin Pedrol
6462dd3963 tests: Makefile.am: Fix typo in include path
Change-Id: I036f1f587f2a5eaf93ec8fb619bf76b571c1633a
2018-04-16 15:35:57 +02:00
Pau Espin Pedrol
e1977fcd22 use osmo_init_logging2()
Change-Id: I2c28e6e6e3eb9f587680b34330e03408e32c2b94
2018-04-16 14:50:55 +02:00
Alexander Couzens
f97296e0ce jenkins.sh: change qemu-img default location to $HOME/qemu-img instead of /opt/qemu-img
Change-Id: I56f314d78c0ca968b1fef9a91ecd540a7cc8fa86
2018-04-12 09:23:28 +00:00
Martin Hauke
20259cb307 configure.ac: Fix typo
Unbreak git-version-gen when used with .tarball-version

Change-Id: Id836c6822daf1f6835a8c869624b4b40dde47f3a
2018-04-08 19:53:37 +02:00
Alexander Couzens
ffa4e5938c jenkins.sh: cleanup always the workspace
It was broken before becaues of checking emptyness against literal string
will never be zero.
However it should be cleaned always because the script is executed
recursive which would also end up, never being executed.

Change-Id: Ib228ff247a72b21b12e8dd4cbe3afe3e858c89d3
2018-03-27 13:37:39 +02:00
Vadim Yanitskiy
c0c6d70fe9 Transceiver.cpp: prevent out-of-range array access
There was no a simple range check for both (NO)HANDOVER commands,
so an out-of-range access was possible. For example, a command:

  CMD HANDOVER 0 -3

might enable EDGE at run-time, because:

  a[i] == *(a + i)

Let's fix this.

Change-Id: I24a5f70e8e8097f218d7cbdef8cb10df2c35416f
2018-03-14 21:12:32 +00:00
Vadim Yanitskiy
8c6c5d2bcd Transceiver.cpp: fix incorrect format string for SETTSC
Change-Id: If69a478121a31aa7df945548cc17271c476d6a6b
2018-03-14 21:12:32 +00:00
Vadim Yanitskiy
a62fcf786a Transceiver.cpp: use pointer arithmetics for CMD parsing
It looks like the author of control command parsing code was not
familar with simple pointer arithmetics, so excessive amount of
memory and useless memcopying was used to parse a single command.

Let's introduce two pointers, one of which will point to the
beginning of a command, another to the beginning of its arguments.
Also, let's simplify the command matching by using a separate
function called 'MATCH_CMD'.

Change-Id: I226ca0771e63228cf5e04ef9766057d4107fdd11
2018-03-14 21:12:31 +00:00
Vadim Yanitskiy
4d9b59c3ef Transceiver.cpp: properly zero-terminate received commands
Previously it was assumed that a sender should zero-terminate
each command being sent. Otherwise, this could cause to printing
garbage. Let's do this manually, using the length of received
data as a position for '\0'.

Change-Id: I69f413f33156c38a853efc5a8cdc66fbfb0ca6af
2018-03-14 21:12:30 +00:00
Vadim Yanitskiy
bd0efb0bea Transceiver.cpp: use a define for the MAX_PACKET_LENGTH
No need to keep this value on stack.

Change-Id: If9ffb03b9e7b642f45732ba5938977bca271f1c7
2018-03-14 21:12:30 +00:00
Pau Espin Pedrol
8fbbd656c7 Build Transceiver52M/common as an .la lib
Stop picking files from that directory on different places as it causes
dependency issues during make distclean/maintainer-clean.

Fixes: OS#3029

Change-Id: I81bb4251d18fce978d27849b621b20f541caab0b
2018-03-08 14:53:13 +01:00
Pau Espin Pedrol
b35cba613a Makefile.am: Avoid using subdir if arch is not required
There's no need in going a level deeper if we already know nothing's
going to be done. This way we also get cleaner make outputs.

Reference: https://www.gnu.org/software/automake/manual/html_node/Conditional-Subdirectories.html#Conditional-Subdirectories

Related: OS#3029

Change-Id: I3ff57ab14edc575904e8137929a0ef02c95e03af
2018-03-07 19:46:42 +01:00
Pau Espin Pedrol
8dffadb8da osmo-trx: Re-introduce -l cmd line parameter
Parameter -l to set the terminal logging levle was removed in
3da1f8352e, but afterwards it was decided
to keep the cmd line options for a bit more to easy migration to VTY
cfg.

The command line no longer accepts keywords ("DEBUG", "INFO", etc.) but
log level numbers, due to libosmocore APIs log_parse_level and
log_level_str being marked as deprecated and for internal use only.

Keep in mind the log level is overridden by VTY cfg if any line sets log
levels for log stderr in there.

Explicit cast to unsigned int for loglvel is issued to avoid iostream
printing it as a char.

Change-Id: I91c35ecded177b7976045d9b693855adb9e18f8a
2018-03-06 18:41:29 +01:00
Pau Espin Pedrol
408f25081e osmo-trx: Use VTY cfg structures while still allowing cmd line options
Existing cmd line options are kept for a while to give people some time
to move to use VTY cfg. All new cfg options should be set only through
VTY. VTY options take preference (override) over cmd line options.
Deprecated options are removed from help message to dissuade users from
keep using them.

Steps to drop cmd line options in the future:
- Drop comma_delimited_to_vector, print_deprecated
- Drop all options in handle_options marked with print_deprecated.
- Set "-c" param to do the same as "-C", to keep compatibility with old
param and still use same naming as all other osmocom projects.
- Remove the hack in main() to set 1 channel implicitly by default.

Change-Id: Ib8de1a5da4b3c0b6a49e00033f616e1d66656adf
2018-03-05 20:12:40 +01:00
Pau Espin Pedrol
2001550f7d doc: Add sample cfg file for LimeSDR
Change-Id: I16de70eac0fd79107b8317af37201e6da834c169
2018-03-05 19:55:02 +01:00
Pau Espin Pedrol
a3ab8c263d vty: Implement VTY cfg parsing for current parameters
At this stage, osmo-trx still uses the cmdline parameters top run the
device, but it is already able to parse all the same parameters from a
cfg file through the VTY and filling a trx_ctx structure which will be
later used to drive the device. Device config can be printed in the VTY
with "show trx".

Change-Id: Ie084c1b30b63f91c6e7640832ec1797d9e813832
2018-03-05 19:55:02 +01:00
Pau Espin Pedrol
efac20b6bb Move enums required by VTY to a separate header
This patch is a preparation for next patches, which add full VTY cfg
support.

Change-Id: I3d5b0576aa96869756f1629a40306c0043b6304b
2018-03-05 17:16:05 +01:00
Pau Espin Pedrol
0bbd8922ea osmo-trx.cpp: Move trx start and stop to helper functions
Make main() smaller, and make it easier to replace cmdline parameters in
following commits.

Change-Id: I10eaaafe38ace2b7bb095a0ad1db70d6c06ee03b
2018-03-05 17:14:32 +01:00
Alexander Couzens
28b8cc6283 jenkins.sh: fix the download url if the qemu image wasn't setup
Download the image from yesterday because linuxcontainers only contains the images of the last 3 days.

Change-Id: I75e270b7255c1cd7fca1674111b0f19fc7bba74f
2018-03-02 08:58:31 +00:00
Alexander Huemer
3f52f0e6c5 Fix USRP1 build with support for setting Rx/TxAntenna
The USRP1 build was broken by commit 77ce99ac67.

Commit 77ce99ac67 broke the USRP1 build

Change-Id: I28585947d5662cdd580a814cce54a5d9aa30eeb8
2018-02-27 22:35:37 +01:00
Pau Espin Pedrol
3da1f8352e Logger: Use libosmocore logging system
We still need an intermediate class Logger due to osmo-trx being
multi-threaded and requiring to have a lock to use libosmocore, which is
not thread safe.

Change-Id: I30baac89f53e927f8699d0586b43cccf88ecd493
2018-02-27 07:11:11 +00:00
Pau Espin Pedrol
5ea1817dc2 Add initial support for logging, vty, ctrl
Up to this point, the logging system, vty and ctrl are initialized and
can be used fine, though they don't have a lot of use yet.

Depends on libosmocore Change-Id Ib79cdb62d45d8c78445c7b064e58eb7e9faeccf9

Related: OS#2184

Change-Id: I08982c37b4f873966304b3cfb38a10ee86eb3dad
2018-02-27 07:10:50 +00:00
Pau Espin Pedrol
49d42e979e debian: Depend on libtalloc and libosmocore
Change-Id: If4bf03d164e9d19a8a21399a2c74b2984c48cc70
2018-02-26 00:56:10 +01:00
Pau Espin Pedrol
3a3b220751 osmo-trx: Set up talloc ctx
Change-Id: I67f1980fc615ab74371cbe1c4f83e987381299bc
2018-02-22 20:04:47 +01:00
Pau Espin Pedrol
ab22f4c421 osmo-trx: set up signals using libosmocore helpers
Change-Id: I86e78cd6054d0deff1b1aa061299d9f307e2a352
2018-02-22 20:04:47 +01:00
Pau Espin Pedrol
8b843e5bed Depend on libosmocore
Change-Id: If345c89293fcd7d1ad4f17214eea339951f25a5d
2018-02-22 20:04:47 +01:00
Pau Espin Pedrol
c92dad32dd configure.ac: Check for pkg-config
Change-Id: I1a851181a99f2f35ea4ff1b38c7afe27a04e5f18
2018-02-20 20:32:27 +01:00
Pau Espin Pedrol
61837c0420 Logger: Remove gLogToConsole flag
No code is using it and we always lock to console anyways.

Change-Id: I5fde99c6af5a845e635b5d27abab855682071f14
2018-02-20 20:32:27 +01:00
Pau Espin Pedrol
f83e11fefd Logger: Remove unused includes
Change-Id: I4d26c0b4f36ee3c66ed1a9e2e9fa2fa8272da16d
2018-02-20 20:32:27 +01:00
Pau Espin Pedrol
01aff88ce9 Logger: Drop support to log into file
This feature is currently not being used, so let's simplify current code
to move to libosmocore logging system in the future.

Change-Id: If2c77c776823f595130edac963be953026049423
2018-02-20 20:32:27 +01:00
Pau Espin Pedrol
11d50d950c Logger: Drop syslog support
This feature is currently not being used, so let's drop it to make it
easier to integrate into libosmocore logging system in the future.

Change-Id: I8282745ef0282d41599eaf94fe460a1d29b18e2a
2018-02-20 20:32:21 +01:00
Pau Espin Pedrol
8bd111c942 Logger: get rid of alarm APIs
It's only used internally inside the Logger module, and in case there's
an "alarm" (level more than critical) we still print on cerr, so we can
just rely on our system catching stderr instead of stdout to handle it.

Change-Id: I6d6df1578c3a4c1a37bd0d69952d443f62eed2ab
2018-02-20 18:26:45 +01:00
Pau Espin Pedrol
3808e479aa Logger: Remove unused logging macros
Change-Id: I1133e181183bec8dabe2fa77d0385f783458503f
2018-02-20 18:14:20 +01:00
Pau Espin Pedrol
bd45a979f8 Logger: Drop unused gLogEarly
Change-Id: I2c8f24fbf453e0a94d7a95c3df7cc75f0e4bd456
2018-02-20 18:14:20 +01:00
Pau Espin Pedrol
b7095c7bc5 UHDDevice: Initialize async_event_thrd in constructor
Fixes coverity CID 182757.
It's actually a false warning because "async_event_thrd" member is
protected by other member "started", so in practice it's never going to
be used before being initialized in start().

Change-Id: I5d5739bc9d08fe533e4d44c3992005a14e568a4f
2018-02-09 16:20:39 +01:00
Pau Espin Pedrol
77ce99ac67 Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.

In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.

Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.

One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW

Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.

One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW

Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-07 13:43:42 +01:00
Pau Espin Pedrol
f58cd8ac83 Fix whitespace
Change-Id: Icda84caa998614ce6c15d5118f8c5c1568ba9a79
2018-02-05 13:04:41 +01:00
Max
99eb07e232 tests: null-terminate buffer
Initialize temporary buffer with 0 to make sure that it's
null-terminated.

Change-Id: Icdde701839e35d3131605ea5a11882af21c8939a
Fixes: CID149362
2018-01-31 11:34:59 +01:00
Pau Espin Pedrol
89be118a3b Remove unneeded libdl dependency
Closes: OS#1929

Change-Id: I0caea2a2a8e6bd07432fd73bae72b42b1ce022cd
2018-01-23 18:15:24 +00:00
Alexander Huemer
6fafd33b13 Unbreak ./configure --with-usrp1 build
Change-Id: I49b385594271ae64a48d4d39ee9fe26d7c95bd30
2018-01-20 23:24:20 +01:00
Pau Espin Pedrol
6e55d51747 tests: convolve: Disable due to difference in output in different archs
Let's disable this test in order to have passing jenkins jobs until we
find a better way to properly test this for different architectures.

Change-Id: I2320309bc8c1c20e2de6ef2e0f17472c68de80cb
2018-01-16 11:33:50 +01:00
Pau Espin Pedrol
6cae1d7b4b contrib/jenkins.sh: Use qemu+proot+debootstrap to run tests with ARM instruction set
The following logic doesn't require root access to run the tests, which
means we can easily run it inside jenkins.

Change-Id: Iba3f4de008662805d8ffc46e1f473e407b088fb8
2018-01-15 18:21:17 +01:00
Pau Espin Pedrol
28ce315a32 tests: TimevalTest: refactor and avoid double comparison
Before this patch, the experession assert(then_secondws==then.seconds())
was failing in x86 architecture (and passing when adding a fprintf to
debug it). Avoid comparing the double values with == as that's usually a
bad idea, since the processor can output slightly different results for
the same operation depending on how it is optimized. Use timespec()
instead to check the invariant. Take the chance to refactor some
variables around to make the test easier to read.

Change-Id: Id4324be8ece86d371b1acb46bbd97856dfed241d
2018-01-15 11:49:10 +01:00
Pau Espin Pedrol
10d76b6863 tests: SocketsTest: Fail test on write fail
Change-Id: Ib6b778a2225339ebd2eaa80b3fca6ee8d8646b23
2018-01-15 10:47:13 +01:00
Pau Espin Pedrol
708b8b44ae tests: SocketsTest: Avoid hang forever if test fails
Change-Id: Ia95e216a2ab6d397ab02c828b70f2b95d1671257
2018-01-15 10:46:42 +01:00
Pau Espin Pedrol
cb0fc9b21a tests: SocketTests: Pick OS-assigned instead of setting one manually
This fixes failures if the port is already being taken by other apps or
if this test is run several times concurrently in the same system.

Change-Id: Iea213375e489a56cf8ed3e47fe814e17c288803e
2018-01-15 10:35:11 +01:00
Pau Espin Pedrol
8639fee504 Remove UDDSocket class
This class is not used anymore in osmo-trx, so we can safely remove it.

Change-Id: I67f90aa3d6a2a5e92292436d10928e0705c8f8ff
2018-01-11 20:17:43 +01:00
Pau Espin Pedrol
ca46896cfe .gitignore: Add missing test related files
Change-Id: I7a82a2c0c97bbfa4877f148c89d121b4c3476176
2018-01-11 20:17:40 +01:00
Pau Espin Pedrol
4a25d6b8f6 arm/convert.c: Add missing convert_init implementation
osmo-trx.cpp calls convert_init, which in case of building using
--with-neon is not implemented and the compiler stops with an error.

Error was introduced in 7e07cf2346.

Related: OS#2720

Change-Id: I9840d374d13b525b97f978ea0c5ed9e8421072a0
2018-01-11 18:45:12 +01:00
Pau Espin Pedrol
79baee3a8f arm/convert.c: Fix compilation error
Commit fe9769833f aiming at cleaning stuff
introduced a compilation error.

Related: OS#2720

Change-Id: I6ce6e5ec3fdb1e3e8818e2cb674470ad54e38afb
2018-01-11 18:45:12 +01:00
Pau Espin Pedrol
c2ba427b52 tests: Migrate convtest util to autotest infrastructure
Change-Id: Ie682abf7e83de436d0f37f9f6e0664cb2f4d0c9e
2018-01-11 18:45:12 +01:00
Pau Espin Pedrol
611212676b Move ARCH_LA to Makefile.common
It will later be used by other directories too (tests/Transceiver52M).

Change-Id: I0ca9b7fc5e1377db971cb7da0b3496ba8d61c716
2018-01-10 12:32:33 +01:00
Pau Espin Pedrol
4ebb289c90 utils/convolvtest: Remove uneeded libosmocore dependency
Change-Id: I1742146c31cadec8ce8afbbdae5777f076b212d4
2018-01-10 11:54:34 +01:00
Pau Espin Pedrol
2f376a3edf tests: Sockets: adapt to have reproducible output and enable autotest
Change-Id: I5414076c6846b849973bcdeb3f2358b28dcb004c
2018-01-10 11:31:22 +01:00
Pau Espin Pedrol
2edbe4d366 Sockets.cpp: Fix initialization of UDD socket
Without this line, destination address for a UDD socket is left with
incorrect value AF_UNSPEC. Later on when calling DatagramSocket:write(),
sendto() fails with EINVAL.

This commit fixes test SocketsTest.cpp.

Change-Id: I6e1b7e743a781abdcf69aa9842b30be893633433
2018-01-10 11:29:16 +01:00
Pau Espin Pedrol
a3694bd303 tests: Log: adapt to have reproducible output and enable autotest
Change-Id: I77c40230503acadef5f64ab2624cd872f9782b98
2018-01-10 11:29:16 +01:00
Pau Espin Pedrol
2652f2bc39 tests: Timeval: adapt to have reproducible output and enable autotest
Change-Id: I1a79892ba3c934879a171789e0edb357277acae4
2018-01-10 11:29:13 +01:00
Pau Espin Pedrol
93d9b114b7 tests: InterThread: adapt to have reproducible output and enable autotest
Change-Id: I05d4067890b526bd72d2eb31cf76de43ee11e80f
2018-01-10 11:25:42 +01:00
Pau Espin Pedrol
2ac788b2c3 Set up GNU Autotest infrastructure
Test files are moved from CommonLibs/ to tests/CommonLibs/.
Some tests are disabled in autotest because they generate timedate
related output which cannot exactly match against expected output.

Change-Id: I3d6ba625968be09297642d18090c496490e9b8fc
2018-01-10 11:17:32 +01:00
Pau Espin Pedrol
d36ef2f57b cosmetic: AUTHORS: fix trailing whitespace
Change-Id: I92d9ad9a0fd69e88928a8f57920d39dcda67d59d
2018-01-10 11:14:31 +01:00
Pau Espin Pedrol
caf2abc58f Remove Configuration module and libsqlite dependency
Change-Id: I823aea91367d586507bbf352f1b6f25bdd635baa
2018-01-09 15:26:50 +01:00
Pau Espin Pedrol
de1685f6d7 Drop use of ConfigurationTable gConfig
After latest changes, it is not being used anymore.

Change-Id: I43a49aee94e3239194ad9742fb6374324acac0de
2018-01-09 15:26:50 +01:00
Pau Espin Pedrol
f3837d26f9 Logger: Stop using Log.File and Log.Level from config
This is a required step towards getting rid of ConfigurationTable class
and libsqlite dependency.

As a side effect, support for different log levels for different files
is dropped, but it's not something really being used and we will end up
dropping current logging system in favour of osmocom's one in the future
anyway.

Change-Id: I51cb12d1ab7e103e78190ac71a70fb5bb1d9ff51
2018-01-09 15:26:49 +01:00
Pau Espin Pedrol
ddf4743306 Logger: Stop using Log.Alarms.Max from config
This is a first step towards removing ConfigurationTable class and
sqlite3 dependency.

Change-Id: Idcd789afe668a5c0271352f1d20d2efda826213a
2018-01-09 15:26:49 +01:00
Pau Espin Pedrol
82f83ced73 cosmetic: Remove trailing whitespace
Change-Id: I64c8dbad3fc42bcb8dd4ac9b16bbd9c59a0cf5d5
2018-01-09 15:26:49 +01:00
Max
cff4ed9b4c Update license notes
* replace references to OpenBTS with OsmoTRX
* drop trademark notice
* drop outdated example

Change-Id: I144f96c507bfe48df350fb0350edbeba87126462
Related: OS#2600
2018-01-05 10:07:08 +00:00
Max
6ec26bb788 Update legal disclaimer
* drop trademark passage
* add link to OpenBTS website and corresponding attribution
* replace OpenBTS references with OsmoTRX

Change-Id: Ia40df831649cdb68898db9ca77868c422a8d631d
Related: OS#2600
2018-01-04 15:17:27 +01:00
Max
a1ff991402 Update installation instructions
* remove references to OpenBTS
* update URLs
* remove unnecessary requirements

Change-Id: I6ec26beaaa74dd3d98f27d110055a8f0cdd3c991
Related: OS#2600
2018-01-04 14:31:54 +01:00
Max
d09843c692 Remove unused headers
Change-Id: Idadb17aeb85b011d114ffc1d81c920544bac1989
2018-01-04 14:31:54 +01:00
Max
e5448ff972 Remove outdated references to OpenBTS
Change-Id: I2df613bf59af28e2f44a520d0ee953932bcf4d7e
2018-01-04 13:41:06 +01:00
Max
e48c1367dc Mark release target as virtual
Change-Id: Iee747faa3171663f1874a5eacddd56607de55297
2018-01-04 13:40:42 +01:00
Piotr Krysik
aa60dda99a UHDDevice.cpp: add USRP B205mini support
The B205mini is similar to the B200mini and runs OsmoTRX just
fine, so let's make OsmoTRX recogonize and support it too.

Change-Id: Iee575121248ea541f7abc49055e49ec2d30904c0
2017-12-04 00:32:33 +07:00
Harald Welte
1468a5c3dc SocketsTest: Fix printing of non-nul-terminated string
Change-Id: I33d0ddf851d84b81ab5252e3755422170cee54ee
Fixes: Coverity CID#149363
2017-11-07 20:32:09 +00:00
Neels Hofmeyr
b0e1bd8c22 jenkins: use osmo-clean-workspace.sh before and after build
See osmo-ci change I2409b2928b4d7ebbd6c005097d4ad7337307dd93 for rationale.

Depends: I2409b2928b4d7ebbd6c005097d4ad7337307dd93
Change-Id: I609f7c7c88b49f26e2e48e1f1cffed76d9e6fb5e
2017-10-31 09:24:58 +00:00
Harald Welte
78e1cd20e2 Tag/Release 0.2.0
This is the first real tagged Osmocom release of OsmoTRX.

  [ Alexander Chemeris ]
  * EDGE: Add support for UmTRX.
  * Common: Get rid of a compilation warning.
  * Common: Make sure gLogEarly() log to the same facilities as the normal log.
  * transceiver: Properly handle MAXDLY.
  * transceiver: Add an option to generate random Access Bursts.
  * osmo-trx: Output Rx SPS as a part of configuration output.
  * transceiver: Do not pass transceiver state struct to function where it's not used.
  * makefile: Fix build from an external path.
  * radioDevice: GSMRATE macro must have parentheses around its definition.
  * uhd: Fix comment.
  * radioInterface: Initialize power scale with a meaningful default.
  * transceiver: Log channel number in DEBUG output of demoded bursts.
  * transceiver: Add an option to emulate a RACH delay in random filler mode.
  * UHD: Initial LimeSDR support.
  * CommonLibs: Remove unused files.
  * sigProcLib: Typo sybols -> symbols
  * radioBuffer: Remove extra ; at the end of inline function definitions.
  * sigProcLib: Fix documentation, sync argument names in .cpp and .h files.
  * sigProcLib: make energyDetect() simpler by returning actual energy.
  * sigProcLib: Rename demodulateBurst() to demodGmskBurst() for clarity.
  * sigProcLib: Slice SoftVector instead of signalVector for GMSK demod.
  * Call vectorSlicer() right before packing bits for transmission to osmo-bts.
  * CommonLibs: Print soft bits with less confidence to console when printing a soft vector.
  * BitVector: Remove convolutional codec - we don't use it in osmo-trx.
  * BitVector: Convert SoftVector from 0..1 to -1..+1 soft bits.
  * signalVector: Implement segment().
  * vector: Introduce segmentMove() method to move data inside of a vector.
  * vector: Introduce shrink() function to shrink vector size without loosing data.
  * Move CorrType type from Transceiver to sigProcLib.
  * sigProcLib: rename signalError type to SignalError.
  * Move Transceiver::detectBurst() to sigProcLib to make it reusable.
  * Move BURST_THRESH from Transceiver.cpp to sigProcLib.h to make it reusable.
  * sigProcLib: Add operator<< to print CorrType to a string.
  * sigProcLib.h: Fix whitespaces. No non-whitespace changes.
  * Move Transceiver::demodulate() to sigProcLib to make it reusable.
  * sigProcLib: constify signalVector arguments for detectBurst() functions.
  * sigProcLib: Constify demodulation functions burst argument.
  * sigProcLib: Fix number of tail bits in random Normal Bursts and zero Stealing Bits.
  * Configuration: Variables allocated with 'new' must be freed with 'delete'.
  * BitVector: Remove Generator class.
  * PRBS: a Pseudo-random binary sequence (PRBS) generator class.

  [ Tom Tsou ]
  * EDGE: Fix USRP B210 device support
  * uhd: Correct timing alignment in 8-PSK and GMSK downlink bursts
  * EDGE: Fix demodulation slicer input
  * common: Restrict UDP binding to localhost only
  * common: Add mandatory length field to UDP receive calls
  * uhd: Update default E3XX settings
  * uhd: Set default Tx sampling to 4 sps
  * uhd: Make device offset check a private method
  * uhd: Set minimum UHD version requirement for E3XX
  * sigproc: Expand RACH, TSC, and EDGE correlation windows
  * transceiver: Do not report error on SETTSC when radio is on
  * transceiver: Add Rx samples-per-symbol option
  * radioInterface: Convert diversity argument to general type
  * iface: Add inner ring-buffer implementation
  * mcbts: Add multi-ARFCN channelizing filters
  * mcbts: Add multi-ARFCN radio support
  * sigproc: Adjust burst detection threshold criteria
  * egprs: Enable 8-PSK length vectors on the Tx interface
  * egprs: Enable 8-PSK burst detection when EDGE is enabled
  * transceiver: Remove HANDOVER warnings
  * mcbts: Allow out of order channel setup
  * radioInterface: Fix multi-channel buffer index bug
  * uhd: Add command line option for GPS reference
  * transceiver: Fix mixed GSMK / 8-PSK transmission
  * transceiver: Fix 4 SPS receive TOA value
  * sigproc: Fix missing 8-PSK tail symbols
  * uhd: Update USRP2/N200/N210 for 4 SPS Rx
  * sigproc: Match differential GMSK start/end bits to tail bits
  * uhd: Add missing B200 sample timing for 4 SPS receive
  * transceiver: Fix command build warning
  * uhd: Set minimum supported version to 3.9.0
  * uhd: Add X300 sample timing for 4 SPS
  * Revert "uhd: Set minimum supported version to 3.9.0"
  * uhd: Add support for UHD-3.11 logging control
  * uhd: Increase MC-BTS FPGA clock rate to 51.2 MHz
  * Resampler: Fix initialization return checking
  * sigProcLib: Remove unreachable code and no-effect checks
  * sigProcLib: Check return status on downsampling
  * sigProcLib: Fix negative value check on unsigned value
  * Resampler: Fix non-array delete for filter taps
  * Transceiver: Remove unsigned negative compares
  * Configuration: Fix const and signedness compile warnings
  * config: Remove OpenBTS style sqlite configuration
  * radioInterface: Remove UmTRX 'diversity' option
  * build: Require and check for gcc C++11 support
  * uhd: Use map container for for device parameter access
  * sigProcLib: Remove unused functions from public interface
  * uhd: Add non-UmTRX channel swap support
  * uhd: Fix Tx-RX timing offset setting
  * uhd: Fix USRP2/N200/N210 device detection
  * transceiver: Fix POWEROFF crash on USRP2/N200/X300 devices
  * sigProcLib: Fix complex/real vector flag in Laurent modulator
  * sigProcLib: Remove heap based signal vector allocations
  * common: Declare explicit Vector move constructor
  * sigProcLib: Remove trigonometric tables
  * sigProcLib: Use explicit NaN check in sinc table generation
  * sigProcLib: Replace dynamically allocated resampling buffers
  * sigProcLib: Specify standard namespace for isnan()
  * uhd: Always specify samples-per-symbol for device lookup
  * LimeSDR: set approximate tx offset value to make GSM work

  [ Neels Hofmeyr ]
  * add basic .gitignore
  * configure.ac: check for boost/config.hpp header
  * The INSTALL file is being overwritten by autoreconf, but it is committed as empty file. As a result, the INSTALL file always shows as modified. Instead, remove INSTALL from git and ignore it.
  * add contrib/jenkins.sh, for gerrit build bot

  [ pierre.baudry ]
  * transceiver: Fix mismatched allocations and deallocations

  [ Holger Hans Peter Freyther ]
  * debian: Require fftw3 header files for osmo-trx

  [ Max ]
  * Add gerrit settings
  * Integrate Debian packaging changes
  * Remove embedded sqlite3
  * Fix building against sqlite3
  * Add autoconf-archive to dependencies
  * debian: remove obsolete dependency
  * deb: remove unused dependency
  * Remove redundant explicit dependency
  * Use release helper from libosmocore

  [ Ruben Undheim ]
  * Do not embed sqlite3 when building

  [ Philipp Maier ]
  * buildenv: Turn off native architecture builds
  * cosmetic: Make parameter lists uniform
  * Add test program to verify convolution implementation
  * ssedetect: Add runtime CPU detection
  * cosmetic: remove code duplication
  * buildenv: Make build CPU invariant
  * buildenv: Split up SSE3 and SSE4.1 code
  * cosmetic: Add info about SSE support

  [ Vadim Yanitskiy ]
  * buildenv: correct the ax_sse macro description
  * buildenv: actually strip unused cpuid functionality
  * buildenv: fix build on systems without SIMD support
  * buildenv: cosmetic changes
  * buildenv: check for __builtin_cpu_supports call support
  * ssedetect: call __builtin_cpu_supports() only if supported

  [ Pau Espin Pedrol ]
  * cosmetic: transciever: Remove trailing whitespaces
  * transceiver: Avoid sending clock indications when trx is not powered on
  * Add -j option to bind to specific address

  [ ignasj ]
  * LimeSDR: Change device detection to work with USB and PCIe versions
  * LimeSDR: change tx window type to TX_WINDOW_FIXED
  * LimeSDR: Fix sample value range

  [ Harald Welte ]
  * Add '-t' command line option to enable SCHED_RR
  * Import git-version-gen and update AC_INIT()

Change-Id: Ibf3be6cc25e9b20d625b1f67972114b7f613f05c
2017-10-28 17:53:25 +02:00
Harald Welte
db9c1b54cb Import git-version-gen and update AC_INIT()
In AC_INIT(), it still stated openbts.  Let's clean this up and use
the same method of version generation that we use in all other osmocom
projects, too.

Change-Id: Ie7ae0585955aebdc3950b1dd8bff0d1fff3be212
2017-10-28 17:51:54 +02:00
Max
099a44abfb Use release helper from libosmocore
See
https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
for details.

Change-Id: Ieb843923d8f534654413be695f2b5f0c87b75520
Related: OS#1861
2017-08-28 12:26:54 +02:00
Pau Espin Pedrol
8c80095017 Add -j option to bind to specific address
Before this patch, the binding of the listening sockets was hardcoded to
a local IP.

Change-Id: I9ba184a1251c823e413a9230943ed263e52142ec
2017-08-16 17:06:54 +02:00
Max
d49a6aa136 Remove redundant explicit dependency
There's no need to explicitly mention library package because
${shlibs:Depends} will take care of it automatically.

Change-Id: Ibd9cfc3673d828122edb85ba9de7ceb77f0299d0
2017-07-20 18:36:11 +00:00
Harald Welte
81486e053c Add '-t' command line option to enable SCHED_RR
SCHED_RR allows us to operate osmo-trx reliable even under exceptionally
high system load, as the realtime scheduler priority will have higher
priority than the other "regular" tasks on the system.

Change-Id: Ia2452b9763960b2be37fbeee9d832554da68a53f
Closes: OS#2344
2017-07-20 18:36:01 +00:00
ignasj
28d8081e25 LimeSDR: Fix sample value range
when "sc16" stream arg is passed to SoapyUHD sample value range is -32768 to 32767

Change-Id: I58b8b6b71648bd9cbc105ddaaa9a7cf0a31b3d47
2017-07-10 11:45:06 +02:00
ignasj
87ed77b937 LimeSDR: change tx window type to TX_WINDOW_FIXED
It seems that TX_WINDOW_USRP1 is for devices that do not support tx
sync to timestamp. LimeSDR supports it. Changing to TX_WINDOW_FIXED
greatly reduces number of "dumping stale buffer" messages

Modified to match current master by Harald Welte.

Change-Id: I8de5b165ccd72a62b0f16655618e24ca740d9637
2017-07-10 09:34:58 +00:00
ignasj
f9d996813d LimeSDR: Change device detection to work with USB and PCIe versions
Modified to match current master by Harald Welte.

Change-Id: Ie43610de0b2196d84caf09717ec8c8ca75ab926d
2017-07-10 09:34:32 +00:00
Max
aa5acc953c deb: remove unused dependency
The libdbd dependency is not used because libsqlite3 is used directly -
adjust debian/control to match.

Change-Id: Id2ab1facad703fa0c1d45084e70d41e73dbad6e7
Related: OS#1929
2017-07-06 08:28:29 +00:00
Pau Espin Pedrol
934da48618 transceiver: Avoid sending clock indications when trx is not powered on
Stop calling writeClockInterface() when receiving commands in Transceiver::driveControl,
otherwise it fools osmo-bts-trx clock skew check because it is always sending a clock
indication with the same fn when it issues any commands during the time in between
CMD POWEROFF and RSP POWERON, because fn is not increased during that period.

Also use mForceClockInterface flag to delay delivery of first IND CLOCK until we start
serving frames, otherwise the first one is sent and only after a long period of time
the next clock indications are sent, when the radio starts to process bursts. That makes
osmo-bts-trx unhappy because it expects to receive an IND CLOCK aprox at least every
400 frames. This way also we send the first IND CLOCK after the RSP POWERON 0 response.

Change-Id: I91b81a4d7627cec39c1814a39ed4be306681b874
2017-07-04 19:15:57 +02:00
Pau Espin Pedrol
7c405a0c1f cosmetic: transciever: Remove trailing whitespaces
Change-Id: Ib3fbe768048b2a34a75ace9688e306720e67019a
2017-07-04 17:23:30 +02:00
Tom Tsou
4cafb0fa15 LimeSDR: set approximate tx offset value to make GSM work
may be fine-tuned in the future

Modified to match current master by Harald Welte.

Change-Id: Ied215ca9e9d9c346c2a654f96785d1b87b075129
2017-06-29 02:26:07 +02:00
Tom Tsou
f611569018 uhd: Always specify samples-per-symbol for device lookup
Fix MCBTS device setup where the map access was failing on the wrong
assumption that all devices support 1-SPS TX-RX operation. Some devices
and/or configurations such as LIMESDR and MCBTS only support running
at 4-SPS.

Even though certain settings (e.g. number of physical channels or the
FPGA clocking rate) are not dependent on the SPS value, we still need to
specify because we use SPS as a parameter for device classification.

Fixes: OS#2341
Change-Id: I56e939285d585cc38efa6c329e30e3acebb734eb
Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
2017-06-27 11:36:34 -07:00
Tom Tsou
354741326c sigProcLib: Specify standard namespace for isnan()
In commit a3dce85f
"sigProcLib: Use explicit NaN check in sinc table generation"

Use of std::isnan(double) was added without namespace specifier,
which may cause build issues depending on whether the C version
isnan() call is available. Add standard namespace to force C++
call usage and potential build issues.

Change-Id: I49328c43fdd690a4e6a2b2e949411aaf5674ead1
2017-06-22 18:03:29 +00:00
Tom Tsou
d2e5c5694e sigProcLib: Replace dynamically allocated resampling buffers
Instead use object allocated STL vectors. This simplifies code,
removes the need to explicitly release buffers, and fixes a
memory leak in destructor deallocation. Also, remove simplified
init and release sub-calls.

Maintain partition filter allocation using memalign() for SIMD
alignment requirements.

Change-Id: Ie836982794c10fb1b6334e40592d44b200454846
2017-06-22 17:39:44 +00:00
Tom Tsou
a3dce85ffc sigProcLib: Use explicit NaN check in sinc table generation
Using "x < 0.01" is a crude check for detecting NaN condition, which
occurs in a sinc call when x = 0 due to divide-by-zero. Use stdlib
isnan() call for this purpose. Also, as the table is created only
once during initialization, use double floats for table value
generation.

Change-Id: I3a838fe3139fa977dfe906246020a14451185714
2017-06-19 17:04:04 +00:00
Tom Tsou
bb0c68ae61 sigProcLib: Remove trigonometric tables
Trigonometric sin/cos tables are unused after initialization.
There is no benefit to implementing lookup tables for run-once
operations. Also perform initial calculations in double width
because there is no penalty for doing so.

Change-Id: I45bba5daf8610cbba6af95b92c2142f2256491ff
2017-06-19 17:03:11 +00:00
Tom Tsou
87d158cc2d common: Declare explicit Vector move constructor
Vector class already has a semantically odd non-const copy
constructor that serves the same function as a C++11 move
constructor. Make the move constructor semantics explicit
and address Coverity at the same time.

Change-Id: I22e0099abe601b0c59beee808f7560837c6977dd
Fixes: Coverity CID 170738
2017-06-19 17:02:41 +00:00
Tom Tsou
7278a87767 sigProcLib: Remove heap based signal vector allocations
The osmo-trx internals rely heavily on dynamic alloction of
I/Q signal vectors. In a number of cases there is no reason
to to use dynamic rather than stack based allocation. Convert
these cases accordingly.

Change-Id: If53da1bf77b5944b6117765fa98ce12e1ccdeede
2017-06-16 17:11:27 +00:00
Tom Tsou
63eef9faf2 sigProcLib: Fix complex/real vector flag in Laurent modulator
The modulator vector to be shaped by Laurent C1 pulse is complex,
but was set as real. The error does not affect behaviour because
we only support complex-complex and complex-real calculations;
real-real convolution is not supported. So in this case the data
vector was already assumed to be complex despite the improper
flag setting.

Change-Id: I03afc6a93a01fde7a9a02e4eb9d201d3ee37d21a
2017-06-16 17:09:09 +00:00
Tom Tsou
d67bd603e9 transceiver: Fix POWEROFF crash on USRP2/N200/X300 devices
Upon issuing POWEROFF command to a running transceiver, UHD
interfacing thread state may become undefined if the device
is stopped with I/O threads still active. Bad behavior is
device dependent with only network based USRP devices
affected. USB based device thread behavior stops and shutdowns
as expected. Tested with N200, X300, and B210.

Tested solutions include the following:

  1. Set pthread_setcanceltype() with PTHREAD_CANCEL_ASYNCHRONOUS
  2. Add sleep delay to allow I/O threads to timeout before
     stopping the device
  3. Wait for I/O threads to join after cancellation before stopping
     the device

This patch resolves the issue by with the third approach. Number 1
is not guaranteed to always work with UHD internals as driver code
may explicitly set thread parameters. Using sleep calls to fix
order-of-operation issues is almost never a good idea.

Change-Id: Ib72ab98a27a02084b040319046c92d1c4157ae4c
2017-06-16 17:03:30 +00:00
Tom Tsou
988a464d5d uhd: Fix USRP2/N200/N210 device detection
Commit 1fb0ce67 "uhd: Use map container for for device parameter access"
inadvertently removed the string identifier for the USRP2 and derived
devices (N200/N210).

Add the missing USRP2 string identifier. Also search for partial string
matches in the UHD provided device and mboard stings. This is necessary
to guarantee that strings such as "N200r3" instead of just "N200" are
sucessfully found.

Tested with N200, X310, B200mini and B210 devices.

Change-Id: Ide4e22418e2cc469418cba018970cb0eb9906697
2017-06-16 17:02:27 +00:00
Tom Tsou
1b6ab7d7ee uhd: Fix Tx-RX timing offset setting
Integer timestamp offset was set to zero due to bad cast-operator
precedence.

Change-Id: Ib1f524cc86416699b3c143e5faddb33d61380767
2017-06-15 16:22:44 -07:00
208 changed files with 15934 additions and 7787 deletions

521
.clang-format Normal file
View File

@@ -0,0 +1,521 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 4.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0
BeforeCatch: false
BeforeElse: false
IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0
#SplitEmptyRecord: true # Unknown to clang-format-4.0
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- '__ata_qc_for_each'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- '__bio_for_each_bvec'
- 'bio_for_each_bvec'
- 'bio_for_each_integrity_vec'
- '__bio_for_each_segment'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bitmap_for_each_clear_region'
- 'bitmap_for_each_set_region'
- 'blkg_for_each_descendant_post'
- 'blkg_for_each_descendant_pre'
- 'blk_queue_for_each_rl'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf_for_each_spilled_reg'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'device_for_each_child_node'
- 'dma_fence_chain_for_each'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'flow_action_for_each'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_available_child_of_node'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_cmsghdr'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_comp_order'
- 'for_each_console'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
- 'for_each_cpu_wrap'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_displayid_db'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_efi_handle'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_link_codecs'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_member'
- 'for_each_memblock'
- 'for_each_memblock_type'
- 'for_each_memcg_cache_index'
- 'for_each_mem_pfn_range'
- 'for_each_mem_range'
- 'for_each_mem_range_rev'
- 'for_each_migratetype_order'
- 'for_each_msi_entry'
- 'for_each_msi_entry_safe'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_net_rcu'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_private_obj_in_state'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pci_msi_entry'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_property_of_node'
- 'for_each_registered_fb'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dai'
- 'for_each_rtd_codec_dai_rollback'
- 'for_each_rtd_components'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- '__for_each_thread'
- 'for_each_thread'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hctx_for_each_ctx'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- '__hlist_for_each_rcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'ide_host_for_each_port'
- 'ide_port_for_each_dev'
- 'ide_port_for_each_present_dev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'inet_lhash2_for_each_icsk_rcu'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kvm_for_each_memslot'
- 'kvm_for_each_vcpu'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'ping_portaddr_for_each_entry'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- '__rq_for_each_bio'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'shdma_for_each_chan'
- '__shost_for_each_device'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'tb_property_for_each'
- 'tcf_exts_for_each_action'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'zorro_for_each_dev'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

50
.gitignore vendored
View File

@@ -2,20 +2,25 @@
*.o
*.lo
*.la
Transceiver52M/osmo-trx
Transceiver52M/osmo-trx-uhd
Transceiver52M/osmo-trx-usrp1
Transceiver52M/osmo-trx-lms
Transceiver52M/osmo-trx-ipc
# tests
CommonLibs/BitVectorTest
CommonLibs/ConfigurationTest
CommonLibs/F16Test
CommonLibs/InterthreadTest
CommonLibs/LogTest
CommonLibs/RegexpTest
CommonLibs/SocketsTest
CommonLibs/TimevalTest
CommonLibs/URLEncodeTest
CommonLibs/VectorTest
CommonLibs/PRBSTest
tests/CommonLibs/BitVectorTest
tests/CommonLibs/F16Test
tests/CommonLibs/InterthreadTest
tests/CommonLibs/LogTest
tests/CommonLibs/RegexpTest
tests/CommonLibs/SocketsTest
tests/CommonLibs/TimevalTest
tests/CommonLibs/URLEncodeTest
tests/CommonLibs/VectorTest
tests/CommonLibs/PRBSTest
tests/Transceiver52M/convolve_test
tests/Transceiver52M/LMSDeviceTest
Transceiver52M/device/ipc/ipc-driver-test
# automake/autoconf
*.in
@@ -41,6 +46,27 @@ ltmain.sh
missing
stamp-h1
INSTALL
tests/package.m4
tests/testsuite
tests/atconfig
tests/testsuite.dir
tests/testsuite.log
# vim
*.sw?
# manuals
doc/manuals/*.html
doc/manuals/*.svg
doc/manuals/*.pdf
doc/manuals/*__*.png
doc/manuals/*.check
doc/manuals/generated/
doc/manuals/osmomsc-usermanual.xml
doc/manuals/common
doc/manuals/build
contrib/osmo-trx.spec
!contrib/osmo-trx.spec.in
utils/osmo-prbs-tool

192
AUTHORS
View File

@@ -1,192 +0,0 @@
#
# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
David A. Burgess, dburgess@kestrelsp.com:
CLI/CLI.cpp
CLI/CLI.h
CommonLibs/Assert.h
CommonLibs/BitVector.cpp
CommonLibs/BitVectorTest.cpp
CommonLibs/Configuration.cpp
CommonLibs/Configuration.h
CommonLibs/ConfigurationTest.cpp
CommonLibs/Interthread.h
CommonLibs/InterthreadTest.cpp
CommonLibs/LinkedLists.cpp
CommonLibs/LinkedLists.h
CommonLibs/Regexp.h
CommonLibs/RegexpTest.cpp
CommonLibs/Sockets.cpp
CommonLibs/Sockets.h
CommonLibs/SocketsTest.cpp
CommonLibs/Threads.cpp
CommonLibs/Threads.h
CommonLibs/Timeval.cpp
CommonLibs/Timeval.h
CommonLibs/TimevalTest.cpp
CommonLibs/Vector.h
CommonLibs/VectorTest.cpp
Control/CallControl.cpp
Control/ControlCommon.cpp
Control/ControlCommon.h
Control/FACCHDispatch.cpp
Control/MobilityManagement.cpp
Control/PagerTest.cpp
Control/RadioResource.cpp
Control/SDCCHDispatch.cpp
GSM/GSM610Tables.cpp
GSM/GSM610Tables.h
GSM/GSMCommon.cpp
GSM/GSMCommon.h
GSM/GSMConfig.h
GSM/GSML1FEC.cpp
GSM/GSML1FEC.h
GSM/GSML2LAPDm.cpp
GSM/GSML2LAPDm.h
GSM/GSML3CCElements.cpp
GSM/GSML3CCElements.h
GSM/GSML3CCMessages.cpp
GSM/GSML3CCMessages.h
GSM/GSML3CommonElements.cpp
GSM/GSML3CommonElements.h
GSM/GSML3MMElements.cpp
GSM/GSML3MMElements.h
GSM/GSML3MMMessages.cpp
GSM/GSML3MMMessages.h
GSM/GSML3Message.cpp
GSM/GSML3Message.h
GSM/GSML3RRElements.cpp
GSM/GSML3RRElements.h
GSM/GSML3RRMessages.cpp
GSM/GSML3RRMessages.h
GSM/GSMLogicalChannel.h
GSM/GSMTDMA.cpp
GSM/GSMTDMA.h
GSM/GSMTransfer.cpp
GSM/GSMTransfer.h
LICENSEBLOCK
SIP/SIPEngine.h
SIP/SIPInterface.h
SMS/SMSMessages.cpp
SMS/SMSMessages.h
SMS/SMSTransfer.cpp
SMS/SMSTransfer.h
TRXManager/TRXManager.cpp
Transceiver/Complex.h
apps/OpenBTS900.cpp
apps/OpenBTS850.cpp
apps/OpenBTS25c3.cpp
tests/AGCHTest.cpp
tests/BeaconTest.cpp
tests/CallTest.cpp
tests/CallTest2.cpp
tests/LAPDmTest.cpp
tests/LoopbackTest.cpp
tests/RegistrationTest.cpp
tests/TRXSimulator.cpp
Harvind S. Samra, hssamra@kestrelsp.com:
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMConfig.h
GSM/GSMTransfer.h
LICENSEBLOCK
Transceiver/ComplexTest.cpp
Transceiver/Transceiver.cpp
Transceiver/Transceiver.h
Transceiver/USRPDevice.cpp
Transceiver/USRPDevice.h
Transceiver/USRPping.cpp
Transceiver/radioInterface.cpp
Transceiver/radioInterface.h
Transceiver/rcvLPF_651.h
Transceiver/runTransceiver.cpp
Transceiver/sendLPF_961.h
Transceiver/sigProcLib.cpp
Transceiver/sigProcLib.h
Transceiver/sigProcLibTest.cpp
Transceiver/sweepGenerator.cpp
Transceiver/testRadio.cpp
Raffi Sevlian, raffisev@gmail.com:
Control/CallControl.cpp
Control/ControlCommon.cpp
Control/ControlCommon.h
Control/FACCHDispatch.cpp
Control/MobilityManagement.cpp
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMCommon.h
GSM/GSMConfig.h
GSM/GSML1FEC.h
GSM/GSML3CCElements.cpp
GSM/GSML3CCElements.h
GSM/GSML3CCMessages.cpp
GSM/GSML3CCMessages.h
GSM/GSML3CommonElements.cpp
GSM/GSML3CommonElements.h
GSM/GSML3MMElements.cpp
GSM/GSML3MMElements.h
GSM/GSML3MMMessages.cpp
GSM/GSML3MMMessages.h
GSM/GSML3Message.cpp
GSM/GSML3Message.h
GSM/GSML3RRElements.cpp
GSM/GSML3RRElements.h
GSM/GSML3RRMessages.cpp
GSM/GSML3RRMessages.h
GSM/GSMLogicalChannel.h
GSM/GSMSAPMux.cpp
GSM/GSMSAPMux.h
GSM/GSMTransfer.h
LICENSEBLOCK
SIP/SIPEngine.cpp
SIP/SIPInterface.cpp
SIP/SIPInterface.h
SIP/SIPMessage.cpp
SIP/SIPMessage.h
SIP/SIPUtility.cpp
SIP/SIPUtility.h
SMS/CMMessage.cpp
SMS/CMMessage.h
SMS/CMProcessor.cpp
SMS/CMProcessor.h
SMS/CMTest.cpp
SMS/RLMessage.cpp
SMS/RLMessage.h
SMS/RLProcessor.cpp
SMS/RLProcessor.h
SMS/SMSMessages.cpp
SMS/SMSMessages.h
SMS/SMSProcessors.cpp
SMS/SMSProcessors.h
SMS/SMSTransfer.cpp
SMS/SMSTransfer.h
SMS/TLMessage.cpp
SMS/TLMessage.h
SMS/TLProcessor.cpp
SMS/TLProcessor.h
TRXManager/TRXManager.h
Alon Levy, alonlevy1@gmail.com
RRLPMessages.cpp
RRLPMessages.h
RRLPTest.cpp

30
COPYING
View File

@@ -666,23 +666,23 @@ For more information on this, and how to apply and follow the GNU AGPL, see
=========================================================================
This marks the end of the AGPLv3 text. The following text is appended to the
same file for convience but constituting a distinct document, not part of the
same file for convenience but constituting a distinct document, not part of the
actual AGPL text and not part of an attempt to create a deriviative work based
on the AGPLv3 text.
=========================================================================
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OPENBTS
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OsmoTRX
Permissive Terms Supplementing the License
1. Remote Interaction Through IP Networks.
OpenBTS includes an implementation of the GSM network cellular air interface,
OsmoTRX is an implementation of the GSM network cellular air interface,
as well as other interfaces to IP networks. The interaction of cellular
handsets with the OpenBTS software is considered "remote network interaction"
handsets with the OsmoTRX software is considered "remote network interaction"
for the purposes of the Affero General Public License and cellular users are
subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
Network Interaction; Use with the GNU General Public License").
@@ -694,17 +694,6 @@ interfaces other than the GSM air interface from the requirements of Section 13
is an additional permission granted to you.
Non-Permissive Terms Supplementing The License
1. Trademarks.
"OpenBTS" is a trademark of Range Networks, Inc., registered with
the US Patent and Trademark Office. Your use of OpenBTS software under a GPL
license does not include the right to use the OpenBTS trademark in commerce.
This additional non-permissive term is consistent with Section 7 of the AGPLv3
license.
END OF ADDITIONAL TERMS
@@ -712,13 +701,8 @@ END OF ADDITIONAL TERMS
How to comply with Section 13 of the AGPLv3 license.
The recommended method for compliance with Section 13 of the AGPLv3 license is
to deliver a text message to each handset that attaches to the OpenBTS cellular
network. At a minimum, that text message should include the string "OpenBTS
AGPLv3" and a URL that can be used to access the OpenBTS source code. This
to deliver a text message to each handset that attaches to the cellular
network which uses OsmoTRX. At a minimum, that text message should include the string
"OsmoTRX AGPLv3" and a URL that can be used to access the OsmoBTS source code. This
message need not be delivered to handsets that are denied registration with the
network, since those handsets have been denied service.
In OpenBTS 2.6, such text messages can be delivered with the "Welcome Message"
feature. See the OpenBTS.config.example file for more information on the use of
this feature for AGPLv3 compliance.

View File

@@ -1,6 +1,7 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -36,7 +37,7 @@ using namespace std;
/**
Apply a Galois polymonial to a binary seqeunce.
Apply a Galois polymonial to a binary sequence.
@param val The input sequence.
@param poly The polynomial.
@param order The order of the polynomial.

View File

@@ -1,6 +1,8 @@
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*

File diff suppressed because it is too large Load Diff

View File

@@ -1,422 +0,0 @@
/*
* Copyright 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011, 2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
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/>.
*/
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
#include "sqlite3util.h"
#include <assert.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <regex.h>
#include <map>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <Threads.h>
#include <stdint.h>
/** A class for configuration file errors. */
class ConfigurationTableError {};
extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it.
/** An exception thrown when a given config key isn't found. */
class ConfigurationTableKeyNotFound : public ConfigurationTableError {
private:
std::string mKey;
public:
ConfigurationTableKeyNotFound(const std::string& wKey)
:mKey(wKey)
{ }
const std::string& key() const { return mKey; }
};
class ConfigurationRecord {
private:
std::string mValue;
long mNumber;
bool mDefined;
public:
ConfigurationRecord(bool wDefined=true):
mDefined(wDefined)
{ }
ConfigurationRecord(const std::string& wValue):
mValue(wValue),
mNumber(strtol(wValue.c_str(),NULL,0)),
mDefined(true)
{ }
ConfigurationRecord(const char* wValue):
mValue(std::string(wValue)),
mNumber(strtol(wValue,NULL,0)),
mDefined(true)
{ }
const std::string& value() const { return mValue; }
long number() const { return mNumber; }
bool defined() const { return mDefined; }
float floatNumber() const;
};
/** A string class that uses a hash function for comparison. */
class HashString : public std::string {
protected:
uint64_t mHash;
void computeHash();
public:
HashString(const char* src)
:std::string(src)
{
computeHash();
}
HashString(const std::string& src)
:std::string(src)
{
computeHash();
}
HashString()
{
mHash=0;
}
HashString& operator=(std::string& src)
{
std::string::operator=(src);
computeHash();
return *this;
}
HashString& operator=(const char* src)
{
std::string::operator=(src);
computeHash();
return *this;
}
bool operator==(const HashString& other)
{
return mHash==other.mHash;
}
bool operator<(const HashString& other)
{
return mHash<other.mHash;
}
bool operator>(const HashString& other)
{
return mHash<other.mHash;
}
uint64_t hash() const { return mHash; }
};
typedef std::map<std::string, ConfigurationRecord> ConfigurationRecordMap;
typedef std::map<HashString, ConfigurationRecord> ConfigurationMap;
class ConfigurationKey;
typedef std::map<std::string, ConfigurationKey> ConfigurationKeyMap;
/**
A class for maintaining a configuration key-value table,
based on sqlite3 and a local map-based cache.
Thread-safe, too.
*/
class ConfigurationTable {
private:
sqlite3* mDB; ///< database connection
ConfigurationMap mCache; ///< cache of recently access configuration values
mutable Mutex mLock; ///< control for multithreaded access to the cache
std::vector<std::string> (*mCrossCheck)(const std::string&); ///< cross check callback pointer
public:
ConfigurationKeyMap mSchema;///< definition of configuration default values and validation logic
ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, ConfigurationKeyMap wSchema = ConfigurationKeyMap());
/** Generate an up-to-date example sql file for new installs. */
std::string getDefaultSQL(const std::string& program, const std::string& version);
/** Generate an up-to-date TeX snippet. */
std::string getTeX(const std::string& program, const std::string& version);
/** Return true if the key is used in the table. */
bool defines(const std::string& key);
/** Return true if the application's schema knows about this key. */
bool keyDefinedInSchema(const std::string& name);
/** Return true if the provided value validates correctly against the defined schema. */
bool isValidValue(const std::string& name, const std::string& val);
/** Return true if the provided value validates correctly against the defined schema. */
bool isValidValue(const std::string& name, const int val) { std::stringstream ss; ss << val; return isValidValue(name, ss.str()); }
/** Return a map of all similar keys in the defined schema. */
ConfigurationKeyMap getSimilarKeys(const std::string& snippet);
/** Return true if this key is identified as static. */
bool isStatic(const std::string& key);
/**
Get a string parameter from the table.
Throw ConfigurationTableKeyNotFound if not found.
*/
std::string getStr(const std::string& key);
/**
Get a boolean from the table.
Return false if NULL or 0, true otherwise.
*/
bool getBool(const std::string& key);
/**
Get a numeric parameter from the table.
Throw ConfigurationTableKeyNotFound if not found.
*/
long getNum(const std::string& key);
/**
Get a vector of strings from the table.
*/
std::vector<std::string> getVectorOfStrings(const std::string& key);
/**
Get a float from the table.
Throw ConfigurationTableKeyNotFound if not found.
*/
float getFloat(const std::string& key);
/**
Get a numeric vector from the table.
*/
std::vector<unsigned> getVector(const std::string& key);
/** Get length of a vector */
unsigned getVectorLength(const std::string &key)
{ return getVector(key).size(); }
/** Set or change a value in the table. */
bool set(const std::string& key, const std::string& value);
/** Set or change a value in the table. */
bool set(const std::string& key, long value);
/** Create an entry in the table, no value though. */
bool set(const std::string& key);
/**
Remove an entry from the table.
Will not alter required values.
@param key The key of the item to be removed.
@return true if anything was actually removed.
*/
bool remove(const std::string& key);
/** Search the table, dumping to a stream. */
void find(const std::string& pattern, std::ostream&) const;
/** Return all key/value pairs stored in the ConfigurationTable */
ConfigurationRecordMap getAllPairs() const;
/** Define the callback to purge the cache whenever the database changes. */
void setUpdateHook(void(*)(void *,int ,char const *,char const *,sqlite3_int64));
/** Define the callback for cross checking. */
void setCrossCheckHook(std::vector<std::string> (*wCrossCheck)(const std::string&));
/** Execute the application specific value cross checking logic. */
std::vector<std::string> crossCheck(const std::string& key);
/** purege cache if it exceeds a certain age */
void checkCacheAge();
/** Delete all records from the cache. */
void purge();
private:
/**
Attempt to lookup a record, cache if needed.
Throw ConfigurationTableKeyNotFound if not found.
Caller should hold mLock because the returned reference points into the cache.
*/
const ConfigurationRecord& lookup(const std::string& key);
};
typedef std::map<HashString, std::string> HashStringMap;
class SimpleKeyValue {
protected:
HashStringMap mMap;
public:
/** Take a C string "A=B" and set map["A"]="B". */
void addItem(const char*);
/** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */
void addItems(const char*s);
/** Return a reference to the string at map["key"]. */
const char* get(const char*) const;
};
class ConfigurationKey {
public:
enum VisibilityLevel
{
CUSTOMER,
CUSTOMERSITE,
CUSTOMERTUNE,
CUSTOMERWARN,
DEVELOPER,
FACTORY
};
enum Type
{
BOOLEAN,
CHOICE_OPT,
CHOICE,
CIDR_OPT,
CIDR,
FILEPATH_OPT,
FILEPATH,
IPADDRESS_OPT,
IPADDRESS,
IPANDPORT,
MIPADDRESS_OPT,
MIPADDRESS,
PORT_OPT,
PORT,
REGEX_OPT,
REGEX,
STRING_OPT,
STRING,
VALRANGE
};
private:
std::string mName;
std::string mDefaultValue;
std::string mUnits;
VisibilityLevel mVisibility;
Type mType;
std::string mValidValues;
bool mIsStatic;
std::string mDescription;
public:
ConfigurationKey(const std::string& wName, const std::string& wDefaultValue, const std::string& wUnits, const VisibilityLevel wVisibility, const Type wType, const std::string& wValidValues, bool wIsStatic, const std::string& wDescription):
mName(wName),
mDefaultValue(wDefaultValue),
mUnits(wUnits),
mVisibility(wVisibility),
mType(wType),
mValidValues(wValidValues),
mIsStatic(wIsStatic),
mDescription(wDescription)
{ }
ConfigurationKey()
{ }
const std::string& getName() const { return mName; }
const std::string& getDefaultValue() const { return mDefaultValue; }
void updateDefaultValue(const std::string& newValue) { mDefaultValue = newValue; }
void updateDefaultValue(const int newValue) { std::stringstream ss; ss << newValue; updateDefaultValue(ss.str()); }
const std::string& getUnits() const { return mUnits; }
const VisibilityLevel& getVisibility() const { return mVisibility; }
const Type& getType() const { return mType; }
const std::string& getValidValues() const { return mValidValues; }
bool isStatic() const { return mIsStatic; }
const std::string& getDescription() const { return mDescription; }
static bool isValidIP(const std::string& ip);
static void getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping);
template<class T> static bool isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger);
static const std::string visibilityLevelToString(const VisibilityLevel& visibility);
static const std::string typeToString(const ConfigurationKey::Type& type);
static void printKey(const ConfigurationKey &key, const std::string& currentValue, std::ostream& os);
static void printDescription(const ConfigurationKey &key, std::ostream& os);
static const std::string getARFCNsString();
};
#endif
// vim: ts=4 sw=4

View File

@@ -1,149 +0,0 @@
/*
* Copyright 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Configuration.h"
#include <iostream>
#include <string>
using namespace std;
ConfigurationKeyMap getConfigurationKeys();
ConfigurationTable gConfig("exampleconfig.db","test", getConfigurationKeys());
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
//cout << "update hook" << endl;
gConfig.purge();
}
int main(int argc, char *argv[])
{
gConfig.setUpdateHook(purgeConfig);
const char *keys[5] = {"key1", "key2", "key3", "key4", "key5"};
for (int i=0; i<5; i++) {
gConfig.set(keys[i],i);
}
for (int i=0; i<5; i++) {
cout << "table[" << keys[i] << "]=" << gConfig.getStr(keys[i]) << endl;
cout << "table[" << keys[i] << "]=" << gConfig.getNum(keys[i]) << endl;
}
for (int i=0; i<5; i++) {
cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) << endl;
}
gConfig.set("key5","100 200 300 400 ");
std::vector<unsigned> vect = gConfig.getVector("key5");
cout << "vect length " << vect.size() << ": ";
for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
cout << endl;
std::vector<string> svect = gConfig.getVectorOfStrings("key5");
cout << "vect length " << svect.size() << ": ";
for (unsigned i=0; i<svect.size(); i++) cout << " " << svect[i] << ":";
cout << endl;
cout << "bool " << gConfig.getBool("booltest") << endl;
gConfig.set("booltest",1);
cout << "bool " << gConfig.getBool("booltest") << endl;
gConfig.set("booltest",0);
cout << "bool " << gConfig.getBool("booltest") << endl;
gConfig.getStr("newstring");
gConfig.getNum("numnumber");
SimpleKeyValue pairs;
pairs.addItems(" a=1 b=34 dd=143 ");
cout<< pairs.get("a") << endl;
cout<< pairs.get("b") << endl;
cout<< pairs.get("dd") << endl;
gConfig.set("fkey","123.456");
float fval = gConfig.getFloat("fkey");
cout << "fkey " << fval << endl;
cout << "search fkey:" << endl;
gConfig.find("fkey",cout);
cout << "search fkey:" << endl;
gConfig.find("fkey",cout);
gConfig.remove("fkey");
cout << "search fkey:" << endl;
gConfig.find("fkey",cout);
try {
gConfig.getNum("supposedtoabort");
} catch (ConfigurationTableKeyNotFound) {
cout << "ConfigurationTableKeyNotFound exception successfully caught." << endl;
}
}
ConfigurationKeyMap getConfigurationKeys()
{
ConfigurationKeyMap map;
ConfigurationKey *tmp;
tmp = new ConfigurationKey("booltest","0",
"",
ConfigurationKey::DEVELOPER,
ConfigurationKey::BOOLEAN,
"",
false,
""
);
map[tmp->getName()] = *tmp;
free(tmp);
tmp = new ConfigurationKey("numnumber","42",
"",
ConfigurationKey::DEVELOPER,
ConfigurationKey::VALRANGE,
"0-100",
false,
""
);
map[tmp->getName()] = *tmp;
free(tmp);
tmp = new ConfigurationKey("newstring","new string value",
"",
ConfigurationKey::DEVELOPER,
ConfigurationKey::STRING,
"",
false,
""
);
map[tmp->getName()] = *tmp;
free(tmp);
return map;
}

View File

@@ -1,6 +1,8 @@
/*
* Copyright 2008, 2011 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -45,7 +47,7 @@
// (pat) The elements in the queue are type T*, and
// the Fifo class implements the underlying queue.
// The default is class PointerFIFO, which does not place any restrictions on the type of T,
// and is implemented by allocating auxilliary structures for the queue,
// and is implemented by allocating auxiliary structures for the queue,
// or SingleLinkedList, which implements the queue using an internal pointer in type T,
// which must implement the functional interface of class SingleLinkListNode,
// namely: functions T*next() and void setNext(T*).
@@ -53,7 +55,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue {
protected:
Fifo mQ;
Fifo mQ;
mutable Mutex mLock;
mutable Signal mWriteSignal;
@@ -160,7 +162,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue2 {
protected:
Fifo mQ;
Fifo mQ;
mutable Mutex mLock;
mutable Signal mWriteSignal;
@@ -256,7 +258,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue2 {
// This recurs (and the InterthreadQueue fills up with data)
// until the read thread's accumulated temporary priority causes it to
// get a second pre-emptive activation over the writing thread,
// resulting in bursts of activity by the read thread.
// resulting in bursts of activity by the read thread.
{ ScopedLock lock(mLock);
mQ.put(val);
}
@@ -281,7 +283,7 @@ template <class T> class InterthreadQueueWithWait {
protected:
PointerFIFO mQ;
PointerFIFO mQ;
mutable Mutex mLock;
mutable Signal mWriteSignal;
mutable Signal mReadSignal;

View File

@@ -1,6 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -29,6 +30,25 @@
#include "LinkedLists.h"
PointerFIFO::~PointerFIFO()
{
ListNode *node, *next;
node = mHead;
while (node != NULL) {
next = node->next();
delete node;
node = next;
}
node = mFreeList;
while (node != NULL) {
next = node->next();
delete node;
node = next;
}
}
void PointerFIFO::push_front(void* val) // by pat
{
// Pat added this routine for completeness, but never used or tested.

View File

@@ -1,7 +1,10 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
* 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 software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -70,6 +73,7 @@ class PointerFIFO {
:mHead(NULL),mTail(NULL),mFreeList(NULL),
mSize(0)
{}
~PointerFIFO();
unsigned size() const { return mSize; }
unsigned totalSize() const { return 0; } // Not used in this version.

View File

@@ -1,8 +1,7 @@
/*
* Copyright 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011, 2012 Range Networks, Inc.
* Copyright (C) 2018 sysmocom - s.f.m.c. GmbH
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -32,300 +31,33 @@
#include <stdarg.h>
#include <sys/time.h> // For gettimeofday
#include "Configuration.h"
#include "Logger.h"
#include "Threads.h" // pat added
using namespace std;
// Switches to enable/disable logging targets
// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
bool gLogToConsole = true;
bool gLogToSyslog = false;
FILE *gLogToFile = NULL;
Mutex gLogToLock;
// Reference to a global config table, used all over the system.
extern ConfigurationTable gConfig;
/**@ The global alarms table. */
//@{
Mutex alarmsLock;
list<string> alarmsList;
void addAlarm(const string&);
//@}
// (pat) If Log messages are printed before the classes in this module are inited
// (which happens when static classes have constructors that do work)
// the OpenBTS just crashes.
// Prevent that by setting sLoggerInited to true when this module is inited.
static bool sLoggerInited = 0;
static struct CheckLoggerInitStatus {
CheckLoggerInitStatus() { sLoggerInited = 1; }
} sCheckloggerInitStatus;
/** Names of the logging levels. */
const char *levelNames[] = {
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
};
int numLevels = 8;
int levelStringToInt(const string& name)
{
// Reverse search, since the numerically larger levels are more common.
for (int i=numLevels-1; i>=0; i--) {
if (name == levelNames[i]) return i;
}
// Common substitutions.
if (name=="INFORMATION") return 6;
if (name=="WARN") return 4;
if (name=="ERROR") return 3;
if (name=="CRITICAL") return 2;
if (name=="EMERGENCY") return 0;
// Unknown level.
return -1;
}
/** Given a string, return the corresponding level name. */
int lookupLevel(const string& key)
{
string val = gConfig.getStr(key);
int level = levelStringToInt(val);
if (level == -1) {
string defaultLevel = gConfig.mSchema["Log.Level"].getDefaultValue();
level = levelStringToInt(defaultLevel);
_LOG(CRIT) << "undefined logging level (" << key << " = \"" << val << "\") defaulting to \"" << defaultLevel << ".\" Valid levels are: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO or DEBUG";
gConfig.set(key, defaultLevel);
}
return level;
}
static std::string format(const char *fmt, ...)
{
va_list ap;
char buf[300];
va_start(ap,fmt);
int n = vsnprintf(buf,300,fmt,ap);
va_end(ap);
if (n >= (300-4)) { strcpy(&buf[(300-4)],"..."); }
return std::string(buf);
}
const std::string timestr()
{
struct timeval tv;
struct tm tm;
gettimeofday(&tv,NULL);
localtime_r(&tv.tv_sec,&tm);
unsigned tenths = tv.tv_usec / 100000; // Rounding down is ok.
return format(" %02d:%02d:%02d.%1d",tm.tm_hour,tm.tm_min,tm.tm_sec,tenths);
}
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
{
return os << ss.str();
}
int getLoggingLevel(const char* filename)
{
// Default level?
if (!filename) return lookupLevel("Log.Level");
// This can afford to be inefficient since it is not called that often.
const string keyName = string("Log.Level.") + string(filename);
if (gConfig.defines(keyName)) return lookupLevel(keyName);
return lookupLevel("Log.Level");
}
int gGetLoggingLevel(const char* filename)
{
// This is called a lot and needs to be efficient.
static Mutex sLogCacheLock;
static map<uint64_t,int> sLogCache;
static unsigned sCacheCount;
static const unsigned sCacheRefreshCount = 1000;
if (filename==NULL) return gGetLoggingLevel("");
HashString hs(filename);
uint64_t key = hs.hash();
sLogCacheLock.lock();
// Time for a cache flush?
if (sCacheCount>sCacheRefreshCount) {
sLogCache.clear();
sCacheCount=0;
}
// Is it cached already?
map<uint64_t,int>::const_iterator where = sLogCache.find(key);
sCacheCount++;
if (where!=sLogCache.end()) {
int retVal = where->second;
sLogCacheLock.unlock();
return retVal;
}
// Look it up in the config table and cache it.
// FIXME: Figure out why unlock and lock below fix the config table deadlock.
// (pat) Probably because getLoggingLevel may call LOG recursively via lookupLevel().
sLogCacheLock.unlock();
int level = getLoggingLevel(filename);
sLogCacheLock.lock();
sLogCache.insert(pair<uint64_t,int>(key,level));
sLogCacheLock.unlock();
return level;
}
// copies the alarm list and returns it. list supposed to be small.
list<string> gGetLoggerAlarms()
{
alarmsLock.lock();
list<string> ret;
// excuse the "complexity", but to use std::copy with a list you need
// an insert_iterator - copy technically overwrites, doesn't insert.
insert_iterator< list<string> > ii(ret, ret.begin());
copy(alarmsList.begin(), alarmsList.end(), ii);
alarmsLock.unlock();
return ret;
}
/** Add an alarm to the alarm list. */
void addAlarm(const string& s)
{
alarmsLock.lock();
alarmsList.push_back(s);
unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
alarmsLock.unlock();
}
Log::~Log()
{
if (mDummyInit) return;
// Anything at or above LOG_CRIT is an "alarm".
// Save alarms in the local list and echo them to stderr.
if (mPriority <= LOG_ERR) {
if (sLoggerInited) addAlarm(mStream.str().c_str());
cerr << mStream.str() << endl;
}
// Current logging level was already checked by the macro. So just log.
// Log to syslog
if (gLogToSyslog) {
syslog(mPriority, "%s", mStream.str().c_str());
}
// Log to file and console
if (gLogToConsole||gLogToFile) {
int mlen = mStream.str().size();
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
ScopedLock lock(gLogToLock);
if (gLogToConsole) {
// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
// so just use std::cout.
std::cout << mStream.str();
if (neednl) std::cout<<"\n";
}
if (gLogToFile) {
fputs(mStream.str().c_str(),gLogToFile);
if (neednl) {fputc('\n',gLogToFile);}
fflush(gLogToFile);
}
}
int old_state;
int mlen = mStream.str().size();
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
const char *fmt = neednl ? "%s\n" : "%s";
/* print related function called inside a C++ destructor, use pthread_setcancelstate() APIs.
See osmo-trx commit 86be40b4eb762d5c12e8e3f7388ca9f254e77b36 for more information */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
LOGPSRC(mCategory, mPriority, filename, line, fmt, mStream.str().c_str());
pthread_setcancelstate(old_state, NULL);
}
Log::Log(const char* name, const char* level, int facility)
{
mDummyInit = true;
gLogInit(name, level, facility);
}
ostringstream& Log::get()
{
assert(mPriority<numLevels);
mStream << levelNames[mPriority] << ' ';
return mStream;
}
void gLogInit(const char* name, const char* level, int facility)
{
// Set the level if one has been specified.
if (level) {
gConfig.set("Log.Level",level);
}
// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
string str = gConfig.getStr("Log.File");
if (gLogToFile==NULL && str.length() && 0==strncmp(gCmdName,"Open",4)) {
const char *fn = str.c_str();
if (fn && *fn && strlen(fn)>3) { // strlen because a garbage char is getting in sometimes.
gLogToFile = fopen(fn,"w"); // New log file each time we start.
if (gLogToFile) {
time_t now;
time(&now);
fprintf(gLogToFile,"Starting at %s",ctime(&now));
fflush(gLogToFile);
std::cout << "Logging to file: " << fn << "\n";
}
}
}
// Open the log connection.
openlog(name,0,facility);
}
void gLogEarly(int level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (gLogToSyslog) {
va_list args_copy;
va_copy(args_copy, args);
vsyslog(level | LOG_USER, fmt, args_copy);
va_end(args_copy);
}
if (gLogToConsole) {
va_list args_copy;
va_copy(args_copy, args);
vprintf(fmt, args_copy);
printf("\n");
va_end(args_copy);
}
if (gLogToFile) {
va_list args_copy;
va_copy(args_copy, args);
vfprintf(gLogToFile, fmt, args_copy);
fprintf(gLogToFile, "\n");
va_end(args_copy);
}
va_end(args);
}
// vim: ts=4 sw=4

View File

@@ -2,6 +2,8 @@
* Copyright 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -23,71 +25,47 @@
*/
// (pat) WARNING is stupidly defined in /usr/local/include/osipparser2/osip_const.h.
// This must be outside the #ifndef LOGGER_H to fix it as long as Logger.h included after the above file.
#ifdef WARNING
#undef WARNING
#endif
#ifndef LOGGER_H
#define LOGGER_H
#include <syslog.h>
#include <stdint.h>
#include <stdio.h>
#include <sstream>
#include <list>
#include <map>
#include <string>
#define _LOG(level) \
Log(LOG_##level).get() << pthread_self() \
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
extern "C" {
#include <osmocom/core/logging.h>
#include "debug.h"
}
#define IS_LOG_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel)
#ifdef NDEBUG
#define LOG(wLevel) \
if (LOG_##wLevel!=LOG_DEBUG && IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
#else
#define LOG(wLevel) \
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
/* Translation for old log statements */
#ifndef LOGL_ALERT
#define LOGL_ALERT LOGL_FATAL
#endif
#ifndef LOGL_ERR
#define LOGL_ERR LOGL_ERROR
#endif
#ifndef LOGL_WARNING
#define LOGL_WARNING LOGL_NOTICE
#endif
// pat: And for your edification here are the 'levels' as defined in syslog.h:
// LOG_EMERG 0 system is unusable
// LOG_ALERT 1 action must be taken immediately
// LOG_CRIT 2 critical conditions
// LOG_ERR 3 error conditions
// LOG_WARNING 4 warning conditions
// LOG_NOTICE 5 normal, but significant, condition
// LOG_INFO 6 informational message
// LOG_DEBUG 7 debug-level message
#define LOG(level) \
Log(DMAIN, LOGL_##level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "] "
// (pat) added - print out a var and its name.
// Use like this: int descriptive_name; LOG(INFO)<<LOGVAR(descriptive_name);
#define LOGVAR2(name,val) " " << name << "=" << (val)
#define LOGVAR(var) (" " #var "=") << var
#define LOGHEX(var) (" " #var "=0x") << hex << ((unsigned)var) << dec
#define LOGHEX2(name,val) " " << name << "=0x" << hex << ((unsigned)(val)) << dec
// These are kind of cheesy, but you can use for bitvector
#define LOGBV2(name,val) " " << name << "=(" << val<<" size:"<<val.size()<<")"
#define LOGBV(bv) LOGBV2(#bv,bv)
#define LOGVARRANGE(name,cur,lo,hi) " "<<name <<"=("<<(cur) << " range:"<<(lo) << " to "<<(hi) <<")"
#define LOGC(category, level) \
Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "] "
#define LOGLV(category, level) \
Log(category, level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "] "
#define OBJLOG(wLevel) \
LOG(wLevel) << "obj: " << this << ' '
#define LOGSRC(category, level, file, line) \
Log(category, level, file, line).get() << "[tid=" << pthread_self() << "] "
#define LOG_ASSERT(x) { if (!(x)) LOG(EMERG) << "assertion " #x " failed"; } assert(x);
#include "Threads.h" // must be after defines above, if these files are to be allowed to use LOG()
#define LOGCHAN(chan, category, level) \
Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "][chan=" << chan << "] "
/**
A C++ stream-based thread-safe logger.
Derived from Dr. Dobb's Sept. 2007 issue.
Updated to use syslog.
This object is NOT the global logger;
every log record is an object of this class.
*/
@@ -97,45 +75,28 @@ class Log {
protected:
std::ostringstream mStream; ///< This is where we buffer up the log entry.
int mPriority; ///< Priority of current report.
bool mDummyInit;
std::ostringstream mStream; ///< This is where we buffer up the log entry.
int mCategory; ///< Priority of current report.
int mPriority; ///< Category of current report.
const char *filename; ///< Source File Name of current report.
int line; ///< Line number in source file of current report.
public:
Log(int wPriority)
:mPriority(wPriority), mDummyInit(false)
Log(int wCategory, int wPriority, const char* filename, int line)
: mCategory(wCategory), mPriority(wPriority),
filename(filename), line(line)
{ }
Log(const char* name, const char* level=NULL, int facility=LOG_USER);
// Most of the work is in the destructor.
/** The destructor actually generates the log entry. */
~Log();
std::ostringstream& get();
};
extern bool gLogToConsole; // Output log messages to stdout
extern bool gLogToSyslog; // Output log messages to syslog
std::list<std::string> gGetLoggerAlarms(); ///< Get a copy of the recent alarm list.
const std::string timestr(); // A timestamp to print in messages.
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
/**@ Global control and initialization of the logging system. */
//@{
/** Initialize the global logging system. */
void gLogInit(const char* name, const char* level=NULL, int facility=LOG_USER);
/** Get the logging level associated with a given file. */
int gGetLoggingLevel(const char *filename=NULL);
/** Allow early logging when still in constructors */
void gLogEarly(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
//@}
#endif
// vim: ts=4 sw=4

View File

@@ -22,77 +22,35 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread
EXTRA_DIST = \
example.config \
README.common
AM_CXXFLAGS = -Wall -O3 -g -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_CFLAGS = $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = \
BitVector.cpp \
LinkedLists.cpp \
Sockets.cpp \
Threads.cpp \
Timeval.cpp \
Logger.cpp \
Configuration.cpp \
sqlite3util.cpp
noinst_PROGRAMS = \
BitVectorTest \
PRBSTest \
InterthreadTest \
SocketsTest \
TimevalTest \
VectorTest \
ConfigurationTest \
LogTest
# ReportingTest
Utils.cpp \
trx_rate_ctr.cpp \
trx_vty.c \
debug.c
libcommon_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
noinst_HEADERS = \
BitVector.h \
PRBS.h \
Interthread.h \
LinkedLists.h \
Sockets.h \
Threads.h \
Timeval.h \
Vector.h \
Configuration.h \
Logger.h \
sqlite3util.h
BitVectorTest_SOURCES = BitVectorTest.cpp
BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
PRBSTest_SOURCES = PRBSTest.cpp
InterthreadTest_SOURCES = InterthreadTest.cpp
InterthreadTest_LDADD = libcommon.la
InterthreadTest_LDFLAGS = -lpthread
SocketsTest_SOURCES = SocketsTest.cpp
SocketsTest_LDADD = libcommon.la
SocketsTest_LDFLAGS = -lpthread
TimevalTest_SOURCES = TimevalTest.cpp
TimevalTest_LDADD = libcommon.la
VectorTest_SOURCES = VectorTest.cpp
VectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
ConfigurationTest_SOURCES = ConfigurationTest.cpp
ConfigurationTest_LDADD = libcommon.la $(SQLITE3_LIBS)
# ReportingTest_SOURCES = ReportingTest.cpp
# ReportingTest_LDADD = libcommon.la $(SQLITE_LA)
LogTest_SOURCES = LogTest.cpp
LogTest_LDADD = libcommon.la $(SQLITE3_LIBS)
MOSTLYCLEANFILES += testSource testDestination
Utils.h \
trx_rate_ctr.h \
trx_vty.h \
debug.h \
osmo_signal.h \
config_defs.h

View File

@@ -1,6 +1,8 @@
/*
* Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -1,333 +0,0 @@
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <sys/select.h>
#include "Threads.h"
#include "Sockets.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
{
assert(address);
assert(hostAndPort);
char *copy = strdup(hostAndPort);
char *colon = strchr(copy,':');
if (!colon) return false;
*colon = '\0';
char *host = copy;
unsigned port = strtol(colon+1,NULL,10);
bool retVal = resolveAddress(address,host,port);
free(copy);
return retVal;
}
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
{
assert(address);
assert(host);
// FIXME -- Need to ignore leading/trailing spaces in hostname.
struct hostent *hp;
int h_errno_local;
#ifdef HAVE_GETHOSTBYNAME2_R
struct hostent hostData;
char tmpBuffer[2048];
// There are different flavors of gethostbyname_r(), but
// latest Linux use the following form:
if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
return false;
}
#else
static Mutex sGethostbynameMutex;
// gethostbyname() is NOT thread-safe, so we should use a mutex here.
// Ideally it should be a global mutex for all non thread-safe socket
// operations and it should protect access to variables such as
// global h_errno.
sGethostbynameMutex.lock();
hp = gethostbyname(host);
h_errno_local = h_errno;
sGethostbynameMutex.unlock();
#endif
if (hp==NULL) {
CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local));
return false;
}
if (hp->h_addrtype != AF_INET) {
CERR("WARNING -- gethostbyname() resolved " << host << " to something other then AF_INET");
return false;
}
address->sin_family = hp->h_addrtype;
assert(sizeof(address->sin_addr) == hp->h_length);
memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
address->sin_port = htons(port);
return true;
}
DatagramSocket::DatagramSocket()
{
memset(mDestination, 0, sizeof(mDestination));
}
void DatagramSocket::nonblocking()
{
fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
}
void DatagramSocket::blocking()
{
fcntl(mSocketFD,F_SETFL,0);
}
void DatagramSocket::close()
{
::close(mSocketFD);
}
DatagramSocket::~DatagramSocket()
{
close();
}
int DatagramSocket::write( const char * message, size_t length )
{
assert(length<=MAX_UDP_LENGTH);
int retVal = sendto(mSocketFD, message, length, 0,
(struct sockaddr *)mDestination, addressSize());
if (retVal == -1 ) perror("DatagramSocket::write() failed");
return retVal;
}
int DatagramSocket::writeBack( const char * message, size_t length )
{
assert(length<=MAX_UDP_LENGTH);
int retVal = sendto(mSocketFD, message, length, 0,
(struct sockaddr *)mSource, addressSize());
if (retVal == -1 ) perror("DatagramSocket::write() failed");
return retVal;
}
int DatagramSocket::write( const char * message)
{
size_t length=strlen(message)+1;
return write(message,length);
}
int DatagramSocket::writeBack( const char * message)
{
size_t length=strlen(message)+1;
return writeBack(message,length);
}
int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
{
assert(length<=MAX_UDP_LENGTH);
int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
if (retVal == -1 ) perror("DatagramSocket::send() failed");
return retVal;
}
int DatagramSocket::send(const struct sockaddr* dest, const char * message)
{
size_t length=strlen(message)+1;
return send(dest,message,length);
}
int DatagramSocket::read(char* buffer, size_t length)
{
socklen_t addr_len = sizeof(mSource);
int rd_length = recvfrom(mSocketFD, (void *) buffer, length, 0,
(struct sockaddr*) &mSource, &addr_len);
if ((rd_length==-1) && (errno!=EAGAIN)) {
perror("DatagramSocket::read() failed");
throw SocketError();
}
return rd_length;
}
int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(mSocketFD,&fds);
struct timeval tv;
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000)*1000;
int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
if (sel<0) {
perror("DatagramSocket::read() select() failed");
throw SocketError();
}
if (sel==0) return -1;
if (FD_ISSET(mSocketFD,&fds)) return read(buffer, length);
return -1;
}
UDPSocket::UDPSocket(unsigned short wSrcPort)
:DatagramSocket()
{
open(wSrcPort);
}
UDPSocket::UDPSocket(unsigned short wSrcPort,
const char * wDestIP, unsigned short wDestPort )
:DatagramSocket()
{
open(wSrcPort);
destination(wDestPort, wDestIP);
}
void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
{
resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
}
void UDPSocket::open(unsigned short localPort)
{
// create
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
if (mSocketFD<0) {
perror("socket() failed");
throw SocketError();
}
// pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
int on = 1;
setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
// bind
struct sockaddr_in address;
size_t length = sizeof(address);
bzero(&address,length);
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
address.sin_port = htons(localPort);
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
perror("bind() failed");
throw SocketError();
}
}
unsigned short UDPSocket::port() const
{
struct sockaddr_in name;
socklen_t nameSize = sizeof(name);
int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
if (retVal==-1) throw SocketError();
return ntohs(name.sin_port);
}
UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
:DatagramSocket()
{
if (localPath!=NULL) open(localPath);
if (remotePath!=NULL) destination(remotePath);
}
void UDDSocket::open(const char* localPath)
{
// create
mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
if (mSocketFD<0) {
perror("socket() failed");
throw SocketError();
}
// bind
struct sockaddr_un address;
size_t length = sizeof(address);
bzero(&address,length);
address.sun_family = AF_UNIX;
strcpy(address.sun_path,localPath);
unlink(localPath);
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
perror("bind() failed");
throw SocketError();
}
}
void UDDSocket::destination(const char* remotePath)
{
struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
strcpy(unAddr->sun_path,remotePath);
}
// vim:ts=4:sw=4

View File

@@ -1,193 +0,0 @@
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
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/>.
*/
#ifndef SOCKETS_H
#define SOCKETS_H
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <list>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define MAX_UDP_LENGTH 1500
/** A function to resolve IP host names. */
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port);
/** Resolve an address of the form "<host>:<port>". */
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort);
/** An exception to throw when a critical socket operation fails. */
class SocketError {};
#define SOCKET_ERROR {throw SocketError(); }
/** Abstract class for connectionless sockets. */
class DatagramSocket {
protected:
int mSocketFD; ///< underlying file descriptor
char mDestination[256]; ///< address to which packets are sent
char mSource[256]; ///< return address of most recent received packet
public:
/** An almost-does-nothing constructor. */
DatagramSocket();
virtual ~DatagramSocket();
/** Return the address structure size for this socket type. */
virtual size_t addressSize() const = 0;
/**
Send a binary packet.
@param buffer The data bytes to send to mDestination.
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
@return number of bytes written, or -1 on error.
*/
int write( const char * buffer, size_t length);
/**
Send a C-style string packet.
@param buffer The data bytes to send to mDestination.
@return number of bytes written, or -1 on error.
*/
int write( const char * buffer);
/**
Send a binary packet.
@param buffer The data bytes to send to mSource.
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
@return number of bytes written, or -1 on error.
*/
int writeBack(const char * buffer, size_t length);
/**
Send a C-style string packet.
@param buffer The data bytes to send to mSource.
@return number of bytes written, or -1 on error.
*/
int writeBack(const char * buffer);
/**
Receive a packet.
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
@return The number of bytes received or -1 on non-blocking pass.
*/
int read(char* buffer, size_t length);
/**
Receive a packet with a timeout.
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
@param maximum wait time in milliseconds
@return The number of bytes received or -1 on timeout.
*/
int read(char* buffer, size_t length, unsigned timeout);
/** Send a packet to a given destination, other than the default. */
int send(const struct sockaddr *dest, const char * buffer, size_t length);
/** Send a C-style string to a given destination, other than the default. */
int send(const struct sockaddr *dest, const char * buffer);
/** Make the socket non-blocking. */
void nonblocking();
/** Make the socket blocking (the default). */
void blocking();
/** Close the socket. */
void close();
};
/** UDP/IP User Datagram Socket */
class UDPSocket : public DatagramSocket {
public:
/** Open a USP socket with an OS-assigned port and no default destination. */
UDPSocket( unsigned short localPort=0);
/** Given a full specification, open the socket and set the dest address. */
UDPSocket( unsigned short localPort,
const char * remoteIP, unsigned short remotePort);
/** Set the destination port. */
void destination( unsigned short wDestPort, const char * wDestIP );
/** Return the actual port number in use. */
unsigned short port() const;
/** Open and bind the UDP socket to a local port. */
void open(unsigned short localPort=0);
/** Give the return address of the most recently received packet. */
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
size_t addressSize() const { return sizeof(struct sockaddr_in); }
};
/** Unix Domain Datagram Socket */
class UDDSocket : public DatagramSocket {
public:
UDDSocket(const char* localPath=NULL, const char* remotePath=NULL);
void destination(const char* remotePath);
void open(const char* localPath);
/** Give the return address of the most recently received packet. */
const struct sockaddr_un* source() const { return (const struct sockaddr_un*)mSource; }
size_t addressSize() const { return sizeof(struct sockaddr_un); }
};
#endif
// vim:ts=4:sw=4

View File

@@ -1,103 +0,0 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Sockets.h"
#include "Threads.h"
#include <stdio.h>
#include <stdlib.h>
static const int gNumToSend = 10;
void *testReaderIP(void *)
{
UDPSocket readSocket(5934, "localhost", 5061);
readSocket.nonblocking();
int rc = 0;
while (rc<gNumToSend) {
char buf[MAX_UDP_LENGTH];
int count = readSocket.read(buf, MAX_UDP_LENGTH);
if (count>0) {
COUT("read: " << buf);
rc++;
} else {
sleep(2);
}
}
return NULL;
}
void *testReaderUnix(void *)
{
UDDSocket readSocket("testDestination");
readSocket.nonblocking();
int rc = 0;
while (rc<gNumToSend) {
char buf[MAX_UDP_LENGTH];
int count = readSocket.read(buf, MAX_UDP_LENGTH);
if (count>0) {
COUT("read: " << buf);
rc++;
} else {
sleep(2);
}
}
return NULL;
}
int main(int argc, char * argv[] )
{
Thread readerThreadIP;
readerThreadIP.start(testReaderIP,NULL);
Thread readerThreadUnix;
readerThreadUnix.start(testReaderUnix,NULL);
UDPSocket socket1(5061, "127.0.0.1",5934);
UDDSocket socket1U("testSource","testDestination");
COUT("socket1: " << socket1.port());
// give the readers time to open
sleep(1);
for (int i=0; i<gNumToSend; i++) {
socket1.write("Hello IP land");
socket1U.write("Hello Unix domain");
sleep(1);
}
readerThreadIP.join();
readerThreadUnix.join();
}
// vim: ts=4 sw=4

View File

@@ -1,6 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -24,16 +25,24 @@
*/
#include <string.h>
#include <sys/types.h>
#include "Threads.h"
#include "Timeval.h"
#include "Logger.h"
#ifndef gettid
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
using namespace std;
#ifndef HAVE_ATOMIC_OPS
pthread_mutex_t atomic_ops_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
Mutex gStreamLock; ///< Global lock to control access to cout and cerr.
@@ -102,6 +111,25 @@ void Signal::wait(Mutex& wMutex, unsigned timeout) const
pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime);
}
void set_selfthread_name(const char *name)
{
pthread_t selfid = pthread_self();
pid_t tid = gettid();
if (pthread_setname_np(selfid, name) == 0) {
LOG(INFO) << "Thread "<< selfid << " (task " << tid << ") set name: " << name;
} else {
char buf[256];
int err = errno;
char* err_str = strerror_r(err, buf, sizeof(buf));
LOG(NOTICE) << "Thread "<< selfid << " (task " << tid << ") set name \"" << name << "\" failed: (" << err << ") " << err_str;
}
}
void thread_enable_cancel(bool cancel)
{
cancel ? pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) :
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
}
void Thread::start(void *(*task)(void*), void *arg)
{
@@ -110,8 +138,10 @@ void Thread::start(void *(*task)(void*), void *arg)
// (pat) Moved initialization to constructor to avoid crash in destructor.
//res = pthread_attr_init(&mAttrib);
//assert(!res);
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
assert(!res);
if (mStackSize != 0) {
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
assert(!res);
}
res = pthread_create(&mThread, &mAttrib, task, arg);
assert(!res);
}

View File

@@ -1,6 +1,8 @@
/*
* Copyright 2008, 2011 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -26,6 +28,8 @@
#ifndef THREADS_H
#define THREADS_H
#include "config.h"
#include <pthread.h>
#include <iostream>
#include <assert.h>
@@ -55,7 +59,7 @@ void unlockCout(); ///< call after writing cout
#define OBJDCOUT(text) {}
#else
#define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); }
#define OBJDCOUT(text) { DCOUT(this << " " << text); }
#define OBJDCOUT(text) { DCOUT(this << " " << text); }
#endif
//@}
//@}
@@ -141,6 +145,9 @@ class Signal {
#define START_THREAD(thread,function,argument) \
thread.start((void *(*)(void*))function, (void*)argument);
void set_selfthread_name(const char *name);
void thread_enable_cancel(bool cancel);
/** A C++ wrapper for pthread threads. */
class Thread {
@@ -150,12 +157,12 @@ class Thread {
pthread_attr_t mAttrib;
// FIXME -- Can this be reduced now?
size_t mStackSize;
public:
/** Create a thread in a non-running state. */
Thread(size_t wStackSize = (65536*4)):mThread((pthread_t)0) {
Thread(size_t wStackSize = 0):mThread((pthread_t)0) {
pthread_attr_init(&mAttrib); // (pat) moved this here.
mStackSize=wStackSize;
}
@@ -179,12 +186,34 @@ class Thread {
}
}
/** Send cancelation to thread */
/** Send cancellation to thread */
void cancel() { pthread_cancel(mThread); }
};
#ifdef HAVE_ATOMIC_OPS
#define osmo_trx_sync_fetch_and_and(ptr, value) __sync_fetch_and_and((ptr), (value))
#define osmo_trx_sync_or_and_fetch(ptr, value) __sync_or_and_fetch((ptr), (value))
#else
extern pthread_mutex_t atomic_ops_mutex;
static inline int osmo_trx_sync_fetch_and_and(int *ptr, int value)
{
pthread_mutex_lock(&atomic_ops_mutex);
int tmp = *ptr;
*ptr &= value;
pthread_mutex_unlock(&atomic_ops_mutex);
return tmp;
}
static inline int osmo_trx_sync_or_and_fetch(int *ptr, int value)
{
int tmp;
pthread_mutex_lock(&atomic_ops_mutex);
*ptr |= value;
tmp = *ptr;
pthread_mutex_unlock(&atomic_ops_mutex);
return tmp;
}
#endif
#endif
// vim: ts=4 sw=4

View File

@@ -1,6 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -27,43 +28,49 @@
#include "Timeval.h"
extern "C" {
#include <osmocom/core/timer.h>
}
using namespace std;
void Timeval::now()
{
osmo_clock_gettime(CLOCK_REALTIME, &mTimespec);
}
void Timeval::future(unsigned offset)
{
now();
unsigned sec = offset/1000;
unsigned msec = offset%1000;
mTimeval.tv_usec += msec*1000;
mTimeval.tv_sec += sec;
if (mTimeval.tv_usec>1000000) {
mTimeval.tv_usec -= 1000000;
mTimeval.tv_sec += 1;
mTimespec.tv_nsec += msec*1000*1000;
mTimespec.tv_sec += sec;
if (mTimespec.tv_nsec > 1000*1000*1000) {
mTimespec.tv_nsec -= 1000*1000*1000;
mTimespec.tv_sec += 1;
}
}
struct timespec Timeval::timespec() const
{
struct timespec retVal;
retVal.tv_sec = mTimeval.tv_sec;
retVal.tv_nsec = 1000 * (long)mTimeval.tv_usec;
return retVal;
return mTimespec;
}
bool Timeval::passed() const
{
Timeval nowTime;
if (nowTime.mTimeval.tv_sec < mTimeval.tv_sec) return false;
if (nowTime.mTimeval.tv_sec > mTimeval.tv_sec) return true;
if (nowTime.mTimeval.tv_usec > mTimeval.tv_usec) return true;
if (nowTime.mTimespec.tv_sec < mTimespec.tv_sec) return false;
if (nowTime.mTimespec.tv_sec > mTimespec.tv_sec) return true;
if (nowTime.mTimespec.tv_nsec >= mTimespec.tv_nsec) return true;
return false;
}
double Timeval::seconds() const
{
return ((double)mTimeval.tv_sec) + 1e-6*((double)mTimeval.tv_usec);
return ((double)mTimespec.tv_sec) + 1e-9*((double)mTimespec.tv_nsec);
}
@@ -72,24 +79,25 @@ long Timeval::delta(const Timeval& other) const
{
// 2^31 milliseconds is just over 4 years.
int32_t deltaS = other.sec() - sec();
int32_t deltaUs = other.usec() - usec();
return 1000*deltaS + deltaUs/1000;
int32_t deltaNs = other.nsec() - nsec();
return 1000*deltaS + deltaNs/1000000;
}
ostream& operator<<(ostream& os, const Timeval& tv)
{
os.setf( ios::fixed, ios::floatfield );
ios_base::fmtflags flags_backup = os.setf( ios::fixed, ios::floatfield );
os << tv.seconds();
os.flags( flags_backup );
return os;
}
ostream& operator<<(ostream& os, const struct timespec& ts)
{
os << ts.tv_sec << "," << ts.tv_nsec;
os << ts.tv_sec << "," << ts.tv_nsec/1000;
return os;
}

View File

@@ -1,6 +1,8 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -42,12 +44,12 @@ class Timeval {
private:
struct timeval mTimeval;
struct timespec mTimespec;
public:
/** Set the value to gettimeofday. */
void now() { gettimeofday(&mTimeval,NULL); }
/** Set the value to current time. */
void now();
/** Set the value to gettimeofday plus an offset. */
void future(unsigned ms);
@@ -55,16 +57,18 @@ class Timeval {
//@{
Timeval(unsigned sec, unsigned usec)
{
mTimeval.tv_sec = sec;
mTimeval.tv_usec = usec;
mTimespec.tv_sec = sec;
mTimespec.tv_nsec = usec*1000;
}
Timeval(const struct timeval& wTimeval)
:mTimeval(wTimeval)
{}
{
mTimespec.tv_sec = wTimeval.tv_sec;
mTimespec.tv_nsec = wTimeval.tv_sec*1000;
}
/**
Create a Timeval offset into the future.
Create a Timespec offset into the future.
@param offset milliseconds
*/
Timeval(unsigned offset=0) { future(offset); }
@@ -76,10 +80,11 @@ class Timeval {
/** Return total seconds. */
double seconds() const;
uint32_t sec() const { return mTimeval.tv_sec; }
uint32_t usec() const { return mTimeval.tv_usec; }
uint32_t sec() const { return mTimespec.tv_sec; }
uint32_t usec() const { return mTimespec.tv_nsec / 1000; }
uint32_t nsec() const { return mTimespec.tv_nsec; }
/** Return differnce from other (other-self), in ms. */
/** Return difference from other (other-self), in ms. */
long delta(const Timeval& other) const;
/** Elapsed time in ms. */
@@ -88,11 +93,11 @@ class Timeval {
/** Remaining time in ms. */
long remaining() const { return -elapsed(); }
/** Return true if the time has passed, as per gettimeofday. */
/** Return true if the time has passed, as per clock_gettime(CLOCK_REALTIME). */
bool passed() const;
/** Add a given number of minutes to the time. */
void addMinutes(unsigned minutes) { mTimeval.tv_sec += minutes*60; }
void addMinutes(unsigned minutes) { mTimespec.tv_sec += minutes*60; }
};

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Timeval.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
Timeval then(10000);
cout << then.elapsed() << endl;
while (!then.passed()) {
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
usleep(500000);
}
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
}

38
CommonLibs/Utils.cpp Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright 2018 sysmocom - s.f.m.c. GmbH
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <vector>
#include <string>
#include <sstream>
std::vector<std::string> comma_delimited_to_vector(const char* opt)
{
std::string str = std::string(opt);
std::vector<std::string> result;
std::stringstream ss(str);
while( ss.good() )
{
std::string substr;
getline(ss, substr, ',');
result.push_back(substr);
}
return result;
}

26
CommonLibs/Utils.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright 2018 sysmocom - s.f.m.c. GmbH
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <vector>
#include <string>
std::vector<std::string> comma_delimited_to_vector(const char* opt);

View File

@@ -2,6 +2,8 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -32,11 +34,14 @@
#include <string.h>
#include <iostream>
#include <assert.h>
// We cant use Logger.h in this file...
#include <stdlib.h>
// We can't use Logger.h in this file...
extern int gVectorDebug;
#define BVDEBUG(msg) if (gVectorDebug) {std::cout << msg;}
typedef void (*vector_free_func)(void* wData);
typedef void *(*vector_alloc_func)(size_t newSize);
/**
A simplified Vector template with aliases.
@@ -60,6 +65,8 @@ template <class T> class Vector {
T* mData; ///< allocated data block, if any
T* mStart; ///< start of useful data
T* mEnd; ///< end of useful data + 1
vector_alloc_func mAllocFunc; ///< function used to alloc new mData during resize.
vector_free_func mFreeFunc; ///< function used to free mData.
public:
@@ -85,9 +92,19 @@ template <class T> class Vector {
/** Change the size of the Vector, discarding content. */
void resize(size_t newSize)
{
if (mData!=NULL) delete[] mData;
if (mData!=NULL) {
if (mFreeFunc)
mFreeFunc(mData);
else
delete[] mData;
}
if (newSize==0) mData=NULL;
else mData = new T[newSize];
else {
if (mAllocFunc)
mData = (T*) mAllocFunc(newSize);
else
mData = new T[newSize];
}
mStart = mData;
mEnd = mStart + newSize;
}
@@ -107,7 +124,7 @@ template <class T> class Vector {
void clone(const Vector<T>& other)
{
resize(other.size());
memcpy(mData,other.mStart,other.bytes());
other.copyTo(*this);
}
@@ -116,29 +133,31 @@ template <class T> class Vector {
//@{
/** Build an empty Vector of a given size. */
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
Vector(size_t wSize=0, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
:mData(NULL), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
{ resize(wSize); }
/** Build a Vector by shifting the data block. */
Vector(Vector<T>& other)
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
/** Build a Vector by moving another. */
Vector(Vector<T>&& other)
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd), mAllocFunc(other.mAllocFunc), mFreeFunc(other.mFreeFunc)
{ other.mData=NULL; }
/** Build a Vector by copying another. */
Vector(const Vector<T>& other):mData(NULL) { clone(other); }
Vector(const Vector<T>& other):mData(NULL), mAllocFunc(other.mAllocFunc), mFreeFunc(other.mFreeFunc) { clone(other); }
/** Build a Vector with explicit values. */
Vector(T* wData, T* wStart, T* wEnd)
:mData(wData),mStart(wStart),mEnd(wEnd)
Vector(T* wData, T* wStart, T* wEnd, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
:mData(wData),mStart(wStart),mEnd(wEnd), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
{ }
/** Build a vector from an existing block, NOT to be deleted upon destruction. */
Vector(T* wStart, size_t span)
:mData(NULL),mStart(wStart),mEnd(wStart+span)
Vector(T* wStart, size_t span, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
:mData(NULL),mStart(wStart),mEnd(wStart+span),mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
{ }
/** Build a Vector by concatenation. */
Vector(const Vector<T>& other1, const Vector<T>& other2)
:mData(NULL)
Vector(const Vector<T>& other1, const Vector<T>& other2, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
:mData(NULL), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
{
resize(other1.size()+other2.size());
memcpy(mStart, other1.mStart, other1.bytes());
@@ -162,6 +181,8 @@ template <class T> class Vector {
mData=other.mData;
mStart=other.mStart;
mEnd=other.mEnd;
mAllocFunc=other.mAllocFunc;
mFreeFunc=other.mFreeFunc;
other.mData=NULL;
}
@@ -204,10 +225,15 @@ template <class T> class Vector {
*/
void copyToSegment(Vector<T>& other, size_t start, size_t span) const
{
T* base = other.mStart + start;
assert(base+span<=other.mEnd);
unsigned int i;
T* dst = other.mStart + start;
T* src = mStart;
assert(dst+span<=other.mEnd);
assert(mStart+span<=mEnd);
memcpy(base,mStart,span*sizeof(T));
for (i = 0; i < span; i++, src++, dst++)
*dst = *src;
/*TODO if not non-trivially copiable type class, optimize:
memcpy(dst,mStart,span*sizeof(T)); */
}
/** Copy all of this Vector to a segment of another Vector. */
@@ -282,7 +308,7 @@ template <class T> class Vector {
T* end() { return mEnd; }
bool isOwner() { return !!mData; } // Do we own any memory ourselves?
//@}
};

20
CommonLibs/config_defs.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
/*
* This file contains structures used by both VTY (C, dir CommonLibs) and
* osmo-trx (CXX, dir Transceiver52)
*/
enum FillerType {
FILLER_DUMMY,
FILLER_ZERO,
FILLER_NORM_RAND,
FILLER_EDGE_RAND,
FILLER_ACCESS_RAND,
};
enum ReferenceType {
REF_INTERNAL,
REF_EXTERNAL,
REF_GPS,
};

101
CommonLibs/debug.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2018-2019 sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* 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"
/* default categories */
static const struct log_info_cat default_categories[] = {
[DMAIN] = {
.name = "DMAIN",
.description = "Main generic category",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXCLK] = {
.name = "DTRXCLK",
.description = "TRX Master Clock",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXCTRL] = {
.name = "DTRXCTRL",
.description = "TRX CTRL interface",
.color = "\033[1;33m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXDDL] = {
.name = "DTRXDDL",
.description = "TRX Data interface Downlink",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXDUL] = {
.name = "DTRXDUL",
.description = "TRX CTRL interface Uplink",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DDEV] = {
.name = "DDEV",
.description = "Device/Driver specific code",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DDEVDRV] = {
.name = "DDEVDRV",
.description = "Logging from external device driver library implementing lower level specifics",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
};
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
}

29
CommonLibs/debug.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <stdbool.h>
#include <sys/types.h>
#include <osmocom/core/logging.h>
extern const struct log_info log_info;
/* Debug Areas of the code */
enum {
DMAIN,
DTRXCLK,
DTRXCTRL,
DTRXDDL,
DTRXDUL,
DDEV,
DDEVDRV,
};
pid_t my_gettid(void);
#define CLOGC(category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld] " fmt, (long int) my_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); \
} while(0)

57
CommonLibs/osmo_signal.h Normal file
View File

@@ -0,0 +1,57 @@
/* Generic signalling/notification infrastructure */
/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* All Rights Reserved
*
* 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/>.
*
*/
#pragma once
#include <osmocom/core/signal.h>
/* Signalling subsystems */
enum signal_subsystems {
SS_MAIN,
SS_DEVICE,
};
/* SS_MAIN signals */
enum SS_MAIN {
S_MAIN_STOP_REQUIRED, /* TRX fatal error, it should be stopped */
};
/* SS_DEVICE signals */
enum SS_DEVICE {
/* Device internal counters changed. Counters are provided as cb data
(struct device_counters). Must be sent with PTHREAD_CANCEL_DISABLE
to avoid deadlocks in case osmo-trx process is asked to exit. */
S_DEVICE_COUNTER_CHANGE,
};
/* signal cb for signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> */
struct device_counters {
size_t chan;
unsigned int rx_overruns;
unsigned int tx_underruns;
unsigned int rx_dropped_events;
unsigned int rx_dropped_samples;
unsigned int tx_dropped_events;
unsigned int tx_dropped_samples;
};

View File

@@ -1,154 +0,0 @@
/*
* Copyright 2010 Kestrel Signal Processing, Inc.
* All rights reserved.
*/
#include <sqlite3.h>
#include "sqlite3util.h"
#include <string.h>
#include <unistd.h>
#include <stdio.h>
// Wrappers to sqlite operations.
// These will eventually get moved to commonlibs.
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query)
{
int src = SQLITE_BUSY;
while (src==SQLITE_BUSY) {
src = sqlite3_prepare_v2(DB,query,strlen(query),stmt,NULL);
if (src==SQLITE_BUSY) {
usleep(100000);
}
}
if (src) {
fprintf(stderr,"sqlite3_prepare_v2 failed for \"%s\": %s\n",query,sqlite3_errmsg(DB));
sqlite3_finalize(*stmt);
}
return src;
}
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt)
{
int src = SQLITE_BUSY;
while (src==SQLITE_BUSY) {
src = sqlite3_step(stmt);
if (src==SQLITE_BUSY) {
usleep(100000);
}
}
if ((src!=SQLITE_DONE) && (src!=SQLITE_ROW)) {
fprintf(stderr,"sqlite3_run_query failed: %s: %s\n", sqlite3_sql(stmt), sqlite3_errmsg(DB));
}
return src;
}
bool sqlite3_exists(sqlite3* DB, const char *tableName,
const char* keyName, const char* keyData)
{
size_t stringSize = 100 + strlen(tableName) + strlen(keyName) + strlen(keyData);
char query[stringSize];
sprintf(query,"SELECT * FROM %s WHERE %s == \"%s\"",tableName,keyName,keyData);
// Prepare the statement.
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
// Read the result.
int src = sqlite3_run_query(DB,stmt);
sqlite3_finalize(stmt);
// Anything there?
return (src == SQLITE_ROW);
}
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
const char* keyName, const char* keyData,
const char* valueName, unsigned &valueData)
{
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
char query[stringSize];
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
// Prepare the statement.
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
// Read the result.
int src = sqlite3_run_query(DB,stmt);
bool retVal = false;
if (src == SQLITE_ROW) {
valueData = (unsigned)sqlite3_column_int64(stmt,0);
retVal = true;
}
sqlite3_finalize(stmt);
return retVal;
}
// This function returns an allocated string that must be free'd by the caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
const char* keyName, const char* keyData,
const char* valueName, char* &valueData)
{
valueData=NULL;
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
char query[stringSize];
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
// Prepare the statement.
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
// Read the result.
int src = sqlite3_run_query(DB,stmt);
bool retVal = false;
if (src == SQLITE_ROW) {
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
if (ptr) valueData = strdup(ptr);
retVal = true;
}
sqlite3_finalize(stmt);
return retVal;
}
// This function returns an allocated string that must be free'd by tha caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
const char* keyName, unsigned keyData,
const char* valueName, char* &valueData)
{
valueData=NULL;
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + 20;
char query[stringSize];
sprintf(query,"SELECT %s FROM %s WHERE %s == %u",valueName,tableName,keyName,keyData);
// Prepare the statement.
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
// Read the result.
int src = sqlite3_run_query(DB,stmt);
bool retVal = false;
if (src == SQLITE_ROW) {
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
if (ptr) valueData = strdup(ptr);
retVal = true;
}
sqlite3_finalize(stmt);
return retVal;
}
bool sqlite3_command(sqlite3* DB, const char* query)
{
// Prepare the statement.
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
// Run the query.
int src = sqlite3_run_query(DB,stmt);
sqlite3_finalize(stmt);
return src==SQLITE_DONE;
}

View File

@@ -1,29 +0,0 @@
#ifndef SQLITE3UTIL_H
#define SQLITE3UTIL_H
#include <sqlite3.h>
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query);
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt);
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
const char* keyName, const char* keyData,
const char* valueName, unsigned &valueData);
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
const char* keyName, const char* keyData,
const char* valueName, char* &valueData);
// This function returns an allocated string that must be free'd by the caller.
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
const char* keyName, unsigned keyData,
const char* valueName, char* &valueData);
bool sqlite3_exists(sqlite3* DB, const char* tableName,
const char* keyName, const char* keyData);
/** Run a query, ignoring the result; return true on success. */
bool sqlite3_command(sqlite3* DB, const char* query);
#endif

336
CommonLibs/trx_rate_ctr.cpp Normal file
View File

@@ -0,0 +1,336 @@
/*
* Copyright (C) 2019 sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* See the COPYING file in the main directory for details.
*/
/*
* rate_ctr API uses several osmocom select loop features, and as a result,
* calls to it must be done through the main thread (the one running the osmocom
* loop in osmo-trx).
* Since read/write from/to SDR is done in separate threads (even read and write
* each use a different thread), we must use some sort of message passing system
* between main thread feeding rate_ctr structures and the Rx/Tx threads
* generating the events.
* The idea is that upon read/write issues, lower layers (SDR APIs) provide us with
* underrun/overrun/droppedPackets information, and in that case we pass that up
* the stack through signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> with signal_cb
* being a pointer to a "struct device_counters" structure, which contains
* device (implementation agnostic) statful counters for different kind of
* statistics.
* That signal is processed here in device_sig_cb, where a copy of the "struct
* device_counters" structure is held and the main thread is instructed through
* a timerfd to update rate_ctr APIs against this copy. All this is done inside
* a mutex to avoid different race conditions (between Rx andTx threads, and
* between Rx/Tx and main thread). For the same reason, callers of signal
* <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> (device_sig_cb), that is Rx/Tx threads,
* must do so with PTHREAD_CANCEL_DISABLE, in order to avoid possible deadlocks
* in case the main thread decides to cancel other threads due to a shutdown
* operation (fi SIGKILL received)
*/
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <arpa/inet.h>
extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/timer.h>
#include "osmo_signal.h"
#include "trx_vty.h"
#include "trx_rate_ctr.h"
}
#include "Threads.h"
#include "Logger.h"
/* Used in ctrs_pending, when set it means that channel slot contains unused
(non-pending) counter data */
#define PENDING_CHAN_NONE SIZE_MAX
static void *trx_rate_ctr_ctx;
static struct rate_ctr_group** rate_ctrs;
static struct device_counters* ctrs_pending;
static size_t chan_len;
static struct osmo_fd rate_ctr_timerfd;
static Mutex rate_ctr_mutex;
struct osmo_timer_list threshold_timer;
static LLIST_HEAD(threshold_list);
static int threshold_timer_sched_secs;
static bool threshold_initied;
const struct value_string rate_ctr_intv[] = {
{ RATE_CTR_INTV_SEC, "per-second" },
{ RATE_CTR_INTV_MIN, "per-minute" },
{ RATE_CTR_INTV_HOUR, "per-hour" },
{ RATE_CTR_INTV_DAY, "per-day" },
{ 0, NULL }
};
const struct value_string trx_chan_ctr_names[] = {
{ TRX_CTR_RX_OVERRUNS, "rx_overruns" },
{ TRX_CTR_TX_UNDERRUNS, "tx_underruns" },
{ TRX_CTR_RX_DROP_EV, "rx_drop_events" },
{ TRX_CTR_RX_DROP_SMPL, "rx_drop_samples" },
{ TRX_CTR_TX_DROP_EV, "tx_drop_events" },
{ TRX_CTR_TX_DROP_SMPL, "tx_drop_samples" },
{ 0, NULL }
};
static const struct rate_ctr_desc trx_chan_ctr_desc[] = {
[TRX_CTR_RX_OVERRUNS] = { "device:rx_overruns", "Number of Rx overruns in FIFO queue" },
[TRX_CTR_TX_UNDERRUNS] = { "device:tx_underruns", "Number of Tx underruns in FIFO queue" },
[TRX_CTR_RX_DROP_EV] = { "device:rx_drop_events", "Number of times Rx samples were dropped by HW" },
[TRX_CTR_RX_DROP_SMPL] = { "device:rx_drop_samples", "Number of Rx samples dropped by HW" },
[TRX_CTR_TX_DROP_EV] = { "device:tx_drop_events", "Number of times Tx samples were dropped by HW" },
[TRX_CTR_TX_DROP_SMPL] = { "device:tx_drop_samples", "Number of Tx samples dropped by HW" }
};
static const struct rate_ctr_group_desc trx_chan_ctr_group_desc = {
.group_name_prefix = "trx:chan",
.group_description = "osmo-trx statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
.num_ctr = ARRAY_SIZE(trx_chan_ctr_desc),
.ctr_desc = trx_chan_ctr_desc,
};
static int rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) {
size_t chan;
struct rate_ctr *ctr;
LOGC(DMAIN, NOTICE) << "Main thread is updating counters";
rate_ctr_mutex.lock();
for (chan = 0; chan < chan_len; chan++) {
if (ctrs_pending[chan].chan == PENDING_CHAN_NONE)
continue;
LOGCHAN(chan, DMAIN, INFO) << "rate_ctr update";
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_OVERRUNS];
rate_ctr_add(ctr, ctrs_pending[chan].rx_overruns - ctr->current);
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_TX_UNDERRUNS];
rate_ctr_add(ctr, ctrs_pending[chan].tx_underruns - ctr->current);
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_DROP_EV];
rate_ctr_add(ctr, ctrs_pending[chan].rx_dropped_events - ctr->current);
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_DROP_SMPL];
rate_ctr_add(ctr, ctrs_pending[chan].rx_dropped_samples - ctr->current);
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_TX_DROP_EV];
rate_ctr_add(ctr, ctrs_pending[chan].tx_dropped_events - ctr->current);
ctr = &rate_ctrs[chan]->ctr[TRX_CTR_TX_DROP_SMPL];
rate_ctr_add(ctr, ctrs_pending[chan].tx_dropped_samples - ctr->current);
/* Mark as done */
ctrs_pending[chan].chan = PENDING_CHAN_NONE;
}
if (osmo_timerfd_disable(&rate_ctr_timerfd) < 0)
LOGC(DMAIN, ERROR) << "Failed to disable timerfd";
rate_ctr_mutex.unlock();
return 0;
}
/* Callback function to be called every time we receive a signal from DEVICE */
static int device_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct device_counters *ctr;
/* Delay sched around 20 ms, in case we receive several calls from several
* channels batched */
struct timespec next_sched = {.tv_sec = 0, .tv_nsec = 20*1000*1000};
/* no automatic re-trigger */
struct timespec intv_sched = {.tv_sec = 0, .tv_nsec = 0};
switch (signal) {
case S_DEVICE_COUNTER_CHANGE:
ctr = (struct device_counters *)signal_data;
LOGCHAN(ctr->chan, DMAIN, NOTICE) << "Received counter change from radioDevice";
rate_ctr_mutex.lock();
ctrs_pending[ctr->chan] = *ctr;
if (osmo_timerfd_schedule(&rate_ctr_timerfd, &next_sched, &intv_sched) < 0) {
LOGC(DMAIN, ERROR) << "Failed to schedule timerfd: " << errno << " = "<< strerror(errno);
}
rate_ctr_mutex.unlock();
break;
default:
break;
}
return 0;
}
/************************************
* ctr_threshold APIs
************************************/
static const char* ctr_threshold_2_vty_str(struct ctr_threshold *ctr)
{
static char buf[256];
int rc = 0;
rc += snprintf(buf, sizeof(buf), "ctr-error-threshold %s", get_value_string(trx_chan_ctr_names, ctr->ctr_id));
rc += snprintf(buf + rc, sizeof(buf) - rc, " %d %s", ctr->val, get_value_string(rate_ctr_intv, ctr->intv));
return buf;
}
static void threshold_timer_cb(void *data)
{
struct ctr_threshold *ctr_thr;
struct rate_ctr *rate_ctr;
size_t chan;
LOGC(DMAIN, DEBUG) << "threshold_timer_cb fired!";
llist_for_each_entry(ctr_thr, &threshold_list, list) {
for (chan = 0; chan < chan_len; chan++) {
rate_ctr = &rate_ctrs[chan]->ctr[ctr_thr->ctr_id];
LOGCHAN(chan, DMAIN, INFO) << "checking threshold: " << ctr_threshold_2_vty_str(ctr_thr)
<< " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")";
if (rate_ctr->intv[ctr_thr->intv].rate >= ctr_thr->val) {
LOGCHAN(chan, DMAIN, FATAL) << "threshold reached, stopping! " << ctr_threshold_2_vty_str(ctr_thr)
<< " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")";
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
return;
}
}
}
osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0);
}
static size_t ctr_threshold_2_seconds(struct ctr_threshold *ctr)
{
size_t mult = 0;
switch (ctr->intv) {
case RATE_CTR_INTV_SEC:
mult = 1;
break;
case RATE_CTR_INTV_MIN:
mult = 60;
break;
case RATE_CTR_INTV_HOUR:
mult = 60*60;
break;
case RATE_CTR_INTV_DAY:
mult = 60*60*24;
break;
default:
OSMO_ASSERT(false);
}
return mult;
}
static void threshold_timer_update_intv() {
struct ctr_threshold *ctr, *min_ctr;
size_t secs, min_secs;
/* Avoid scheduling timer until itself and other structures are prepared
by trx_rate_ctr_init */
if (!threshold_initied)
return;
if (llist_empty(&threshold_list)) {
if (osmo_timer_pending(&threshold_timer))
osmo_timer_del(&threshold_timer);
return;
}
min_ctr = llist_first_entry(&threshold_list, struct ctr_threshold, list);
min_secs = ctr_threshold_2_seconds(min_ctr);
llist_for_each_entry(ctr, &threshold_list, list) {
secs = ctr_threshold_2_seconds(ctr);
if( min_secs > secs)
min_secs = secs;
}
threshold_timer_sched_secs = OSMO_MAX(min_secs / 2 - 1, 1);
LOGC(DMAIN, INFO) << "New ctr-error-threshold check interval: "
<< threshold_timer_sched_secs << " seconds";
osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0);
}
/* Init rate_ctr subsystem. Expected to be called during process start by main thread before VTY is ready */
void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx)
{
size_t i;
trx_rate_ctr_ctx = ctx;
chan_len = trx_ctx->cfg.num_chans;
ctrs_pending = (struct device_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct device_counters));
rate_ctrs = (struct rate_ctr_group**) talloc_zero_size(ctx, chan_len * sizeof(struct rate_ctr_group*));
for (i = 0; i < chan_len; i++) {
ctrs_pending[i].chan = PENDING_CHAN_NONE;
rate_ctrs[i] = rate_ctr_group_alloc(ctx, &trx_chan_ctr_group_desc, i);
if (!rate_ctrs[i]) {
LOGCHAN(i, DMAIN, ERROR) << "Failed to allocate rate ctr";
exit(1);
}
}
rate_ctr_timerfd.fd = -1;
if (osmo_timerfd_setup(&rate_ctr_timerfd, rate_ctr_timerfd_cb, NULL) < 0) {
LOGC(DMAIN, ERROR) << "Failed to setup timerfd";
exit(1);
}
osmo_signal_register_handler(SS_DEVICE, device_sig_cb, NULL);
/* Now set up threshold checks */
threshold_initied = true;
osmo_timer_setup(&threshold_timer, threshold_timer_cb, NULL);
threshold_timer_update_intv();
}
void trx_rate_ctr_threshold_add(struct ctr_threshold *ctr)
{
struct ctr_threshold *new_ctr;
new_ctr = talloc_zero(trx_rate_ctr_ctx, struct ctr_threshold);
*new_ctr = *ctr;
LOGC(DMAIN, NOTICE) << "Adding new threshold check: " << ctr_threshold_2_vty_str(new_ctr);
llist_add(&new_ctr->list, &threshold_list);
threshold_timer_update_intv();
}
int trx_rate_ctr_threshold_del(struct ctr_threshold *del_ctr)
{
struct ctr_threshold *ctr;
llist_for_each_entry(ctr, &threshold_list, list) {
if (ctr->intv != del_ctr->intv ||
ctr->ctr_id != del_ctr->ctr_id ||
ctr->val != del_ctr->val)
continue;
LOGC(DMAIN, NOTICE) << "Deleting threshold check: " << ctr_threshold_2_vty_str(del_ctr);
llist_del(&ctr->list);
talloc_free(ctr);
threshold_timer_update_intv();
return 0;
}
return -1;
}
void trx_rate_ctr_threshold_write_config(struct vty *vty, char *indent_prefix)
{
struct ctr_threshold *ctr;
llist_for_each_entry(ctr, &threshold_list, list) {
vty_out(vty, "%s%s%s", indent_prefix, ctr_threshold_2_vty_str(ctr), VTY_NEWLINE);
}
}

30
CommonLibs/trx_rate_ctr.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <osmocom/core/rate_ctr.h>
#include <osmocom/vty/command.h>
enum TrxCtr {
TRX_CTR_RX_OVERRUNS,
TRX_CTR_TX_UNDERRUNS,
TRX_CTR_RX_DROP_EV,
TRX_CTR_RX_DROP_SMPL,
TRX_CTR_TX_DROP_EV,
TRX_CTR_TX_DROP_SMPL,
};
struct ctr_threshold {
/*! Linked list of all counter groups in the system */
struct llist_head list;
enum rate_ctr_intv intv;
enum TrxCtr ctr_id;
uint32_t val;
};
extern const struct value_string rate_ctr_intv[];
extern const struct value_string trx_chan_ctr_names[];
struct trx_ctx;
void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx);
void trx_rate_ctr_threshold_add(struct ctr_threshold *ctr);
int trx_rate_ctr_threshold_del(struct ctr_threshold *del_ctr);
void trx_rate_ctr_threshold_write_config(struct vty *vty, char *indent_prefix);

738
CommonLibs/trx_vty.c Normal file
View File

@@ -0,0 +1,738 @@
/*
* Copyright (C) 2018-2019 sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* See the COPYING file in the main directory for details.
*/
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include "trx_rate_ctr.h"
#include "trx_vty.h"
#include "../config.h"
static struct trx_ctx* g_trx_ctx;
const struct value_string clock_ref_names[] = {
{ REF_INTERNAL, "internal" },
{ REF_EXTERNAL, "external" },
{ REF_GPS, "gpsdo" },
{ 0, NULL }
};
const struct value_string filler_names[] = {
{ FILLER_DUMMY, "Dummy bursts (C0 only)" },
{ FILLER_ZERO, "Empty bursts" },
{ FILLER_NORM_RAND, "GMSK Normal Bursts with random payload" },
{ FILLER_EDGE_RAND, "8-PSK Normal Bursts with random payload" },
{ FILLER_ACCESS_RAND, "Access Bursts with random payload" },
{ 0, NULL }
};
static const struct value_string filler_types[] = {
{ FILLER_DUMMY, "dummy" },
{ FILLER_ZERO, "zero" },
{ FILLER_NORM_RAND, "random-nb-gmsk" },
{ FILLER_EDGE_RAND, "random-nb-8psk" },
{ FILLER_ACCESS_RAND, "random-ab" },
{ 0, NULL }
};
struct trx_ctx *trx_from_vty(struct vty *v)
{
/* It can't hurt to force callers to continue to pass the vty instance
* to this function, in case we'd like to retrieve the global
* trx instance from the vty at some point in the future. But
* until then, just return the global pointer, which should have been
* initialized by trx_vty_init().
*/
OSMO_ASSERT(g_trx_ctx);
return g_trx_ctx;
}
enum trx_vty_node {
TRX_NODE = _LAST_OSMOVTY_NODE + 1,
CHAN_NODE,
};
static struct cmd_node trx_node = {
TRX_NODE,
"%s(config-trx)# ",
1,
};
static struct cmd_node chan_node = {
CHAN_NODE,
"%s(config-trx-chan)# ",
1,
};
DEFUN(cfg_trx, cfg_trx_cmd,
"trx",
"Configure the TRX\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (!trx)
return CMD_WARNING;
vty->node = TRX_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
"bind-ip A.B.C.D",
"Set the IP address for the local bind\n"
"IPv4 Address\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
osmo_talloc_replace_string(trx, &trx->cfg.bind_addr, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_remote_ip, cfg_remote_ip_cmd,
"remote-ip A.B.C.D",
"Set the IP address for the remote BTS\n"
"IPv4 Address\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_base_port, cfg_base_port_cmd,
"base-port <1-65535>",
"Set the TRX Base Port\n"
"TRX Base Port\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.base_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_dev_args, cfg_dev_args_cmd,
"dev-args DESC",
"Set the device-specific arguments to pass to the device\n"
"Device-specific arguments\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
osmo_talloc_replace_string(trx, &trx->cfg.dev_args, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
"tx-sps (1|4)",
"Set the Tx Samples-per-Symbol\n"
"Tx Samples-per-Symbol\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.tx_sps = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
"rx-sps (1|4)",
"Set the Rx Samples-per-Symbol\n"
"Rx Samples-per-Symbol\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rx_sps = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
"clock-ref (internal|external|gpsdo)",
"Set the Reference Clock\n"
"Enable internal reference (default)\n"
"Enable external 10 MHz reference\n"
"Enable GPSDO reference\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.clock_ref = get_string_value(clock_ref_names, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd,
"multi-arfcn (disable|enable)",
"Enable multi-ARFCN transceiver (default=disable)\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (strcmp("disable", argv[0]) == 0) {
trx->cfg.multi_arfcn = false;
return CMD_SUCCESS;
}
if (trx->cfg.num_chans > TRX_MCHAN_MAX) {
vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
TRX_MCHAN_MAX, VTY_NEWLINE);
return CMD_WARNING;
}
trx->cfg.multi_arfcn = true;
return CMD_SUCCESS;
}
DEFUN(cfg_offset, cfg_offset_cmd,
"offset FLOAT",
"Set the baseband frequency offset (default=0, auto)\n"
"Baseband Frequency Offset\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.offset = atof(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd,
"rssi-offset FLOAT",
"Set the RSSI to dBm offset in dB (default=0)\n"
"RSSI to dBm offset in dB\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rssi_offset = atof(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
"swap-channels (disable|enable)",
"Swap channels (default=disable)\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (strcmp("disable", argv[0]) == 0) {
trx->cfg.swap_channels = false;
} else if (strcmp("enable", argv[0]) == 0) {
trx->cfg.swap_channels = true;
} else {
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_egprs, cfg_egprs_cmd,
"egprs (disable|enable)",
"Enable EDGE receiver (default=disable)\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (strcmp("disable", argv[0]) == 0) {
trx->cfg.egprs = false;
} else if (strcmp("enable", argv[0]) == 0) {
trx->cfg.egprs = true;
} else {
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_ext_rach, cfg_ext_rach_cmd,
"ext-rach (disable|enable)",
"Enable extended (11-bit) RACH (default=disable)\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (strcmp("disable", argv[0]) == 0)
trx->cfg.ext_rach = false;
if (strcmp("enable", argv[0]) == 0)
trx->cfg.ext_rach = true;
return CMD_SUCCESS;
}
DEFUN(cfg_rt_prio, cfg_rt_prio_cmd,
"rt-prio <1-32>",
"Set the SCHED_RR real-time priority\n"
"Real time priority\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.sched_rr = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_stack_size, cfg_stack_size_cmd,
"stack-size <0-2147483647>",
"Set the stack size per thread in BYTE, 0 = OS default\n"
"Stack size per thread in BYTE\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.stack_size = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_filler, cfg_filler_type_cmd,
"filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)",
"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"
)
{
struct trx_ctx *trx = trx_from_vty(vty);
// trx->cfg.filler is unsigned, so we need an interim int var to detect errors
int type = get_string_value(filler_types, argv[0]);
if (type < 0) {
trx->cfg.filler = FILLER_ZERO;
return CMD_WARNING;
}
trx->cfg.filler = type;
return CMD_SUCCESS;
}
DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
"filler tsc <0-7>",
"Filler burst settings\n"
"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")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rtsc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_test_rach_delay, cfg_filler_rach_delay_cmd,
"filler access-burst-delay <0-68>",
"Filler burst settings\n"
"Set the delay for Access Burst random fillers. Used only with 'random-ab' filler type. (default=0)\n"
"RACH delay in symbols\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rach_delay = atoi(argv[0]);
return CMD_SUCCESS;
}
static int vty_ctr_name_2_id(const char* str) {
size_t i;
for (i = 0; trx_chan_ctr_names[i].str; i++) {
if (strstr(trx_chan_ctr_names[i].str, str)) {
return i;
}
}
return -1;
}
static int vty_intv_name_2_id(const char* str) {
size_t i;
for (i = 0; rate_ctr_intv[i].str; i++) {
if (strcmp(rate_ctr_intv[i].str, str) == 0) {
return i;
}
}
return -1;
}
#define THRESHOLD_ARGS "(rx_overruns|tx_underruns|rx_drop_events|rx_drop_samples|tx_drop_events|tx_drop_samples)"
#define THRESHOLD_STR_VAL(s) "Set threshold value for rate_ctr device:" OSMO_STRINGIFY_VAL(s) "\n"
#define THRESHOLD_STRS \
THRESHOLD_STR_VAL(rx_overruns) \
THRESHOLD_STR_VAL(tx_underruns) \
THRESHOLD_STR_VAL(rx_drop_events) \
THRESHOLD_STR_VAL(rx_drop_samples) \
THRESHOLD_STR_VAL(tx_drop_events) \
THRESHOLD_STR_VAL(tx_drop_samples)
#define INTV_ARGS "(per-second|per-minute|per-hour|per-day)"
#define INTV_STR_VAL(s) "Threshold value sampled " OSMO_STRINGIFY_VAL(s) "\n"
#define INTV_STRS \
INTV_STR_VAL(per-second) \
INTV_STR_VAL(per-minute) \
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)
{
int rc;
struct ctr_threshold ctr;
struct trx_ctx *trx = trx_from_vty(vty);
rc = vty_ctr_name_2_id(argv[0]);
if (rc < 0) {
vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
ctr.ctr_id = (enum TrxCtr)rc;
ctr.val = atoi(argv[1]);
rc = vty_intv_name_2_id(argv[2]);
if (rc < 0) {
vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
argv[0], ctr.val, argv[2], VTY_NEWLINE);
return CMD_WARNING;
}
ctr.intv = (enum rate_ctr_intv) rc;
trx_rate_ctr_threshold_add(&ctr);
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)
{
int rc;
struct ctr_threshold ctr;
struct trx_ctx *trx = trx_from_vty(vty);
rc = vty_ctr_name_2_id(argv[0]);
if (rc < 0) {
vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
ctr.ctr_id = (enum TrxCtr)rc;
ctr.val = atoi(argv[1]);
rc = vty_intv_name_2_id(argv[2]);
if (rc < 0) {
vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
argv[0], ctr.val, argv[2], VTY_NEWLINE);
return CMD_WARNING;
}
ctr.intv = (enum rate_ctr_intv) rc;
if (trx_rate_ctr_threshold_del(&ctr) < 0) {
vty_out(vty, "no ctr-error-threshold: Entry to delete not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_chan, cfg_chan_cmd,
"chan <0-100>",
"Select a channel to configure\n"
"Channel index\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
int idx = atoi(argv[0]);
if (idx >= TRX_CHAN_MAX) {
vty_out(vty, "Chan list full.%s", VTY_NEWLINE);
return CMD_WARNING;
} else if (trx->cfg.multi_arfcn && trx->cfg.num_chans >= TRX_MCHAN_MAX) {
vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
TRX_MCHAN_MAX, VTY_NEWLINE);
return CMD_WARNING;
}
if (trx->cfg.num_chans < idx) { /* Unexisting or creating non-consecutive */
vty_out(vty, "Non-existent or non-consecutive chan %d.%s",
idx, VTY_NEWLINE);
return CMD_WARNING;
} else if (trx->cfg.num_chans == idx) { /* creating it */
trx->cfg.num_chans++;
trx->cfg.chans[idx].trx = trx;
trx->cfg.chans[idx].idx = idx;
}
vty->node = CHAN_NODE;
vty->index = &trx->cfg.chans[idx];
return CMD_SUCCESS;
}
DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd,
"rx-path NAME",
"Set the Rx Path\n"
"Rx Path name\n")
{
struct trx_chan *chan = vty->index;
osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd,
"tx-path NAME",
"Set the Tx Path\n"
"Tx Path name\n")
{
struct trx_chan *chan = vty->index;
osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]);
return CMD_SUCCESS;
}
static int dummy_config_write(struct vty *v)
{
return CMD_SUCCESS;
}
static int config_write_trx(struct vty *vty)
{
struct trx_chan *chan;
int i;
struct trx_ctx *trx = trx_from_vty(vty);
vty_out(vty, "trx%s", VTY_NEWLINE);
if (trx->cfg.bind_addr)
vty_out(vty, " bind-ip %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
if (trx->cfg.remote_addr)
vty_out(vty, " remote-ip %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
if (trx->cfg.base_port != DEFAULT_TRX_PORT)
vty_out(vty, " base-port %u%s", trx->cfg.base_port, VTY_NEWLINE);
if (trx->cfg.dev_args)
vty_out(vty, " dev-args %s%s", trx->cfg.dev_args, VTY_NEWLINE);
if (trx->cfg.tx_sps != DEFAULT_TX_SPS)
vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
if (trx->cfg.rx_sps != DEFAULT_RX_SPS)
vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
if (trx->cfg.clock_ref != REF_INTERNAL)
vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
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);
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);
if (trx->cfg.sched_rr != 0)
vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE);
if (trx->cfg.filler != FILLER_ZERO)
vty_out(vty, " filler type %s%s", get_value_string(filler_types, trx->cfg.filler), VTY_NEWLINE);
if (trx->cfg.rtsc > 0)
vty_out(vty, " filler tsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
if (trx->cfg.rach_delay > 0)
vty_out(vty, " filler access-burst-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
if (trx->cfg.stack_size != 0)
vty_out(vty, " stack-size %u%s", trx->cfg.stack_size, VTY_NEWLINE);
trx_rate_ctr_threshold_write_config(vty, " ");
for (i = 0; i < trx->cfg.num_chans; i++) {
chan = &trx->cfg.chans[i];
vty_out(vty, " chan %u%s", chan->idx, VTY_NEWLINE);
if (chan->rx_path)
vty_out(vty, " rx-path %s%s", chan->rx_path, VTY_NEWLINE);
if (chan->tx_path)
vty_out(vty, " tx-path %s%s", chan->tx_path, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx)
{
struct trx_chan *chan;
int i;
vty_out(vty, "TRX Config:%s", VTY_NEWLINE);
vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE);
vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
vty_out(vty, " Filler Burst Type: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
vty_out(vty, " Filler Burst TSC: %u%s", trx->cfg.rtsc, VTY_NEWLINE);
vty_out(vty, " Filler Burst RACH Delay: %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE);
vty_out(vty, " RSSI to dBm offset: %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
vty_out(vty, " Swap channels: %s%s", trx->cfg.swap_channels ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " EDGE support: %s%s", trx->cfg.egprs ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Extended RACH support: %s%s", trx->cfg.ext_rach ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Real Time Priority: %u (%s)%s", trx->cfg.sched_rr,
trx->cfg.sched_rr ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Stack size per Thread in BYTE (0 = OS default): %u%s", trx->cfg.stack_size, VTY_NEWLINE);
vty_out(vty, " Channels: %u%s", trx->cfg.num_chans, VTY_NEWLINE);
for (i = 0; i < trx->cfg.num_chans; i++) {
chan = &trx->cfg.chans[i];
vty_out(vty, " Channel %u:%s", chan->idx, VTY_NEWLINE);
if (chan->rx_path)
vty_out(vty, " Rx Path: %s%s", chan->rx_path, VTY_NEWLINE);
if (chan->tx_path)
vty_out(vty, " Tx Path: %s%s", chan->tx_path, VTY_NEWLINE);
}
}
DEFUN(show_trx, show_trx_cmd,
"show trx",
SHOW_STR "Display information on the TRX\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx_dump_vty(vty, trx);
return CMD_SUCCESS;
}
static int trx_vty_is_config_node(struct vty *vty, int node)
{
switch (node) {
case TRX_NODE:
case CHAN_NODE:
return 1;
default:
return 0;
}
}
static int trx_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case TRX_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
vty->index_sub = NULL;
break;
case CHAN_NODE:
vty->node = TRX_NODE;
vty->index = NULL;
vty->index_sub = NULL;
break;
default:
vty->node = CONFIG_NODE;
vty->index = NULL;
vty->index_sub = NULL;
}
return vty->node;
}
static const char trx_copyright[] =
"Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
"Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
"Copyright (C) 2013-2019 Fairwaves, Inc.\r\n"
"Copyright (C) 2015 Ettus Research LLC\r\n"
"Copyright (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
struct vty_app_info g_vty_info = {
.name = "OsmoTRX",
.version = PACKAGE_VERSION,
.copyright = trx_copyright,
.go_parent_cb = trx_vty_go_parent,
.is_config_node = trx_vty_is_config_node,
};
struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx)
{
struct trx_ctx * trx = talloc_zero(talloc_ctx, struct trx_ctx);
trx->cfg.bind_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
trx->cfg.remote_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
trx->cfg.base_port = DEFAULT_TRX_PORT;
trx->cfg.tx_sps = DEFAULT_TX_SPS;
trx->cfg.rx_sps = DEFAULT_RX_SPS;
trx->cfg.filler = FILLER_ZERO;
return trx;
}
int trx_vty_init(struct trx_ctx* trx)
{
g_trx_ctx = trx;
install_element_ve(&show_trx_cmd);
install_element(CONFIG_NODE, &cfg_trx_cmd);
install_node(&trx_node, config_write_trx);
install_element(TRX_NODE, &cfg_bind_ip_cmd);
install_element(TRX_NODE, &cfg_remote_ip_cmd);
install_element(TRX_NODE, &cfg_base_port_cmd);
install_element(TRX_NODE, &cfg_dev_args_cmd);
install_element(TRX_NODE, &cfg_tx_sps_cmd);
install_element(TRX_NODE, &cfg_rx_sps_cmd);
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_rssi_offset_cmd);
install_element(TRX_NODE, &cfg_swap_channels_cmd);
install_element(TRX_NODE, &cfg_egprs_cmd);
install_element(TRX_NODE, &cfg_ext_rach_cmd);
install_element(TRX_NODE, &cfg_rt_prio_cmd);
install_element(TRX_NODE, &cfg_filler_type_cmd);
install_element(TRX_NODE, &cfg_filler_tsc_cmd);
install_element(TRX_NODE, &cfg_filler_rach_delay_cmd);
install_element(TRX_NODE, &cfg_ctr_error_threshold_cmd);
install_element(TRX_NODE, &cfg_no_ctr_error_threshold_cmd);
install_element(TRX_NODE, &cfg_stack_size_cmd);
install_element(TRX_NODE, &cfg_chan_cmd);
install_node(&chan_node, dummy_config_write);
install_element(CHAN_NODE, &cfg_chan_rx_path_cmd);
install_element(CHAN_NODE, &cfg_chan_tx_path_cmd);
logging_vty_add_deprecated_subsys(g_trx_ctx, "lms");
return 0;
}

73
CommonLibs/trx_vty.h Normal file
View File

@@ -0,0 +1,73 @@
#pragma once
#include <osmocom/vty/command.h>
#include "config_defs.h"
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
/* Samples-per-symbol for downlink path
* 4 - Uses precision modulator (more computation, less distortion)
* 1 - Uses minimized modulator (less computation, more distortion)
*
* Other values are invalid. Receive path (uplink) is always
* downsampled to 1 sps. Default to 4 sps for all cases.
*/
#define DEFAULT_TX_SPS 4
/*
* Samples-per-symbol for uplink (receiver) path
* Do not modify this value. EDGE configures 4 sps automatically on
* B200/B210 devices only. Use of 4 sps on the receive path for other
* configurations is not supported.
*/
#define DEFAULT_RX_SPS 1
/* Default configuration parameters */
#define DEFAULT_TRX_PORT 5700
#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;
};
int trx_vty_init(struct trx_ctx* trx);
struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx);

View File

@@ -2,6 +2,8 @@
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -54,7 +56,10 @@ const BitVector GSM::gEdgeTrainingSequence[] = {
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
const BitVector GSM::gRACHSynchSequenceTS0("01001011011111111001100110101010001111000"); /* GSM, GMSK (default) */
const BitVector GSM::gRACHSynchSequenceTS1("01010100111110001000011000101111001001101"); /* EGPRS, 8-PSK */
const BitVector GSM::gRACHSynchSequenceTS2("11101111001001110101011000001101101110111"); /* EGPRS, GMSK */
// |-head-||---------midamble----------------------||--------------data----------------||t|
const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");

View File

@@ -2,6 +2,8 @@
/*
* Copyright 2008-2011 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
@@ -52,7 +54,9 @@ extern const BitVector gEdgeTrainingSequence[];
extern const BitVector gDummyBurst;
/** Random access burst synch. sequence */
extern const BitVector gRACHSynchSequence;
extern const BitVector gRACHSynchSequenceTS0;
extern const BitVector gRACHSynchSequenceTS1;
extern const BitVector gRACHSynchSequenceTS2;
/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
extern const BitVector gRACHBurst;
@@ -164,7 +168,7 @@ class Time {
unsigned newTN = (mTN + other.mTN) % 8;
uint64_t newFN = (mFN+other.mFN + (mTN + other.mTN)/8) % gHyperframe;
return Time(newFN,newTN);
}
}
int operator-(const Time& other) const
{

View File

@@ -1,33 +0,0 @@
Installation Requirements
OpenBTS compiles to a simple Unix binary and does not require special
installation.
One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to
running configure.
To run OpenBTS, the following should be installed:
Asterisk (http://www.asterisk.org), running SIP on port 5060.
libosip2 (http://www.gnu.org/software/osip/)
libortp (http://freshmeat.net/projects/ortp/)
libusrp (http://gnuradio.org).
This is part of the GNURadio installation.
It is the only part used by OpenBTS.
OpenBTS logs to syslogd as facility LOG_LOCAL7. Please set your /etc/syslog.conf
accordingly.
For information on specific executables, see tests/README.tests and
apps/README.apps.
See http://gnuradio.org/redmine/wiki/gnuradio/OpenBTS/BuildingAndRunning for more
information.

20
LEGAL
View File

@@ -1,5 +1,8 @@
OpenBTS
The OsmoTRX project is direved from OpenBTS transceiver code. See http://openbts.org/ for details.
The related copyrights:
Most parts copyright 2008-2011 Free Software Foundation.
Some parts copyright 2010 Kestrel Signal Processing, Inc.
Some parts copyright 2011 Range Networks, Inc.
@@ -12,17 +15,9 @@ patented technologies. The user of this software is required to take whatever
actions are necessary to avoid patent infringement.
Trademark
"OpenBTS" is a registered trademark of Range Networks, Inc. (Range), a
California corporation. Range reserves the right to control the use of this
trademark. Do not use this trademark in commerce without permission and do not
rebrand OpenBTS under a different trademark.
Telecom and Radio Spectrum Laws
The primary function of OpenBTS is the provision of telecommunications service
The primary function of OsmoTRX is the provision of telecommunications service
over a radio link. This activity is heavily regulated nearly everywhere in
the world. Users of this software are expected to comply with local and national
regulations in the jurisdictions where this sortware is used with radio equipment.
@@ -39,7 +34,7 @@ The legal restrictions listed here are not necessarily exhaustive.
Note to US Government Users
The OpenBTS software applications and associated documentation are "Commercial
The OsmoTRX software applications and associated documentation are "Commercial
Item(s)," as that term is defined at 48 C.F.R. Section 2.101, consisting of
"Commercial Computer Software" and "Commercial Computer Software Documentation,"
as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as
@@ -54,13 +49,12 @@ and AGPLv3.
Note to US Government Contractors
GPL is not compatible with "government purpose rights" (GPR). If you receive
OpenBTS software under a GPL and deliver it under GPR, you will be in violation
OsmoTRX software under a GPL and deliver it under GPR, you will be in violation
of GPL and possibly subject to enforcement actions by the original authors and
copyright holders, including the Free Software Foundation, Inc.
Software Licensing and Distribution
A subset of OpenBTS is distributed publicly under AGPLv3. Range reserves the right to
distribute most of this source code other licenses as well. See the COPYING file
The OsmoTRX is distributed publicly under AGPLv3. See the COPYING file
for more information on the license for this distribution.

View File

@@ -21,24 +21,35 @@
include $(top_srcdir)/Makefile.common
ACLOCAL_AMFLAGS = -I config
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES) $(SQLITE3_CFLAGS)
AM_CXXFLAGS = -Wall -pthread -ldl
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES)
AM_CXXFLAGS = -Wall -pthread
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread
# Order must be preserved
SUBDIRS = \
doc \
CommonLibs \
GSM \
Transceiver52M
Transceiver52M \
contrib \
tests \
utils
EXTRA_DIST = \
autogen.sh \
INSTALLATION \
LEGAL \
COPYING \
README
README.md \
contrib/osmo-trx.spec.in \
debian \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
.PHONY: release
@RELMAKE@
dox: FORCE
doxygen doxconfig

View File

@@ -18,9 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
top_srcdir = $(abs_top_srcdir)
top_builddir = $(abs_top_builddir)
COMMON_INCLUDEDIR = $(top_srcdir)/CommonLibs
GSM_INCLUDEDIR = $(top_srcdir)/GSM
@@ -32,4 +29,10 @@ STD_DEFINES_AND_INCLUDES = \
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
GSM_LA = $(top_builddir)/GSM/libGSM.la
if ARCH_ARM
ARCH_LA = $(top_builddir)/Transceiver52M/arch/arm/libarch.la
else
ARCH_LA = $(top_builddir)/Transceiver52M/arch/x86/libarch.la
endif
MOSTLYCLEANFILES = *~

0
NEWS
View File

116
README
View File

@@ -1,116 +0,0 @@
This is the interface to the transcevier.
Each TRX Manager UDP socket interface represents a single ARFCN.
Each of these per-ARFCN interfaces is a pair of UDP sockets, one for control and one for data.
Give a base port B (5700), the master clock interface is at port P=B.
The TRX-side control interface for C(N) is on port P=B+2N+1 and the data interface is on an odd numbered port P=B+2N+2.
The corresponding core-side interface for every socket is at P+100.
For any given build, the number of ARFCN interfaces can be fixed.
Indications on the Master Clock Interface
The master clock interface is output only (from the radio).
Messages are "indications".
CLOCK gives the current value of the transceiver clock to be used by the core.
This message is sent whenever a trasmission packet arrives that is too late or too early. The clock value is NOT the current transceiver time. It is a time setting the the core should use to give better packet arrival times.
IND CLOCK <totalFrames>
Commands on the Per-ARFCN Control Interface
The per-ARFCN control interface uses a command-reponse protocol.
Commands are NULL-terminated ASCII strings, one per UDP socket.
Each command has a corresponding response.
Every command is of the form:
CMD <cmdtype> [params]
The <cmdtype> is the actual command.
Parameters are optional depending on the commands type.
Every response is of the form:
RSP <cmdtype> <status> [result]
The <status> is 0 for success and a non-zero error code for failure.
Successful responses may include results, depending on the command type.
Power Control
POWEROFF shuts off transmitter power and stops the demodulator.
CMD POWEROFF
RSP POWEROFF <status>
POWERON starts the transmitter and starts the demodulator. Initial power level is very low.
This command fails if the transmitter and receiver are not yet tuned.
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
If the transceiver is already on, it response with success to this command.
CMD POWERON
RSP POWERON <status>
SETPOWER sets output power in dB wrt full scale.
This command fails if the transmitter and receiver are not running.
CMD SETPOWER <dB>
RSP SETPOWER <status> <dB>
ADJPOWER adjusts power by the given dB step. Response returns resulting power level wrt full scale.
This command fails if the transmitter and receiver are not running.
CMD ADJPOWER <dBStep>
RSP ADJPOWER <status> <dBLevel>
Tuning Control
RXTUNE tunes the receiver to a given frequency in kHz.
This command fails if the receiver is already running.
(To re-tune you stop the radio, re-tune, and restart.)
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
CMD RXTUNE <kHz>
RSP RXTUNE <status> <kHz>
TXTUNE tunes the transmitter to a given frequency in kHz.
This command fails if the transmitter is already running.
(To re-tune you stop the radio, re-tune, and restart.)
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
CMD TXTUNE <kHz>
RSP TXTUNE <status> <kHz>
Timeslot Control
SETSLOT sets the format of the uplink timeslots in the ARFCN.
The <timeslot> indicates the timeslot of interest.
The <chantype> indicates the type of channel that occupies the timeslot.
A chantype of zero indicates the timeslot is off.
CMD SETSLOT <timeslot> <chantype>
RSP SETSLOT <status> <timeslot> <chantype>
Messages on the per-ARFCN Data Interface
Messages on the data interface carry one radio burst per UDP message.
Received Data Burst
1 byte timeslot index
4 bytes GSM frame number, big endian
1 byte RSSI in -dBm
2 bytes correlator timing offset in 1/256 symbol steps, 2's-comp, big endian
148 bytes soft symbol estimates, 0 -> definite "0", 255 -> definite "1"
Transmit Data Burst
1 byte timeslot index
4 bytes GSM frame number, big endian
1 byte transmit level wrt ARFCN max, -dB (attenuation)
148 bytes output symbol values, 0 & 1

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
About OsmTRX
============
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"
OsmoTRX is 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.
Homepage
--------
The official homepage of the project is
<https://osmocom.org/projects/osmotrx/wiki/OsmoTRX>
GIT Repository
--------------
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/>
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>.
Mailing List
------------
Discussions related to OsmoTRX are happening on the openbsc@lists.osmocom.org
mailing list, please see <https://lists.osmocom.org/mailman/listinfo/openbsc>
for subscription options and the list archive.
Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
Contributing
------------
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
We us a gerrit based patch submission/review process for managing contributions.
Please see <https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit>
for more details
The current patch queue for OsmoTRX can be seen at
<https://gerrit.osmocom.org/q/project:osmo-trx+status:open>

View File

@@ -1,9 +1,11 @@
/*
* Polyphase channelizer
*
*
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
* Copyright (C) 2015 Ettus Research LLC
*
* 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
@@ -25,12 +27,11 @@
#include <string.h>
#include <cstdio>
#include "Logger.h"
#include "Channelizer.h"
extern "C" {
#include "common/fft.h"
#include "common/convolve.h"
#include "fft.h"
#include "convolve.h"
}
static void deinterleave(const float *in, size_t ilen,
@@ -64,7 +65,7 @@ float *Channelizer::outputBuffer(size_t chan) const
return hInputs[chan];
}
/*
/*
* Implementation based on material found in:
*
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
@@ -79,8 +80,8 @@ bool Channelizer::rotate(const float *in, size_t len)
deinterleave(in, len, hInputs, blockLen, m);
/*
* Convolve through filterbank while applying and saving sample history
/*
* Convolve through filterbank while applying and saving sample history
*/
for (size_t i = 0; i < m; i++) {
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
@@ -89,7 +90,7 @@ bool Channelizer::rotate(const float *in, size_t len)
convolve_real(hInputs[i], blockLen,
subFilters[i], hLen,
hOutputs[i], blockLen,
0, blockLen, 1, 0);
0, blockLen);
}
cxvec_fft(fftHandle);
@@ -97,7 +98,7 @@ bool Channelizer::rotate(const float *in, size_t len)
return true;
}
/* Setup channelizer paramaters */
/* Setup channelizer parameters */
Channelizer::Channelizer(size_t m, size_t blockLen, size_t hLen)
: ChannelizerBase(m, blockLen, hLen)
{

View File

@@ -1,8 +1,10 @@
/*
* Polyphase channelizer
*
*
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
* Copyright (C) 2015 Ettus Research LLC
* Copyright (C) 2015 Ettus Research LLC
*
* 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
@@ -29,7 +31,7 @@
#include "ChannelizerBase.h"
extern "C" {
#include "common/fft.h"
#include "fft.h"
}
static float sinc(float x)
@@ -55,10 +57,10 @@ static void reverse(float *buf, size_t len)
}
}
/*
/*
* Create polyphase filterbank
*
* Implementation based material found in,
* Implementation based material found in,
*
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
* Prentice Hall, 2006."
@@ -70,7 +72,7 @@ bool ChannelizerBase::initFilters()
float sum = 0.0f, scale = 0.0f;
float midpt = (float) (protoLen - 1.0) / 2.0;
/*
/*
* Allocate 'M' partition filters and the temporary prototype
* filter. Coefficients are real only and must be 16-byte memory
* aligned for SSE usage.
@@ -90,7 +92,7 @@ bool ChannelizerBase::initFilters()
memalign(16, hLen * 2 * sizeof(float));
}
/*
/*
* Generate the prototype filter with a Blackman-harris window.
* Scale coefficients with DC filter gain set to unity divided
* by the number of channels.
@@ -110,7 +112,7 @@ bool ChannelizerBase::initFilters()
}
scale = (float) m / sum;
/*
/*
* Populate partition filters and reverse the coefficients per
* convolution requirements.
*/
@@ -174,7 +176,7 @@ bool ChannelizerBase::mapBuffers()
return true;
}
/*
/*
* Setup filterbank internals
*/
bool ChannelizerBase::init()
@@ -222,11 +224,12 @@ bool ChannelizerBase::checkLen(size_t innerLen, size_t outerLen)
return true;
}
/*
* Setup channelizer paramaters
/*
* Setup channelizer parameters
*/
ChannelizerBase::ChannelizerBase(size_t m, size_t blockLen, size_t hLen)
: fftInput(NULL), fftOutput(NULL), fftHandle(NULL)
: subFilters(NULL), hInputs(NULL), hOutputs(NULL), hist(NULL),
fftInput(NULL), fftOutput(NULL), fftHandle(NULL)
{
this->m = m;
this->hLen = hLen;
@@ -239,7 +242,7 @@ ChannelizerBase::~ChannelizerBase()
for (size_t i = 0; i < m; i++) {
free(subFilters[i]);
delete hist[i];
delete[] hist[i];
}
fft_free(fftInput);

View File

@@ -32,7 +32,7 @@ protected:
/* Buffer length validity checking */
bool checkLen(size_t innerLen, size_t outerLen);
public:
/* Initilize channelizer/synthesis filter internals */
/* Initialize channelizer/synthesis filter internals */
bool init();
};

View File

@@ -5,7 +5,7 @@ unlike the built-in complex<> templates, these inline most operations for speed
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

View File

@@ -21,34 +21,13 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/common
AM_CXXFLAGS = -ldl -lpthread
SUBDIRS = arch device
SUBDIRS = arm x86
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/arch/common -I${srcdir}/device/common
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
if ARCH_ARM
ARCH_LA = arm/libarch.la
else
ARCH_LA = x86/libarch.la
endif
if USRP1
AM_CPPFLAGS += $(USRP_CFLAGS)
else
AM_CPPFLAGS += $(UHD_CFLAGS)
endif
rev2dir = $(datadir)/usrp/rev2
rev4dir = $(datadir)/usrp/rev4
dist_rev2_DATA = std_inband.rbf
dist_rev4_DATA = std_inband.rbf
EXTRA_DIST = \
README \
README.Talgorithm
noinst_LTLIBRARIES = libtransceiver.la
noinst_LTLIBRARIES = libtransceiver_common.la
COMMON_SOURCES = \
radioInterface.cpp \
@@ -61,48 +40,75 @@ COMMON_SOURCES = \
ChannelizerBase.cpp \
Channelizer.cpp \
Synthesis.cpp \
common/fft.c
proto_trxd.c
libtransceiver_la_SOURCES = \
libtransceiver_common_la_SOURCES = \
$(COMMON_SOURCES) \
Resampler.cpp \
radioInterfaceResamp.cpp \
radioInterfaceMulti.cpp
bin_PROGRAMS = osmo-trx
noinst_HEADERS = \
Complex.h \
radioInterface.h \
radioVector.h \
radioClock.h \
radioDevice.h \
radioBuffer.h \
sigProcLib.h \
signalVector.h \
Transceiver.h \
USRPDevice.h \
Resampler.h \
ChannelizerBase.h \
Channelizer.h \
Synthesis.h \
common/convolve.h \
common/convert.h \
common/scale.h \
common/mult.h \
common/fft.h
proto_trxd.h
osmo_trx_SOURCES = osmo-trx.cpp
osmo_trx_LDADD = \
libtransceiver.la \
COMMON_LDADD = \
libtransceiver_common.la \
$(ARCH_LA) \
$(GSM_LA) \
$(COMMON_LA) $(SQLITE3_LIBS)
$(COMMON_LA) \
$(FFTWF_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOVTY_LIBS)
if USRP1
libtransceiver_la_SOURCES += USRPDevice.cpp
osmo_trx_LDADD += $(USRP_LIBS)
else
libtransceiver_la_SOURCES += UHDDevice.cpp
osmo_trx_LDADD += $(UHD_LIBS) $(FFTWF_LIBS)
bin_PROGRAMS =
if DEVICE_UHD
bin_PROGRAMS += osmo-trx-uhd
osmo_trx_uhd_SOURCES = osmo-trx.cpp
osmo_trx_uhd_LDADD = \
$(builddir)/device/uhd/libdevice.la \
$(COMMON_LDADD) \
$(UHD_LIBS)
osmo_trx_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
endif
if DEVICE_USRP1
bin_PROGRAMS += osmo-trx-usrp1
osmo_trx_usrp1_SOURCES = osmo-trx.cpp
osmo_trx_usrp1_LDADD = \
$(builddir)/device/usrp1/libdevice.la \
$(COMMON_LDADD) \
$(USRP_LIBS)
osmo_trx_usrp1_CPPFLAGS = $(AM_CPPFLAGS) $(USRP_CFLAGS)
endif
if DEVICE_LMS
bin_PROGRAMS += osmo-trx-lms
osmo_trx_lms_SOURCES = osmo-trx.cpp
osmo_trx_lms_LDADD = \
$(builddir)/device/lms/libdevice.la \
$(COMMON_LDADD) \
$(LMS_LIBS)
osmo_trx_lms_CPPFLAGS = $(AM_CPPFLAGS) $(LMS_CFLAGS)
endif
bin_PROGRAMS += osmo-trx-ipc
osmo_trx_ipc_SOURCES = osmo-trx.cpp
osmo_trx_ipc_LDADD = \
$(builddir)/device/ipc/libdevice.la \
$(COMMON_LDADD) \
$(UHD_LIBS)
osmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)

View File

@@ -1,35 +0,0 @@
The Transceiver
The transceiver consists of three modules:
--- transceiver
--- radioInterface
--- USRPDevice
The USRPDevice module is basically a driver that reads/writes
packets to a USRP with two RFX900 daughterboards, board
A is the Tx chain and board B is the Rx chain.
The radioInterface module is basically an interface b/w the
transceiver and the USRP. It operates the basestation clock
based upon the sample count of received USRP samples. Packets
from the USRP are queued and segmented into GSM bursts that are
passed up to the transceiver; bursts from the transceiver are
passed down to the USRP.
The transceiver basically operates "layer 0" of the GSM stack,
performing the modulation, detection, and demodulation of GSM
bursts. It communicates with the GSM stack via three UDP sockets,
one socket for data, one for control messages, and one socket to
pass clocking information. The transceiver contains a priority
queue to sort to-be-transmitted bursts, and a filler table to fill
in timeslots that do not have bursts in the priority queue. The
transceiver tries to stay ahead of the basestation clock, adapting
its latency when underruns are reported by the radioInterface/USRP.
Received bursts (from the radioInterface) pass through a simple
energy detector, a RACH or midamble correlator, and a DFE-based demodulator.
NOTE: There's a SWLOOPBACK #define statement, where the USRP is replaced
with a memory buffer. In this mode, data written to the USRP is actually stored
in a buffer, and read commands to the USRP simply pull data from this buffer.
This was very useful in early testing, and still may be useful in testing basic
Transceiver and radioInterface functionality.

View File

@@ -2,6 +2,8 @@
* Rational Sample Rate Conversion
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -22,6 +24,7 @@
#include <string.h>
#include <malloc.h>
#include <iostream>
#include <algorithm>
#include "Resampler.h"
@@ -35,6 +38,8 @@ extern "C" {
#define MAX_OUTPUT_LEN 4096
using namespace std;
static float sinc(float x)
{
if (x == 0.0)
@@ -43,37 +48,24 @@ static float sinc(float x)
return sin(M_PI * x) / (M_PI * x);
}
bool Resampler::initFilters(float bw)
void Resampler::initFilters(float bw)
{
size_t proto_len = p * filt_len;
float *proto, val, cutoff;
float cutoff;
float sum = 0.0f, scale = 0.0f;
float midpt = (float) (proto_len - 1.0) / 2.0;
/*
/*
* Allocate partition filters and the temporary prototype filter
* according to numerator of the rational rate. Coefficients are
* real only and must be 16-byte memory aligned for SSE usage.
*/
proto = new float[proto_len];
if (!proto)
return false;
auto proto = vector<float>(p * filt_len);
for (auto &part : partitions)
part = (complex<float> *) memalign(16, filt_len * sizeof(complex<float>));
partitions = (float **) malloc(sizeof(float *) * p);
if (!partitions) {
delete[] proto;
return false;
}
for (size_t i = 0; i < p; i++) {
partitions[i] = (float *)
memalign(16, filt_len * 2 * sizeof(float));
}
/*
/*
* Generate the prototype filter with a Blackman-harris window.
* Scale coefficients with DC filter gain set to unity divided
* by the number of filter partitions.
* by the number of filter partitions.
*/
float a0 = 0.35875;
float a1 = 0.48829;
@@ -85,47 +77,26 @@ bool Resampler::initFilters(float bw)
else
cutoff = (float) q;
for (size_t i = 0; i < proto_len; i++) {
float midpt = (proto.size() - 1) / 2.0;
for (size_t i = 0; i < proto.size(); i++) {
proto[i] = sinc(((float) i - midpt) / cutoff * bw);
proto[i] *= a0 -
a1 * cos(2 * M_PI * i / (proto_len - 1)) +
a2 * cos(4 * M_PI * i / (proto_len - 1)) -
a3 * cos(6 * M_PI * i / (proto_len - 1));
a1 * cos(2 * M_PI * i / (proto.size() - 1)) +
a2 * cos(4 * M_PI * i / (proto.size() - 1)) -
a3 * cos(6 * M_PI * i / (proto.size() - 1));
sum += proto[i];
}
scale = p / sum;
/* Populate filter partitions from the prototype filter */
for (size_t i = 0; i < filt_len; i++) {
for (size_t n = 0; n < p; n++) {
partitions[n][2 * i + 0] = proto[i * p + n] * scale;
partitions[n][2 * i + 1] = 0.0f;
}
for (size_t n = 0; n < p; n++)
partitions[n][i] = complex<float>(proto[i * p + n] * scale);
}
/* For convolution, we store the filter taps in reverse */
for (size_t n = 0; n < p; n++) {
for (size_t i = 0; i < filt_len / 2; i++) {
val = partitions[n][2 * i];
partitions[n][2 * i] = partitions[n][2 * (filt_len - 1 - i)];
partitions[n][2 * (filt_len - 1 - i)] = val;
}
}
delete[] proto;
return true;
}
void Resampler::releaseFilters()
{
if (partitions) {
for (size_t i = 0; i < p; i++)
free(partitions[i]);
}
free(partitions);
partitions = NULL;
/* Store filter taps in reverse */
for (auto &part : partitions)
reverse(&part[0], &part[filt_len]);
}
static bool check_vec_len(int in_len, int out_len, int p, int q)
@@ -159,14 +130,6 @@ static bool check_vec_len(int in_len, int out_len, int p, int q)
return true;
}
void Resampler::computePath()
{
for (int i = 0; i < MAX_OUTPUT_LEN; i++) {
in_index[i] = (q * i) / p;
out_path[i] = (q * i) % p;
}
}
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
{
int n, path;
@@ -176,13 +139,13 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
/* Generate output from precomputed input/output paths */
for (size_t i = 0; i < out_len; i++) {
n = in_index[i];
path = out_path[i];
n = in_index[i];
path = out_path[i];
convolve_real(in, in_len,
partitions[path], filt_len,
&out[2 * i], out_len - i,
n, 1, 1, 0);
reinterpret_cast<float *>(partitions[path]),
filt_len, &out[2 * i], out_len - i,
n, 1);
}
return out_len;
@@ -190,14 +153,18 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
bool Resampler::init(float bw)
{
if (p == 0 || q == 0 || filt_len == 0) return false;
/* Filterbank filter internals */
if (!initFilters(bw))
return false;
initFilters(bw);
/* Precompute filterbank paths */
in_index = new size_t[MAX_OUTPUT_LEN];
out_path = new size_t[MAX_OUTPUT_LEN];
computePath();
int i = 0;
for (auto &index : in_index)
index = (q * i++) / p;
i = 0;
for (auto &path : out_path)
path = (q * i++) % p;
return true;
}
@@ -208,7 +175,7 @@ size_t Resampler::len()
}
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
: in_index(NULL), out_path(NULL), partitions(NULL)
: in_index(MAX_OUTPUT_LEN), out_path(MAX_OUTPUT_LEN), partitions(p)
{
this->p = p;
this->q = q;
@@ -217,8 +184,6 @@ Resampler::Resampler(size_t p, size_t q, size_t filt_len)
Resampler::~Resampler()
{
releaseFilters();
delete in_index;
delete out_path;
for (auto &part : partitions)
free(part);
}

View File

@@ -2,6 +2,8 @@
* Rational Sample Rate Conversion
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -20,22 +22,25 @@
#ifndef _RESAMPLER_H_
#define _RESAMPLER_H_
#include <vector>
#include <complex>
class Resampler {
public:
/* Constructor for rational sample rate conversion
* @param p numerator of resampling ratio
* @param q denominator of resampling ratio
* @param filt_len length of each polyphase subfilter
* @param filt_len length of each polyphase subfilter
*/
Resampler(size_t p, size_t q, size_t filt_len = 16);
~Resampler();
/* Initilize resampler filterbank.
/* Initialize resampler filterbank.
* @param bw bandwidth factor on filter generation (pre-window)
* @return false on error, zero otherwise
*
* Automatic setting is to compute the filter to prevent aliasing with
* a Blackman-Harris window. Adjustment is made through a bandwith
* a Blackman-Harris window. Adjustment is made through a bandwidth
* factor to shift the cutoff and/or the constituent filter lengths.
* Calculation of specific rolloff factors or 3-dB cutoff points is
* left as an excersize for the reader.
@@ -55,7 +60,7 @@ public:
int rotate(const float *in, size_t in_len, float *out, size_t out_len);
/* Get filter length
* @return number of taps in each filter partition
* @return number of taps in each filter partition
*/
size_t len();
@@ -63,14 +68,11 @@ private:
size_t p;
size_t q;
size_t filt_len;
size_t *in_index;
size_t *out_path;
std::vector<size_t> in_index;
std::vector<size_t> out_path;
std::vector<std::complex<float> *> partitions;
float **partitions;
bool initFilters(float bw);
void releaseFilters();
void computePath();
void initFilters(float bw);
};
#endif /* _RESAMPLER_H_ */

View File

@@ -1,9 +1,11 @@
/*
* Polyphase synthesis filter
*
*
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
* Copyright (C) 2015 Ettus Research LLC
*
* 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
@@ -24,13 +26,13 @@
#include <assert.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include "Logger.h"
#include "Synthesis.h"
extern "C" {
#include "common/fft.h"
#include "common/convolve.h"
#include "fft.h"
#include "convolve.h"
}
static void interleave(float **in, size_t ilen,
@@ -74,7 +76,7 @@ bool Synthesis::resetBuffer(size_t chan)
return true;
}
/*
/*
* Implementation based on material found in:
*
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
@@ -92,8 +94,8 @@ bool Synthesis::rotate(float *out, size_t len)
cxvec_fft(fftHandle);
/*
* Convolve through filterbank while applying and saving sample history
/*
* Convolve through filterbank while applying and saving sample history
*/
for (size_t i = 0; i < m; i++) {
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
@@ -102,7 +104,7 @@ bool Synthesis::rotate(float *out, size_t len)
convolve_real(hInputs[i], blockLen,
subFilters[i], hLen,
hOutputs[i], blockLen,
0, blockLen, 1, 0);
0, blockLen);
}
/* Interleave into output vector */

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: GPL-3.0+
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
*
@@ -25,27 +27,24 @@
#include "radioInterface.h"
#include "Interthread.h"
#include "GSMCommon.h"
#include "Sockets.h"
#include <sys/types.h>
#include <sys/socket.h>
extern "C" {
#include <osmocom/core/signal.h>
#include <osmocom/core/select.h>
#include "config_defs.h"
}
class Transceiver;
extern Transceiver *transceiver;
/** Channel descriptor for transceiver object and channel number pair */
struct TransceiverChannel {
TransceiverChannel(Transceiver *trx, int num)
{
this->trx = trx;
this->num = num;
}
~TransceiverChannel()
{
}
Transceiver *trx;
size_t num;
struct TrxChanThParams {
Transceiver *trx;
size_t num;
};
/** Internal transceiver state variables */
@@ -54,7 +53,7 @@ struct TransceiverState {
~TransceiverState();
/* Initialize a multiframe slot in the filler table */
bool init(int filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay);
bool init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay);
int chanType[8];
@@ -89,25 +88,28 @@ struct TransceiverState {
/** The Transceiver class, responsible for physical layer of basestation */
class Transceiver {
public:
/** Transceiver constructor
/** Transceiver constructor
@param wBasePort base port number of UDP sockets
@param TRXAddress IP address of the TRX manager, as a string
@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 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,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset);
double wRssiOffset, int stackSize);
/** Destructor */
~Transceiver();
/** Start the control loop */
bool init(int filler, size_t rtsc, unsigned rach_delay, bool edge);
bool init(FillerType filler, size_t rtsc, unsigned rach_delay,
bool edge, bool ext_rach);
/** attach the radioInterface receive FIFO */
bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
@@ -142,21 +144,35 @@ public:
LOOPBACK ///< similar go VII, used in loopback testing
} ChannelCombination;
enum FillerType {
FILLER_DUMMY,
FILLER_ZERO,
FILLER_NORM_RAND,
FILLER_EDGE_RAND,
FILLER_ACCESS_RAND,
};
private:
int mBasePort;
std::string mAddr;
std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
struct ctrl_msg {
char data[101];
ctrl_msg() {};
};
struct ctrl_sock_state {
osmo_fd conn_bfd;
std::deque<ctrl_msg> txmsgqueue;
ctrl_sock_state() {
conn_bfd.fd = -1;
}
~ctrl_sock_state() {
if(conn_bfd.fd >= 0) {
close(conn_bfd.fd);
conn_bfd.fd = -1;
osmo_fd_unregister(&conn_bfd);
}
}
};
int mBasePort;
std::string mLocalAddr;
std::string mRemoteAddr;
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
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts
@@ -164,12 +180,11 @@ private:
std::vector<Thread *> mRxServiceLoopThreads; ///< thread to pull bursts into receive FIFO
Thread *mRxLowerLoopThread; ///< thread to pull bursts into receive FIFO
Thread *mTxLowerLoopThread; ///< thread to push bursts into transmit FIFO
std::vector<Thread *> mControlServiceLoopThreads; ///< thread to process control messages from GSM core
std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
RadioInterface *mRadioInterface; ///< associated radioInterface object
@@ -177,6 +192,7 @@ private:
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,
@@ -189,9 +205,7 @@ private:
void pushRadioVector(GSM::Time &nowTime);
/** Pull and demodulate a burst from the receive FIFO */
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
double &timingOffset, double &noise,
size_t chan = 0);
int pullRadioVector(size_t chan, struct trx_ul_burst_ind *ind);
/** Set modulus for specific timeslot */
void setModulus(size_t timeslot, size_t chan);
@@ -200,14 +214,22 @@ private:
CorrType expectedCorrType(GSM::Time currTime, size_t chan);
/** send messages over the clock socket */
void writeClockInterface(void);
bool writeClockInterface(void);
static int ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags);
int ctrl_sock_write(int chan);
void ctrl_sock_send(ctrl_msg& m, int chan);
/** 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
double mTxFreq; ///< the transmit frequency
double mRxFreq; ///< the receive frequency
@@ -216,63 +238,48 @@ private:
unsigned mMaxExpectedDelayNB; ///< maximum expected time-of-arrival offset in GSM symbols for Normal Bursts
unsigned mWriteBurstToDiskMask; ///< debug: bitmask to indicate which timeslots to dump to disk
std::vector<unsigned> mVersionTRXD; ///< Format version to use for TRXD protocol communication, per channel
std::vector<TransceiverState> mStates;
/** Start and stop I/O threads through the control socket API */
bool start();
void stop();
/** Protect destructor accessable stop call */
/** Protect destructor accessible stop call */
Mutex mLock;
protected:
/** drive lower receive I/O and burst generation */
void driveReceiveRadio();
bool driveReceiveRadio();
/** drive demodulation of GSM bursts */
void driveReceiveFIFO(size_t chan);
bool driveReceiveFIFO(size_t chan);
/** drive transmission of GSM bursts */
void driveTxFIFO();
/** drive handling of control messages from GSM core */
void driveControl(size_t chan);
/**
drive modulation and sorting of GSM bursts from GSM core
@return true if a burst was transferred successfully
*/
bool driveTxPriorityQueue(size_t chan);
friend void *RxUpperLoopAdapter(TransceiverChannel *);
friend void *TxUpperLoopAdapter(TransceiverChannel *);
friend void *RxLowerLoopAdapter(Transceiver *);
friend void *TxLowerLoopAdapter(Transceiver *);
friend void *ControlServiceLoopAdapter(TransceiverChannel *);
friend void *RxUpperLoopAdapter(TrxChanThParams *params);
friend void *TxUpperLoopAdapter(TrxChanThParams *params);
friend void *RxLowerLoopAdapter(Transceiver *transceiver);
friend void *TxLowerLoopAdapter(Transceiver *transceiver);
void reset();
/** set priority on current thread */
void setPriority(float prio = 0.5) { mRadioInterface->setPriority(prio); }
void logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
double rssi, double noise, double toa);
void logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi);
};
void *RxUpperLoopAdapter(TransceiverChannel *);
void *RxUpperLoopAdapter(TrxChanThParams *params);
/** Main drive threads */
void *RxLowerLoopAdapter(Transceiver *);
void *TxLowerLoopAdapter(Transceiver *);
/** control message handler thread loop */
void *ControlServiceLoopAdapter(TransceiverChannel *);
void *RxLowerLoopAdapter(Transceiver *transceiver);
void *TxLowerLoopAdapter(Transceiver *transceiver);
/** transmit queueing thread loop */
void *TxUpperLoopAdapter(TransceiverChannel *);
void *TxUpperLoopAdapter(TrxChanThParams *params);

View File

@@ -0,0 +1,8 @@
include $(top_srcdir)/Makefile.common
SUBDIRS = common
if ARCH_ARM
SUBDIRS += arm
else
SUBDIRS += x86
endif

View File

@@ -1,17 +1,17 @@
if ARCH_ARM
if ARCH_ARM_A15
ARCH_FLAGS = -mfpu=neon-vfpv4
else
ARCH_FLAGS = -mfpu=neon
endif
AM_CFLAGS = -Wall $(ARCH_FLAGS) -std=gnu99 -I../common
AM_CFLAGS = -Wall $(ARCH_FLAGS) -std=gnu99 -I${srcdir}/../common
AM_CCASFLAGS = $(ARCH_FLAGS)
noinst_LTLIBRARIES = libarch.la
libarch_la_LIBADD = $(top_builddir)/Transceiver52M/arch/common/libarch_common.la
libarch_la_SOURCES = \
../common/convolve_base.c \
convert.c \
convert_neon.S \
convolve.c \
@@ -20,4 +20,3 @@ libarch_la_SOURCES = \
scale_neon.S \
mult.c \
mult_neon.S
endif

View File

@@ -2,6 +2,8 @@
* NEON type conversions
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -28,6 +30,9 @@
void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
void neon_convert_si16_ps_4n(float *, const short *, int);
void convert_init(void) {
}
/* 4*N 16-bit signed integer conversion with remainder */
static void neon_convert_si16_ps(float *out,
const short *in,
@@ -54,7 +59,6 @@ static void neon_convert_ps_si16(short *out,
for (int i = 0; i < len % 4; i++)
out[start + i] = (short) (in[start + i] * (*scale));
}
#endif
void convert_float_short(short *out, const float *in, float scale, int len)
{

View File

@@ -2,6 +2,8 @@
* NEON type conversions
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -2,6 +2,8 @@
* NEON Convolution
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -29,17 +31,15 @@
int _base_convolve_real(float *x, int x_len,
float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int _base_convolve_complex(float *x, int x_len,
float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int bounds_check(int x_len, int h_len, int y_len,
int start, int len, int step);
int start, int len);
#ifdef HAVE_NEON
/* Calls into NEON assembler */
@@ -58,7 +58,7 @@ static void neon_conv_cmplx_4n(float *x, float *h, float *y, int h_len, int len)
}
#endif
/* API: Initalize convolve module */
/* API: Initialize convolve module */
void convolve_init(void)
{
/* Stub */
@@ -69,35 +69,32 @@ void convolve_init(void)
int convolve_real(float *x, int x_len,
float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
void (*conv_func)(float *, float *, float *, int) = NULL;
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
#ifdef HAVE_NEON
if (step <= 4) {
switch (h_len) {
case 4:
conv_func = neon_conv_real4;
break;
case 8:
conv_func = neon_conv_real8;
break;
case 12:
conv_func = neon_conv_real12;
break;
case 16:
conv_func = neon_conv_real16;
break;
case 20:
conv_func = neon_conv_real20;
break;
}
switch (h_len) {
case 4:
conv_func = neon_conv_real4;
break;
case 8:
conv_func = neon_conv_real8;
break;
case 12:
conv_func = neon_conv_real12;
break;
case 16:
conv_func = neon_conv_real16;
break;
case 20:
conv_func = neon_conv_real20;
break;
}
#endif
if (conv_func) {
@@ -107,7 +104,7 @@ int convolve_real(float *x, int x_len,
_base_convolve_real(x, x_len,
h, h_len,
y, y_len,
start, len, step, offset);
start, len);
}
return len;
@@ -118,18 +115,17 @@ int convolve_real(float *x, int x_len,
int convolve_complex(float *x, int x_len,
float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
void (*conv_func)(float *, float *, float *, int, int) = NULL;
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
#ifdef HAVE_NEON
if (step <= 4 && !(h_len % 4))
if (!(h_len % 4))
conv_func = neon_conv_cmplx_4n;
#endif
if (conv_func) {
@@ -139,7 +135,7 @@ int convolve_complex(float *x, int x_len,
_base_convolve_complex(x, x_len,
h, h_len,
y, y_len,
start, len, step, offset);
start, len);
}
return len;

View File

@@ -2,6 +2,8 @@
* NEON Convolution
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -92,8 +94,8 @@ neon_conv_real12:
vld2.32 {q8-q9}, [r4], r6
vld2.32 {q10-q11}, [r5], r6
#ifdef HAVE_NEON_FMA
vfma.f32 q1, q6, q0
vfma.f32 q3, q7, q0
vmul.f32 q1, q6, q0
vmul.f32 q3, q7, q0
vfma.f32 q1, q8, q2
vfma.f32 q3, q9, q2
vfma.f32 q1, q10, q4

View File

@@ -2,6 +2,8 @@
* NEON scaling
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -1,7 +1,9 @@
/*
* NEON complex multiplication
* NEON complex multiplication
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -2,6 +2,8 @@
* NEON scaling
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -2,6 +2,8 @@
* ARM NEON Scaling
* Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either

View File

@@ -0,0 +1,15 @@
AM_CFLAGS = -Wall -std=gnu99
noinst_LTLIBRARIES = libarch_common.la
noinst_HEADERS = \
convolve.h \
convert.h \
scale.h \
mult.h \
fft.h
libarch_common_la_SOURCES = \
convolve_base.c \
convert_base.c \
fft.c

View File

@@ -2,6 +2,8 @@
* Conversion
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -31,4 +33,3 @@ void base_convert_short_float(float *out, const short *in, int len)
for (int i = 0; i < len; i++)
out[i] = in[i];
}

View File

@@ -1,31 +1,27 @@
#ifndef _CONVOLVE_H_
#define _CONVOLVE_H_
void *convolve_h_alloc(int num);
void *convolve_h_alloc(size_t num);
int convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int base_convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int base_convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
void convolve_init(void);

View File

@@ -2,6 +2,8 @@
* Convolution
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
*
* SPDX-License-Identifier: LGPL-2.1+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -41,17 +43,17 @@ static void mac_cmplx(const float *x, const float *h, float *y)
/* Base vector complex-complex multiply and accumulate */
static void mac_real_vec_n(const float *x, const float *h, float *y,
int len, int step, int offset)
int len)
{
for (int i = offset; i < len; i += step)
for (int i=0; i<len; i++)
mac_real(&x[2 * i], &h[2 * i], y);
}
/* Base vector complex-complex multiply and accumulate */
static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
int len, int step, int offset)
int len)
{
for (int i = offset; i < len; i += step)
for (int i=0; i<len; i++)
mac_cmplx(&x[2 * i], &h[2 * i], y);
}
@@ -59,14 +61,12 @@ static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
int _base_convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
for (int i = 0; i < len; i++) {
mac_real_vec_n(&x[2 * (i - (h_len - 1) + start)],
h,
&y[2 * i], h_len,
step, offset);
&y[2 * i], h_len);
}
return len;
@@ -76,14 +76,13 @@ int _base_convolve_real(const float *x, int x_len,
int _base_convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
for (int i = 0; i < len; i++) {
mac_cmplx_vec_n(&x[2 * (i - (h_len - 1) + start)],
h,
&y[2 * i],
h_len, step, offset);
h_len);
}
return len;
@@ -91,10 +90,10 @@ int _base_convolve_complex(const float *x, int x_len,
/* Buffer validity checks */
int bounds_check(int x_len, int h_len, int y_len,
int start, int len, int step)
int start, int len)
{
if ((x_len < 1) || (h_len < 1) ||
(y_len < 1) || (len < 1) || (step < 1)) {
(y_len < 1) || (len < 1)) {
fprintf(stderr, "Convolve: Invalid input\n");
return -1;
}
@@ -113,10 +112,9 @@ int bounds_check(int x_len, int h_len, int y_len,
int base_convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
@@ -124,17 +122,16 @@ int base_convolve_real(const float *x, int x_len,
return _base_convolve_real(x, x_len,
h, h_len,
y, y_len,
start, len, step, offset);
start, len);
}
/* API: Non-aligned (no SSE) complex-complex */
int base_convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset)
int start, int len)
{
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
@@ -142,11 +139,11 @@ int base_convolve_complex(const float *x, int x_len,
return _base_convolve_complex(x, x_len,
h, h_len,
y, y_len,
start, len, step, offset);
start, len);
}
/* Aligned filter tap allocation */
void *convolve_h_alloc(int len)
void *convolve_h_alloc(size_t len)
{
#ifdef HAVE_SSE3
return memalign(16, len * 2 * sizeof(float));

View File

@@ -1,18 +1,20 @@
/*
* Fast Fourier transform
* Fast Fourier transform
*
* Copyright (C) 2012 Tom Tsou <tom@tsou.cc>
*
*
* SPDX-License-Identifier: LGPL-2.1+
*
* 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.
@@ -32,9 +34,9 @@ struct fft_hdl {
fftwf_plan fft_plan;
};
/*! \brief Initialize FFT backend
/*! \brief Initialize FFT backend
* \param[in] reverse FFT direction
* \param[in] m FFT length
* \param[in] m FFT length
* \param[in] istride input stride count
* \param[in] ostride output stride count
* \param[in] in input buffer (FFTW aligned)
@@ -92,7 +94,7 @@ void fft_free(void *ptr)
free(ptr);
}
/*! \brief Free FFT backend resources
/*! \brief Free FFT backend resources
*/
void free_fft(struct fft_hdl *hdl)
{
@@ -101,7 +103,7 @@ void free_fft(struct fft_hdl *hdl)
}
/*! \brief Run multiple DFT operations with the initialized plan
* \param[in] hdl handle to an intitialized fft struct
* \param[in] hdl handle to an initialized fft struct
*
* Input and output buffers are configured with init_fft().
*/

View File

@@ -1,11 +1,15 @@
if !ARCH_ARM
AM_CFLAGS = -Wall -std=gnu99 -I${srcdir}/../common
noinst_LTLIBRARIES = libarch.la
noinst_LTLIBRARIES += libarch_sse_3.la
noinst_LTLIBRARIES += libarch_sse_4_1.la
libarch_la_LIBADD =
noinst_HEADERS = \
convert_sse_3.h \
convert_sse_4_1.h \
convolve_sse_3.h
libarch_la_LIBADD = $(top_builddir)/Transceiver52M/arch/common/libarch_common.la
# SSE 3 specific code
if HAVE_SSE3
@@ -25,8 +29,5 @@ libarch_la_LIBADD += libarch_sse_4_1.la
endif
libarch_la_SOURCES = \
../common/convolve_base.c \
../common/convert_base.c \
convert.c \
convolve.c
endif

View File

@@ -27,7 +27,7 @@
#include "config.h"
#endif
/* Architecture dependant function pointers */
/* Architecture dependent function pointers */
struct convert_cpu_context {
void (*convert_si16_ps_16n) (float *, const short *, int);
void (*convert_si16_ps) (float *, const short *, int);

View File

@@ -27,28 +27,28 @@
#include "config.h"
#endif
/* Architecture dependant function pointers */
/* Architecture dependent function pointers */
struct convolve_cpu_context {
void (*conv_cmplx_4n) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_cmplx_8n) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_cmplx) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real4) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real8) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real12) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real16) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real20) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real4n) (const float *, int, const float *, int, float *,
int, int, int, int, int);
int, int, int);
void (*conv_real) (const float *, int, const float *, int, float *, int,
int, int, int, int);
int, int);
};
static struct convolve_cpu_context c;
@@ -56,19 +56,17 @@ static struct convolve_cpu_context c;
int _base_convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int _base_convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len,
int step, int offset);
int start, int len);
int bounds_check(int x_len, int h_len, int y_len,
int start, int len, int step);
int start, int len);
/* API: Initalize convolve module */
/* API: Initialize convolve module */
void convolve_init(void)
{
c.conv_cmplx_4n = (void *)_base_convolve_complex;
@@ -99,46 +97,37 @@ void convolve_init(void)
/* API: Aligned complex-real */
int convolve_real(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len, int start, int len, int step, int offset)
float *y, int y_len, int start, int len)
{
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
if (step <= 4) {
switch (h_len) {
case 4:
c.conv_real4(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
break;
case 8:
c.conv_real8(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
break;
case 12:
c.conv_real12(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
break;
case 16:
c.conv_real16(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
break;
case 20:
c.conv_real20(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
break;
default:
if (!(h_len % 4))
c.conv_real4n(x, x_len, h, h_len, y, y_len,
start, len, step, offset);
else
c.conv_real(x, x_len, h, h_len, y, y_len, start,
len, step, offset);
}
} else
c.conv_real(x, x_len, h, h_len, y, y_len, start, len, step,
offset);
switch (h_len) {
case 4:
c.conv_real4(x, x_len, h, h_len, y, y_len, start, len);
break;
case 8:
c.conv_real8(x, x_len, h, h_len, y, y_len, start, len);
break;
case 12:
c.conv_real12(x, x_len, h, h_len, y, y_len, start, len);
break;
case 16:
c.conv_real16(x, x_len, h, h_len, y, y_len, start, len);
break;
case 20:
c.conv_real20(x, x_len, h, h_len, y, y_len, start, len);
break;
default:
if (!(h_len % 4))
c.conv_real4n(x, x_len, h, h_len, y, y_len,
start, len);
else
c.conv_real(x, x_len, h, h_len, y, y_len, start,
len);
}
return len;
}
@@ -147,26 +136,19 @@ int convolve_real(const float *x, int x_len,
int convolve_complex(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
return -1;
memset(y, 0, len * 2 * sizeof(float));
if (step <= 4) {
if (!(h_len % 8))
c.conv_cmplx_8n(x, x_len, h, h_len, y, y_len, start,
len, step, offset);
else if (!(h_len % 4))
c.conv_cmplx_4n(x, x_len, h, h_len, y, y_len, start,
len, step, offset);
else
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len,
step, offset);
} else
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len, step,
offset);
if (!(h_len % 8))
c.conv_cmplx_8n(x, x_len, h, h_len, y, y_len, start, len);
else if (!(h_len % 4))
c.conv_cmplx_4n(x, x_len, h, h_len, y, y_len, start, len);
else
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len);
return len;
}

View File

@@ -34,12 +34,12 @@
void sse_conv_real4(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* NOTE: The parameter list of this function has to match the parameter
* list of _base_convolve_real() in convolve_base.c. This specific
* implementation, ignores some of the parameters of
* _base_convolve_complex(), which are: x_len, y_len, offset, step */
* _base_convolve_complex(), which are: x_len, y_len. */
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
@@ -75,7 +75,7 @@ void sse_conv_real4(const float *x, int x_len,
void sse_conv_real8(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_real4() */
@@ -126,7 +126,7 @@ void sse_conv_real8(const float *x, int x_len,
void sse_conv_real12(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_real4() */
@@ -192,7 +192,7 @@ void sse_conv_real12(const float *x, int x_len,
void sse_conv_real16(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_real4() */
@@ -271,7 +271,7 @@ void sse_conv_real16(const float *x, int x_len,
void sse_conv_real20(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_real4() */
@@ -361,7 +361,7 @@ void sse_conv_real20(const float *x, int x_len,
void sse_conv_real4n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_real4() */
@@ -408,12 +408,12 @@ void sse_conv_real4n(const float *x, int x_len,
void sse_conv_cmplx_4n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* NOTE: The parameter list of this function has to match the parameter
* list of _base_convolve_complex() in convolve_base.c. This specific
* implementation, ignores some of the parameters of
* _base_convolve_complex(), which are: x_len, y_len, offset, step. */
* _base_convolve_complex(), which are: x_len, y_len. */
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
@@ -466,7 +466,7 @@ void sse_conv_cmplx_4n(const float *x, int x_len,
void sse_conv_cmplx_8n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset)
int start, int len)
{
/* See NOTE in sse_conv_cmplx_4n() */

View File

@@ -23,46 +23,46 @@
void sse_conv_real4(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 8-tap SSE complex-real convolution */
void sse_conv_real8(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 12-tap SSE complex-real convolution */
void sse_conv_real12(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 16-tap SSE complex-real convolution */
void sse_conv_real16(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 20-tap SSE complex-real convolution */
void sse_conv_real20(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 4*N-tap SSE complex-real convolution */
void sse_conv_real4n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 4*N-tap SSE complex-complex convolution */
void sse_conv_cmplx_4n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);
/* 8*N-tap SSE complex-complex convolution */
void sse_conv_cmplx_8n(const float *x, int x_len,
const float *h, int h_len,
float *y, int y_len,
int start, int len, int step, int offset);
int start, int len);

View File

@@ -0,0 +1,19 @@
include $(top_srcdir)/Makefile.common
SUBDIRS = common
#if DEVICE_IPC
SUBDIRS += ipc
#endif
if DEVICE_USRP1
SUBDIRS += usrp1
endif
if DEVICE_UHD
SUBDIRS += uhd
endif
if DEVICE_LMS
SUBDIRS += lms
endif

View File

@@ -0,0 +1,12 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LMS_CFLAGS)
noinst_HEADERS = radioDevice.h smpl_buf.h
noinst_LTLIBRARIES = libdevice_common.la
libdevice_common_la_SOURCES = \
smpl_buf.cpp

View File

@@ -1,7 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
@@ -18,6 +18,14 @@
#include <string>
#include <vector>
#include "GSMCommon.h"
#include "Logger.h"
extern "C" {
#include "config_defs.h"
#include "osmo_signal.h"
}
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -33,7 +41,7 @@ class RadioDevice {
public:
/* Available transport bus types */
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED, TX_WINDOW_LMS1 };
/* Radio interface types */
enum InterfaceType {
@@ -43,14 +51,10 @@ class RadioDevice {
MULTI_ARFCN,
};
enum ReferenceType {
REF_INTERNAL,
REF_EXTERNAL,
REF_GPS,
};
static RadioDevice *make(size_t tx_sps, size_t rx_sps, InterfaceType type,
size_t chans = 1, double offset = 0.0);
size_t chans = 1, double offset = 0.0,
const std::vector<std::string>& tx_paths = std::vector<std::string>(1, ""),
const std::vector<std::string>& rx_paths = std::vector<std::string>(1, ""));
/** Initialize the USRP */
virtual int open(const std::string &args, int ref, bool swap_channels)=0;
@@ -66,9 +70,6 @@ class RadioDevice {
/** Get the Tx window type */
virtual enum TxWindowType getWindowType()=0;
/** Enable thread priority */
virtual void setPriority(float prio = 0.5) = 0;
/**
Read samples from the radio.
@param buf preallocated buf to contain read result
@@ -76,23 +77,20 @@ class RadioDevice {
@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 radio does not have data to transmit, e.g. data not being sent fast enough
@param RSSI The received signal strength of the read result
@return The number of samples actually read
*/
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0,
unsigned *RSSI = 0) = 0;
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0) = 0;
/**
Write samples to the radio.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if radio 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.
@param isControl Set if data is a control packet, e.g. a ping command
@return The number of samples actually written
*/
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp, bool isControl = false) = 0;
TIMESTAMP timestamp) = 0;
/** Update the alignment between the read and write timestamps */
virtual bool updateAlignment(TIMESTAMP timestamp)=0;
@@ -130,18 +128,90 @@ class RadioDevice {
/** sets the transmit chan gain, returns the gain setting **/
virtual double setTxGain(double dB, size_t chan = 0) = 0;
/** get transmit gain */
virtual double getTxGain(size_t chan = 0) = 0;
/** return maximum Tx Gain **/
virtual double maxTxGain(void) = 0;
/** return minimum Tx Gain **/
virtual double minTxGain(void) = 0;
/** sets the RX path to use, returns true if successful and false otherwise */
virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) = 0;
/** return the used RX path */
virtual std::string getRxAntenna(size_t chan = 0) = 0;
/** sets the RX path to use, returns true if successful and false otherwise */
virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) = 0;
/** return the used RX path */
virtual std::string getTxAntenna(size_t chan = 0) = 0;
/** return whether user drives synchronization of Tx/Rx of USRP */
virtual bool requiresRadioAlign() = 0;
/** Minimum latency that the device can achieve */
virtual GSM::Time minLatency() = 0;
/** Return internal status values */
virtual double getTxFreq(size_t chan = 0) = 0;
virtual double getRxFreq(size_t chan = 0) = 0;
virtual double getSampleRate()=0;
virtual double numberRead()=0;
virtual double numberWritten()=0;
protected:
size_t tx_sps, rx_sps;
InterfaceType iface;
size_t chans;
double lo_offset;
std::vector<std::string> tx_paths, rx_paths;
std::vector<struct device_counters> m_ctr;
RadioDevice(size_t tx_sps, size_t rx_sps, InterfaceType type, size_t chan_num, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths):
tx_sps(tx_sps), rx_sps(rx_sps), iface(type), chans(chan_num), lo_offset(offset),
tx_paths(tx_paths), rx_paths(rx_paths)
{
if (iface == MULTI_ARFCN) {
LOGC(DDEV, INFO) << "Multi-ARFCN: "<< chan_num << " logical chans -> 1 physical chans";
chans = 1;
}
m_ctr.resize(chans);
for (size_t i = 0; i < chans; i++) {
memset(&m_ctr[i], 0, sizeof(m_ctr[i]));
m_ctr[i].chan = i;
}
}
bool set_antennas() {
unsigned int i;
for (i = 0; i < tx_paths.size(); i++) {
if (tx_paths[i] == "")
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];
return false;
}
}
for (i = 0; i < rx_paths.size(); i++) {
if (rx_paths[i] == "")
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];
return false;
}
}
LOG(INFO) << "Antennas configured successfully";
return true;
}
};

View File

@@ -0,0 +1,173 @@
/*
* Sample Buffer - Allows reading and writing of timed samples
*
* Copyright 2010,2011 Free Software Foundation, Inc.
* Copyright (C) 2015 Ettus Research LLC
* Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* Author: Tom Tsou <tom.tsou@ettus.com>
*
* 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/>.
* See the COPYING file in the main directory for details.
*/
#include "smpl_buf.h"
#include <inttypes.h>
smpl_buf::smpl_buf(size_t len)
: buf_len(len), time_start(0), time_end(0),
data_start(0), data_end(0)
{
data = new uint32_t[len];
}
smpl_buf::~smpl_buf()
{
delete[] data;
}
ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
{
if (timestamp < time_start)
return ERROR_TIMESTAMP;
else if (timestamp >= time_end)
return 0;
else
return time_end - timestamp;
}
ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
{
int type_sz = 2 * sizeof(short);
// Check for valid read
if (timestamp < time_start)
return ERROR_TIMESTAMP;
if (timestamp >= time_end)
return 0;
if (len >= buf_len)
return ERROR_READ;
// How many samples should be copied
size_t num_smpls = time_end - timestamp;
if (num_smpls > len)
num_smpls = len;
// Starting index
size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
// Read it
if (read_start + num_smpls < buf_len) {
size_t numBytes = len * type_sz;
memcpy(buf, data + read_start, numBytes);
} else {
size_t first_cp = (buf_len - read_start) * type_sz;
size_t second_cp = len * type_sz - first_cp;
memcpy(buf, data + read_start, first_cp);
memcpy((char*) buf + first_cp, data, second_cp);
}
data_start = (read_start + len) % buf_len;
time_start = timestamp + len;
if (time_start > time_end)
return ERROR_READ;
else
return num_smpls;
}
ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
{
int type_sz = 2 * sizeof(short);
// Check for valid write
if ((len == 0) || (len >= buf_len))
return ERROR_WRITE;
if ((timestamp + len) <= time_end)
return ERROR_TIMESTAMP;
if (timestamp < time_end) {
LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="
<< timestamp << " time_end=" << time_end;
// Do not return error here, because it's a rounding error and is not fatal
}
if (timestamp > time_end && time_end != 0) {
LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="
<< timestamp << " time_end=" << time_end;
// Do not return error here, because it's a rounding error and is not fatal
}
// Starting index
size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
// Write it
if ((write_start + len) < buf_len) {
size_t numBytes = len * type_sz;
memcpy(data + write_start, buf, numBytes);
} else {
size_t first_cp = (buf_len - write_start) * type_sz;
size_t second_cp = len * type_sz - first_cp;
memcpy(data + write_start, buf, first_cp);
memcpy(data, (char*) buf + first_cp, second_cp);
}
data_end = (write_start + len) % buf_len;
time_end = timestamp + len;
if (!data_start)
data_start = write_start;
if (((write_start + len) > buf_len) && (data_end > data_start))
return ERROR_OVERFLOW;
else if (time_end <= time_start)
return ERROR_WRITE;
else
return len;
}
std::string smpl_buf::str_status(TIMESTAMP timestamp) const
{
std::ostringstream ost("Sample buffer: ");
ost << "timestamp = " << timestamp;
ost << ", length = " << buf_len;
ost << ", time_start = " << time_start;
ost << ", time_end = " << time_end;
ost << ", data_start = " << data_start;
ost << ", data_end = " << data_end;
return ost.str();
}
std::string smpl_buf::str_code(int code)
{
switch (code) {
case ERROR_TIMESTAMP:
return "Sample buffer: Requested timestamp is not valid";
case ERROR_READ:
return "Sample buffer: Read error";
case ERROR_WRITE:
return "Sample buffer: Write error";
case ERROR_OVERFLOW:
return "Sample buffer: Overrun";
default:
std::stringstream ss;
ss << "Sample buffer: Unknown error " << code;
return ss.str();
}
}

View File

@@ -0,0 +1,89 @@
/*
* Sample Buffer - Allows reading and writing of timed samples
*
* Copyright 2010,2011 Free Software Foundation, Inc.
* Copyright (C) 2015 Ettus Research LLC
* Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* Author: Tom Tsou <tom.tsou@ettus.com>
*
* 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/>.
* See the COPYING file in the main directory for details.
*/
#pragma once
#include <unistd.h>
#include "radioDevice.h"
/*
Sample Buffer - Allows reading and writing of timed samples using osmo-trx
timestamps. Time conversions are handled
internally or accessible through the static convert calls.
*/
class smpl_buf {
public:
/** Sample buffer constructor
@param len number of 32-bit samples the buffer should hold
@param timestamp
*/
smpl_buf(size_t len);
~smpl_buf();
/** Query number of samples available for reading
@param timestamp time of first sample
@return number of available samples or error
*/
ssize_t avail_smpls(TIMESTAMP timestamp) const;
/** Read and write
@param buf pointer to buffer
@param len number of samples desired to read or write
@param timestamp time of first stample
@return number of actual samples read or written or error
*/
ssize_t read(void *buf, size_t len, TIMESTAMP timestamp);
ssize_t write(void *buf, size_t len, TIMESTAMP timestamp);
/** Buffer status string
@return a formatted string describing internal buffer state
*/
std::string str_status(TIMESTAMP timestamp) const;
/** Formatted error string
@param code an error code
@return a formatted error string
*/
static std::string str_code(int code);
enum err_code {
ERROR_TIMESTAMP = -1,
ERROR_READ = -2,
ERROR_WRITE = -3,
ERROR_OVERFLOW = -4
};
private:
uint32_t *data;
size_t buf_len;
TIMESTAMP time_start;
TIMESTAMP time_end;
size_t data_start;
size_t data_end;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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 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.
*/
#ifndef _IPC_DEVICE_H_
#define _IPC_DEVICE_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
extern "C" {
#include <osmocom/core/select.h>
#include <osmocom/core/timer.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>
struct ipc_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 */
};
/** A class to handle a LimeSuite supported device */
class IPCDevice : public RadioDevice {
protected:
struct ipc_sock_state sk_state;
/* FIXME: current limit 8 chans, make dynamic */
struct ipc_sock_state sk_chan_state[8];
uint8_t tmp_state;
char shm_name[SHM_NAME_MAX];
int ipc_shm_connect(const char *shm_name);
void *shm;
struct ipc_shm_region *shm_dec;
std::vector<smpl_buf *> rx_buffers;
double actualSampleRate; ///< the actual USRP sampling rate
bool started; ///< flag indicates LMS has started
bool skipRx; ///< set if LMS is transmit-only.
TIMESTAMP ts_initial, ts_offset;
std::vector<double> tx_gains, rx_gains;
struct ipc_sk_if_info_req current_info_req;
struct ipc_sk_if_info_cnf current_info_cnf;
struct ipc_sk_if_open_cnf current_open_cnf;
std::vector<struct ipc_shm_io *> shm_io_rx_streams;
std::vector<struct ipc_shm_io *> shm_io_tx_streams;
bool do_calib(size_t chan);
bool do_filters(size_t chan);
int get_ant_idx(const std::string &name, bool dir_tx, size_t chan);
virtual 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);
bool do_clock_src_freq(enum ReferenceType ref, double freq);
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);
/** 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 */
virtual int open(const std::string &args, int ref, bool swap_channels) override;
/** Start the LMS */
virtual bool start() override;
/** Stop the LMS */
virtual bool stop() override;
enum TxWindowType getWindowType() override
{
return TX_WINDOW_LMS1;
}
/**
Read samples from the LMS.
@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
@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.
@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 timestamp The timestamp of the first sample of the data buffer.
@return The number of samples actually written
*/
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp = 0xffffffff) override;
/** Update the alignment between the read and write timestamps */
virtual bool updateAlignment(TIMESTAMP timestamp) override;
/** Set the transmitter frequency */
virtual bool setTxFreq(double wFreq, size_t chan = 0) override;
/** Set the receiver frequency */
virtual bool setRxFreq(double wFreq, size_t chan = 0) override;
/** Returns the starting write Timestamp*/
virtual TIMESTAMP initialWriteTimestamp(void) override;
/** Returns the starting read Timestamp*/
virtual TIMESTAMP initialReadTimestamp(void) override;
/** returns the full-scale transmit amplitude **/
virtual double fullScaleInputValue() override
{
return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_rx;
}
/** returns the full-scale receive amplitude **/
virtual double fullScaleOutputValue() override
{
return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_tx;
}
/** sets the receive chan gain, returns the gain setting **/
virtual double setRxGain(double dB, size_t chan = 0) override;
/** get the current receive gain */
virtual double getRxGain(size_t chan = 0) override
{
return rx_gains[chan];
}
/** return maximum Rx Gain **/
virtual double maxRxGain(void) override;
/** return minimum Rx Gain **/
virtual double minRxGain(void) override;
/** sets the transmit chan gain, returns the gain setting **/
virtual double setTxGain(double dB, size_t chan = 0) override;
/** get transmit gain */
virtual double getTxGain(size_t chan = 0) override
{
return tx_gains[chan];
}
/** return maximum Tx Gain **/
virtual double maxTxGain(void) override;
/** return minimum Rx Gain **/
virtual double minTxGain(void) override;
/** sets the RX path to use, returns true if successful and false otherwise */
virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) override;
/* return the used RX path */
virtual std::string getRxAntenna(size_t chan = 0) override;
/** sets the RX path to use, returns true if successful and false otherwise */
virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) override;
/* return the used RX path */
virtual std::string getTxAntenna(size_t chan = 0) override;
/** return whether user drives synchronization of Tx/Rx of USRP */
virtual bool requiresRadioAlign() override;
/** return whether user drives synchronization of Tx/Rx of USRP */
virtual GSM::Time minLatency() override;
/** Return internal status values */
virtual inline double getTxFreq(size_t chan = 0) override
{
return 0;
}
virtual inline double getRxFreq(size_t chan = 0) override
{
return 0;
}
virtual inline double getSampleRate() override
{
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);
};
#endif // _IPC_DEVICE_H_

View File

@@ -0,0 +1,29 @@
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_LDFLAGS = -lpthread -lrt
noinst_HEADERS = IPCDevice.h shm.h ../uhd/UHDDevice.h uhdwrap.h
noinst_LTLIBRARIES = libdevice.la
libdevice_la_SOURCES = ipc-driver-test.c IPCDevice.cpp shm.c ../uhd/UHDDevice.cpp uhdwrap.cpp 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) $(UHD_CFLAGS) -DIPCMAGIC
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_LDADD = \
shm.lo \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOVTY_LIBS)
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

View File

@@ -0,0 +1,467 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define _GNU_SOURCE
#include <pthread.h>
#include <debug.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <getopt.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "shm.h"
#include "ipc_shm.h"
#include "ipc_chan.h"
#include "ipc_sock.h"
#define DEFAULT_SHM_NAME "/osmo-trx-ipc-driver-shm2"
static void *tall_ctx;
struct ipc_sock_state *global_ipc_sock_state;
/* 8 channels are plenty */
struct ipc_sock_state *global_ctrl_socks[8];
struct ipc_shm_io *ios_tx_to_device[8];
struct ipc_shm_io *ios_rx_from_device[8];
void *shm;
void *global_dev;
static struct ipc_shm_region *decoded_region;
/* Debug Areas of the code */
//enum { DMAIN,
//};
static const struct log_info_cat default_categories[] = {
[DMAIN] = {
.name = "DMAIN",
.color = NULL,
.description = "Main generic category",
.loglevel = LOGL_DEBUG,.enabled = 1,
},
[DDEV] = {
.name = "DDEV",
.description = "Device/Driver specific code",
.color = NULL,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
const struct log_info log_infox = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
#ifdef __cplusplus
}
#endif
#include "uhdwrap.h"
volatile int ipc_exit_requested = 0;
static int ipc_shm_setup(const char *shm_name, size_t shm_len)
{
int fd;
int rc;
LOGP(DMAIN, LOGL_NOTICE, "Opening shm path %s\n", shm_name);
if ((fd = shm_open(shm_name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
LOGP(DMAIN, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));
rc = -errno;
goto err_shm_open;
}
LOGP(DMAIN, LOGL_NOTICE, "Truncating %d to size %zu\n", fd, shm_len);
if (ftruncate(fd, shm_len) < 0) {
LOGP(DMAIN, LOGL_ERROR, "ftruncate %d: %s\n", errno, strerror(errno));
rc = -errno;
goto err_mmap;
}
LOGP(DMAIN, LOGL_NOTICE, "mmaping shared memory fd %d\n", fd);
if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
LOGP(DMAIN, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));
rc = -errno;
goto err_mmap;
}
LOGP(DMAIN, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
/* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
close(fd);
return 0;
err_mmap:
shm_unlink(shm_name);
close(fd);
err_shm_open:
return rc;
}
struct msgb *ipc_msgb_alloc(uint8_t msg_type)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
msg = msgb_alloc(sizeof(struct ipc_sk_if) + 1000, "ipc_sock_tx");
if (!msg)
return NULL;
msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);
ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->msg_type = msg_type;
return msg;
}
static int ipc_tx_greeting_cnf(uint8_t req_version)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
msg = ipc_msgb_alloc(IPC_IF_MSG_GREETING_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->u.greeting_cnf.req_version = req_version;
return ipc_sock_send(msg);
}
static int ipc_tx_info_cnf()
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
msg = ipc_msgb_alloc(IPC_IF_MSG_INFO_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_if *)msg->data;
uhdwrap_fill_info_cnf(ipc_prim);
return ipc_sock_send(msg);
}
static int ipc_tx_open_cnf(int rc, uint32_t num_chans, int32_t timingoffset)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
struct ipc_sk_if_open_cnf_chan *chan_info;
unsigned int i;
msg = ipc_msgb_alloc(IPC_IF_MSG_OPEN_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->u.open_cnf.return_code = rc;
ipc_prim->u.open_cnf.path_delay = timingoffset; // 6.18462e-5 * 1625e3 / 6;
OSMO_STRLCPY_ARRAY(ipc_prim->u.open_cnf.shm_name, DEFAULT_SHM_NAME);
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);
/* 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);
chan_info++;
}
return ipc_sock_send(msg);
}
int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req)
{
if (greeting_req->req_version == IPC_SOCK_API_VERSION)
ipc_tx_greeting_cnf(IPC_SOCK_API_VERSION);
else
ipc_tx_greeting_cnf(0);
return 0;
}
int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req)
{
ipc_tx_info_cnf();
return 0;
}
int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)
{
/* calculate size needed */
unsigned int len;
global_dev = uhdwrap_open(open_req);
/* b210 packet size is 2040, but our tx size is 2500, so just do *2 */
int shmbuflen = uhdwrap_get_bufsizerx(global_dev) * 2;
len = ipc_shm_encode_region(NULL, open_req->num_chans, 4, shmbuflen);
/* 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));
/* 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
* 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 */
decoded_region = ipc_shm_decode_region(0, (struct ipc_shm_raw_region *)shm);
for (unsigned int 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);
}
ipc_tx_open_cnf(-rc, open_req->num_chans, uhdwrap_get_timingoffset(global_dev));
return 0;
}
void *uplink_thread(void *x_void_ptr)
{
uint32_t chann = decoded_region->num_chans;
pthread_setname_np(pthread_self(), "uplink rx");
while (!ipc_exit_requested) {
int32_t read = uhdwrap_read(global_dev, chann);
if (read < 0)
return 0;
}
return 0;
}
void *downlink_thread(void *x_void_ptr)
{
int chann = decoded_region->num_chans;
pthread_setname_np(pthread_self(), "downlink tx");
while (!ipc_exit_requested) {
bool underrun;
uhdwrap_write(global_dev, chann, &underrun);
}
return 0;
}
int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
int rc;
/* no per-chan start/stop */
rc = uhdwrap_start(global_dev, chan_nr);
pthread_t rx, tx;
pthread_create(&rx, NULL, uplink_thread, 0);
pthread_create(&tx, NULL, downlink_thread, 0);
msg = ipc_msgb_alloc(IPC_IF_MSG_START_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.start_cnf.return_code = rc ? 0 : -1;
return ipc_chan_sock_send(msg, chan_nr);
}
int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
int rc;
/* no per-chan start/stop */
rc = uhdwrap_stop(global_dev, chan_nr);
msg = ipc_msgb_alloc(IPC_IF_MSG_STOP_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.stop_cnf.return_code = rc ? 0 : -1;
return ipc_chan_sock_send(msg, chan_nr);
}
int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
double rv;
rv = uhdwrap_set_gain(global_dev, req->gain, chan_nr, req->is_tx);
msg = ipc_msgb_alloc(IPC_IF_MSG_SETGAIN_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.set_gain_cnf.is_tx = req->is_tx;
ipc_prim->u.set_gain_cnf.gain = rv;
return ipc_chan_sock_send(msg, chan_nr);
}
int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr)
{
struct msgb *msg;
struct ipc_sk_chan_if *ipc_prim;
bool rv;
rv = uhdwrap_set_freq(global_dev, req->freq, chan_nr, req->is_tx);
msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_CNF);
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
ipc_prim->u.set_freq_cnf.return_code = rv ? 0 : 1;
return ipc_chan_sock_send(msg, chan_nr);
}
int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n)
{
struct ipc_sock_state *state;
struct osmo_fd *bfd;
int rc;
state = talloc_zero(NULL, struct ipc_sock_state);
if (!state)
return -ENOMEM;
*global_state_var = state;
INIT_LLIST_HEAD(&state->upqueue);
state->conn_bfd.fd = -1;
bfd = &state->listen_bfd;
bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND);
if (bfd->fd < 0) {
LOGP(DMAIN, LOGL_ERROR, "Could not create %s unix socket: %s\n", path, strerror(errno));
talloc_free(state);
return -1;
}
bfd->when = BSC_FD_READ;
bfd->cb = sock_callback_fn;
bfd->data = state;
bfd->priv_nr = n;
rc = osmo_fd_register(bfd);
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Could not register listen fd: %d\n", rc);
close(bfd->fd);
talloc_free(state);
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;
}
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"
);
}
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}
};
c = getopt_long(argc, argv, "hn:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_help();
exit(0);
break;
case 'n':
msocknum = atoi(optarg);
break;
default:
exit(2);
break;
}
}
if (argc > optind) {
fprintf(stderr, "Unsupported positional arguments on command line\n");
exit(2);
}
}
#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];
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);
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);
//ipc_sock_close()
return 0;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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.
*/
#pragma once
#include <osmocom/core/select.h>
#include "shm.h"
extern struct ipc_sock_state *global_ipc_sock_state;
/* 8 channels are plenty */
extern struct ipc_sock_state *global_ctrl_socks[8];
extern struct ipc_shm_io *ios_tx_to_device[8];
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 llist_head upqueue; /* queue for sending messages */
};
int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n);
int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req);
int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req);
int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req);
int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);
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);

View File

@@ -0,0 +1,254 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <debug.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "shm.h"
#include "ipc-driver-test.h"
#include "ipc_chan.h"
#include "ipc_sock.h"
static int ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)
{
int rc = 0;
switch (msg_type) {
case IPC_IF_MSG_START_REQ:
rc = ipc_rx_chan_start_req(&ipc_prim->u.start_req, chan_nr);
break;
case IPC_IF_MSG_STOP_REQ:
rc = ipc_rx_chan_stop_req(&ipc_prim->u.stop_req, chan_nr);
break;
case IPC_IF_MSG_SETGAIN_REQ:
rc = ipc_rx_chan_setgain_req(&ipc_prim->u.set_gain_req, chan_nr);
break;
case IPC_IF_MSG_SETFREQ_REQ:
rc = ipc_rx_chan_setfreq_req(&ipc_prim->u.set_freq_req, chan_nr);
break;
default:
LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
rc = -EINVAL;
}
return rc;
}
static int ipc_chan_sock_read(struct osmo_fd *bfd)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
struct ipc_sk_chan_if *ipc_prim;
struct msgb *msg;
int rc;
msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_chan_if *)msg->tail;
rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
if (rc == 0)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
msgb_free(msg);
return 0;
}
goto close;
}
if (rc < (int)sizeof(*ipc_prim)) {
LOGP(DMAIN, LOGL_ERROR,
"Received %d bytes on Unix Socket, but primitive size "
"is %zu, discarding\n",
rc, sizeof(*ipc_prim));
msgb_free(msg);
return 0;
}
rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);
/* as we always synchronously process the message in IPC_rx() and
* its callbacks, we can free the message here. */
msgb_free(msg);
return rc;
close:
msgb_free(msg);
ipc_sock_close(state);
return -1;
}
int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr)
{
struct ipc_sock_state *state = global_ctrl_socks[chan_nr];
struct osmo_fd *conn_bfd;
if (!state)
return -EINVAL;
if (!state) {
LOGP(DMAIN, LOGL_INFO,
"IPC socket not created, "
"dropping message\n");
msgb_free(msg);
return -EINVAL;
}
conn_bfd = &state->conn_bfd;
if (conn_bfd->fd <= 0) {
LOGP(DMAIN, 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;
return 0;
}
static int ipc_chan_sock_write(struct osmo_fd *bfd)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
int rc;
while (!llist_empty(&state->upqueue)) {
struct msgb *msg, *msg2;
struct ipc_sk_chan_if *ipc_prim;
/* peek at the beginning of the queue */
msg = llist_entry(state->upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_chan_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
LOGP(DMAIN, LOGL_ERROR,
"message type (%d) with ZERO "
"bytes!\n",
ipc_prim->msg_type);
goto dontsend;
}
/* try to send it over the socket */
rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
if (rc == 0)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
break;
}
goto close;
}
dontsend:
/* _after_ we send it, we can deueue */
msg2 = msgb_dequeue(&state->upqueue);
assert(msg == msg2);
msgb_free(msg);
}
return 0;
close:
ipc_sock_close(state);
return -1;
}
static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
int rc = 0;
if (flags & BSC_FD_READ)
rc = ipc_chan_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
rc = ipc_chan_sock_write(bfd);
return rc;
}
int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
struct osmo_fd *conn_bfd = &state->conn_bfd;
struct sockaddr_un un_addr;
socklen_t len;
int rc;
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");
return -1;
}
if (conn_bfd->fd >= 0) {
LOGP(DMAIN, 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;
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;
if (osmo_fd_register(conn_bfd) != 0) {
LOGP(DMAIN, LOGL_ERROR,
"Failed to register new connection "
"fd\n");
close(conn_bfd->fd);
conn_bfd->fd = -1;
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
/* send current info */
//IPC_tx_info_ind();
return 0;
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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.
*/
#ifndef IPC_CHAN_H
#define IPC_CHAN_H
#include "shm.h"
#include "ipc-driver-test.h"
int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr);
int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags);
#endif // IPC_CHAN_H

View File

@@ -0,0 +1,204 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Eric Wild <ewild@sysmocom.de>
*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <shm.h>
#include "ipc_shm.h"
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#ifdef __cplusplus
}
#endif
#define SAMPLE_SIZE_BYTE sizeof(uint16_t) * 2
struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s)
{
unsigned int i;
struct ipc_shm_io *r = (struct ipc_shm_io *)malloc(sizeof(struct ipc_shm_io));
r->this_stream = s->raw;
r->buf_ptrs =
(volatile struct ipc_shm_raw_smpl_buf **)malloc(sizeof(struct ipc_shm_raw_smpl_buf *) * s->num_buffers);
/* save actual ptrs */
for (i = 0; i < s->num_buffers; i++)
r->buf_ptrs[i] = s->buffers[i];
r->partial_read_begin_ptr = 0;
return r;
}
struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s)
{
int rv;
pthread_mutexattr_t att;
pthread_condattr_t t1, t2;
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);
}
rv = pthread_mutexattr_setrobust(&att, PTHREAD_MUTEX_ROBUST);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
}
rv = pthread_mutexattr_setpshared(&att, PTHREAD_PROCESS_SHARED);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
}
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);
}
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);
}
rv = pthread_condattr_setpshared(&t2, PTHREAD_PROCESS_SHARED);
if (rv != 0) {
fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
exit(EXIT_FAILURE);
}
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);
}
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);
}
pthread_condattr_destroy(&t1);
pthread_condattr_destroy(&t2);
r->this_stream->read_next = 0;
r->this_stream->write_next = 0;
return r;
}
void ipc_shm_close(struct ipc_shm_io *r)
{
if (r) {
if (r->buf_ptrs)
free(r->buf_ptrs);
free(r);
}
}
int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data)
{
volatile struct ipc_shm_raw_smpl_buf *buf;
int32_t rv;
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
tv.tv_sec += 1;
rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);
if (rv != 0)
return -rv;
while (((r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1)) == r->this_stream->read_next &&
rv == 0)
rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->ce,
(pthread_mutex_t *)&r->this_stream->lock, &tv);
if (rv != 0)
return -rv;
buf = r->buf_ptrs[r->this_stream->write_next];
buf->timestamp = timestamp;
rv = len_in_sps <= r->this_stream->buffer_size ? len_in_sps : r->this_stream->buffer_size;
memcpy((void *)buf->samples, data, SAMPLE_SIZE_BYTE * rv);
buf->data_len = rv;
r->this_stream->write_next = (r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1);
pthread_cond_signal((pthread_cond_t *)&r->this_stream->cf);
pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);
return rv;
}
int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,
uint32_t timeout_seconds)
{
volatile struct ipc_shm_raw_smpl_buf *buf;
int32_t rv;
uint8_t freeflag = 0;
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
tv.tv_sec += timeout_seconds;
rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);
if (rv != 0)
return -rv;
while (r->this_stream->write_next == r->this_stream->read_next && rv == 0)
rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->cf,
(pthread_mutex_t *)&r->this_stream->lock, &tv);
if (rv != 0)
return -rv;
buf = r->buf_ptrs[r->this_stream->read_next];
if (buf->data_len <= num_samples) {
memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * buf->data_len);
r->partial_read_begin_ptr = 0;
rv = buf->data_len;
buf->data_len = 0;
r->this_stream->read_next = (r->this_stream->read_next + 1) & (r->this_stream->num_buffers - 1);
freeflag = 1;
} else /*if (buf->data_len > num_samples)*/ {
memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * num_samples);
r->partial_read_begin_ptr += num_samples;
buf->data_len -= num_samples;
rv = num_samples;
}
*timestamp = buf->timestamp;
buf->timestamp += rv;
if (freeflag)
pthread_cond_signal((pthread_cond_t *)&r->this_stream->ce);
pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);
return rv;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Eric Wild <ewild@sysmocom.de>
*
* 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.
*/
#ifndef IPC_SHM_H
#define IPC_SHM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <shm.h>
#include <stdint.h>
#ifdef __cplusplus
}
#endif
struct ipc_shm_io {
volatile struct ipc_shm_raw_stream *this_stream; // plus num_buffers at end
volatile struct ipc_shm_raw_smpl_buf **volatile buf_ptrs;
uint32_t partial_read_begin_ptr;
};
struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s);
struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s);
void ipc_shm_close(struct ipc_shm_io *r);
int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);
int32_t ipc_shm_tryenqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);
volatile struct ipc_shm_raw_smpl_buf *ipc_shm_dequeue(struct ipc_shm_io *r);
int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,
uint32_t timeout_seconds);
#endif // IPC_SHM_H

View File

@@ -0,0 +1,271 @@
/*
* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <debug.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "shm.h"
#include "ipc-driver-test.h"
extern volatile int ipc_exit_requested;
static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
{
int rc = 0;
switch (msg_type) {
case IPC_IF_MSG_GREETING_REQ:
rc = ipc_rx_greeting_req(&ipc_prim->u.greeting_req);
break;
case IPC_IF_MSG_INFO_REQ:
rc = ipc_rx_info_req(&ipc_prim->u.info_req);
break;
case IPC_IF_MSG_OPEN_REQ:
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);
rc = -EINVAL;
}
return rc;
}
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,
"IPC socket not created, "
"dropping message\n");
msgb_free(msg);
return -EINVAL;
}
conn_bfd = &state->conn_bfd;
if (conn_bfd->fd <= 0) {
LOGP(DMAIN, 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;
return 0;
}
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");
ipc_exit_requested = 1;
close(bfd->fd);
bfd->fd = -1;
osmo_fd_unregister(bfd);
/* re-enable the generation of ACCEPT for new connections */
state->listen_bfd.when |= BSC_FD_READ;
/* flush the queue */
while (!llist_empty(&state->upqueue)) {
struct msgb *msg = msgb_dequeue(&state->upqueue);
msgb_free(msg);
}
}
int ipc_sock_read(struct osmo_fd *bfd)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
struct ipc_sk_if *ipc_prim;
struct msgb *msg;
int rc;
msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");
if (!msg)
return -ENOMEM;
ipc_prim = (struct ipc_sk_if *)msg->tail;
rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
if (rc == 0)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
msgb_free(msg);
return 0;
}
goto close;
}
if (rc < (int)sizeof(*ipc_prim)) {
LOGP(DMAIN, LOGL_ERROR,
"Received %d bytes on Unix Socket, but primitive size "
"is %zu, discarding\n",
rc, sizeof(*ipc_prim));
msgb_free(msg);
return 0;
}
rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
/* as we always synchronously process the message in IPC_rx() and
* its callbacks, we can free the message here. */
msgb_free(msg);
return rc;
close:
msgb_free(msg);
ipc_sock_close(state);
return -1;
}
static int ipc_sock_write(struct osmo_fd *bfd)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
int rc;
while (!llist_empty(&state->upqueue)) {
struct msgb *msg, *msg2;
struct ipc_sk_if *ipc_prim;
/* peek at the beginning of the queue */
msg = llist_entry(state->upqueue.next, struct msgb, list);
ipc_prim = (struct ipc_sk_if *)msg->data;
bfd->when &= ~BSC_FD_WRITE;
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
LOGP(DMAIN, LOGL_ERROR,
"message type (%d) with ZERO "
"bytes!\n",
ipc_prim->msg_type);
goto dontsend;
}
/* try to send it over the socket */
rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
if (rc == 0)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
bfd->when |= BSC_FD_WRITE;
break;
}
goto close;
}
dontsend:
/* _after_ we send it, we can deueue */
msg2 = msgb_dequeue(&state->upqueue);
assert(msg == msg2);
msgb_free(msg);
}
return 0;
close:
ipc_sock_close(state);
return -1;
}
static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
int rc = 0;
if (flags & BSC_FD_READ)
rc = ipc_sock_read(bfd);
if (rc < 0)
return rc;
if (flags & BSC_FD_WRITE)
rc = ipc_sock_write(bfd);
return rc;
}
/* accept connection coming from IPC */
int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
{
struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
struct osmo_fd *conn_bfd = &state->conn_bfd;
struct sockaddr_un un_addr;
socklen_t len;
int rc;
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");
return -1;
}
if (conn_bfd->fd >= 0) {
LOGP(DMAIN, 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;
close(rc);
return 0;
}
conn_bfd->fd = rc;
conn_bfd->when = BSC_FD_READ;
conn_bfd->cb = ipc_sock_cb;
conn_bfd->data = state;
if (osmo_fd_register(conn_bfd) != 0) {
LOGP(DMAIN, LOGL_ERROR,
"Failed to register new connection "
"fd\n");
close(conn_bfd->fd);
conn_bfd->fd = -1;
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
/* send current info */
//IPC_tx_info_ind();
return 0;
}

Some files were not shown because too many files have changed in this diff Show More