Compare commits

...

86 Commits

Author SHA1 Message Date
Pau Espin Pedrol
71637150a1 Bump version: 0.2.0 → 0.3.0
Change-Id: I4dad76ed95dc585acfbd52d7eed4f2e6f9f5fd1f
2018-03-05 16:49:42 +01:00
Alexander Couzens
2393964b77 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
(cherry picked from commit 28b8cc6283)
2018-03-05 16:49:03 +01:00
Alexander Huemer
9ee4df8760 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
(cherry picked from commit 3f52f0e6c5)
2018-03-05 16:47:40 +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
Tom Tsou
980525c8a9 uhd: Add non-UmTRX channel swap support
Previously an UmTRX-only feature.

Change-Id: I4a0e0c1d69e89993158e948535ad33f54e568d2d
Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
2017-06-14 16:34:46 +00:00
Tom Tsou
70134a01eb sigProcLib: Remove unused functions from public interface
Also remove entirely completely unused calls. Most of these
calls have been around since OpenBTS conception. Nearly a
decade is long enough time for deprecation.

Change-Id: Ifc122aaff23414c363b4b00f99061eed8a6902d0
2017-06-14 16:30:28 +00:00
Tom Tsou
1fb0ce67d8 uhd: Use map container for for device parameter access
OsmoTRX is written in C++ so we might as well use built-in
container types when applicable. Map access allows removal
of significant amounts of special device handling code.

Aggregate device rates and timing offsets into a single
table with access keyed by device/tx-sps/rx-sps tuples.

Change-Id: I8660f75a2b2a13488b913c07637bdd0f5f0f4cf9
Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
2017-06-12 13:47:14 -07:00
Tom Tsou
8ca237b5c2 build: Require and check for gcc C++11 support
It is now 2017. We can and should be able to use C++11 features now.

Change-Id: I96477e4125390b17b43a3705bb1daf98fa01c9bb
Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
2017-06-09 11:19:20 -07:00
Alexander Chemeris
082bbbf8fe PRBS: a Pseudo-random binary sequence (PRBS) generator class.
Implemeted with a Galois LFSR for speed and flexibility compared to Fibonacci version.

Aliases for three popular PRBS' are added for convenience - PRBS9, PRBS15 and PRBS64.

Note that we can't test PRBS64 completely, because the sequence is too long to
be generated.

Change-Id: Ib5331ba5d0b5819929541686fdd87905e2177b74
2017-06-08 18:33:47 +00:00
Vadim Yanitskiy
3bd763d2a1 ssedetect: call __builtin_cpu_supports() only if supported
Some compilers don't support the __builtin_cpu_supports built-in,
so let's make them able to compile the project anyway.

Change-Id: I0c90402d8e4c9f196c54b066ff30891c8de3ad2b
2017-06-08 18:32:29 +00:00
Vadim Yanitskiy
ee57357682 buildenv: check for __builtin_cpu_supports call support
The '__builtin_cpu_supports' is a GCC's built-in function which
returns a positive integer if the run-time CPU supports specified
SIMD feature and returns 0 otherwise.

This change adds a new check, whether compiler supports this call.
See /gcc/X86-Built-in-Functions.html at gcc.gnu.org for reference.

Change-Id: I797f638573e8c3aae39c28abb157ce2ac419f3f7
2017-06-08 18:32:29 +00:00
Vadim Yanitskiy
8537b90dbe buildenv: cosmetic changes
Change-Id: I9c52f2981513fa6322bdf992215e3e099ac3ddee
2017-06-08 18:32:29 +00:00
Vadim Yanitskiy
038fd7fd70 buildenv: fix build on systems without SIMD support
HAVE_SSE3 and HAVE_SSE4_1 were never defined if CPU architecture
doesn't match the (86*|x86_64*|amd64*) condition.

Change-Id: I3350b14dbc91e9b388d0b04a0ed22ba27d436313
2017-06-08 18:32:29 +00:00
Vadim Yanitskiy
0cd246c27a buildenv: actually strip unused cpuid functionality
Despite the macro message says, that cpuid functionality was stripped
it was still partially preset and wasn't used anyhow.

Change-Id: I380bc9c13d29319685781ef27973afe6744fcf3d
2017-06-08 18:32:29 +00:00
Vadim Yanitskiy
61fbf2ec95 buildenv: correct the ax_sse macro description
Change-Id: I4ce65443c8a33ae9add8f6da9d911c3178472ab2
2017-06-08 18:32:29 +00:00
70 changed files with 2832 additions and 3892 deletions

26
.gitignore vendored
View File

@@ -5,16 +5,17 @@
Transceiver52M/osmo-trx
# tests
CommonLibs/BitVectorTest
CommonLibs/ConfigurationTest
CommonLibs/F16Test
CommonLibs/InterthreadTest
CommonLibs/LogTest
CommonLibs/RegexpTest
CommonLibs/SocketsTest
CommonLibs/TimevalTest
CommonLibs/URLEncodeTest
CommonLibs/VectorTest
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
# automake/autoconf
*.in
@@ -40,6 +41,11 @@ ltmain.sh
missing
stamp-h1
INSTALL
tests/package.m4
tests/testsuite
tests/atconfig
tests/testsuite.dir
tests/testsuite.log
# vim
*.sw?

83
AUTHORS
View File

@@ -1,18 +1,18 @@
#
# 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.
@@ -23,34 +23,17 @@ David A. Burgess, dburgess@kestrelsp.com:
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
@@ -82,29 +65,15 @@ David A. Burgess, dburgess@kestrelsp.com:
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
tests/CommonLibs/BitVectorTest.cpp
tests/CommonLibs/InterthreadTest.cpp
tests/CommonLibs/SocketsTest.cpp
tests/CommonLibs/TimevalTest.cpp
tests/CommonLibs/VectorTest.cpp
Harvind S. Samra, hssamra@kestrelsp.com:
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMConfig.h
GSM/GSMTransfer.h
LICENSEBLOCK
@@ -126,13 +95,6 @@ Harvind S. Samra, hssamra@kestrelsp.com:
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
@@ -157,36 +119,9 @@ Raffi Sevlian, raffisev@gmail.com:
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

28
COPYING
View File

@@ -673,16 +673,16 @@ 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.

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,69 +0,0 @@
/*
* Copyright 2009 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 <iostream>
#include <iterator>
#include "Logger.h"
#include "Configuration.h"
ConfigurationTable gConfig;
//ConfigurationTable gConfig("example.config");
void printAlarms()
{
std::ostream_iterator<std::string> output( std::cout, "\n" );
std::list<std::string> alarms = gGetLoggerAlarms();
std::cout << "# alarms = " << alarms.size() << std::endl;
std::copy( alarms.begin(), alarms.end(), output );
}
int main(int argc, char *argv[])
{
gLogInit("LogTest","NOTICE",LOG_LOCAL7);
LOG(EMERG) << " testing the logger.";
LOG(ALERT) << " testing the logger.";
LOG(CRIT) << " testing the logger.";
LOG(ERR) << " testing the logger.";
LOG(WARNING) << " testing the logger.";
LOG(NOTICE) << " testing the logger.";
LOG(INFO) << " testing the logger.";
LOG(DEBUG) << " testing the logger.";
std::cout << "\n\n\n";
std::cout << "testing Alarms\n";
std::cout << "you should see three lines:" << std::endl;
printAlarms();
std::cout << "----------- generating 20 alarms ----------" << std::endl;
for (int i = 0 ; i < 20 ; ++i) {
LOG(ALERT) << i;
}
std::cout << "you should see ten lines with the numbers 10..19:" << std::endl;
printAlarms();
}

View File

@@ -32,44 +32,15 @@
#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;
// Global log level threshold:
int config_log_level;
/** Names of the logging levels. */
const char *levelNames[] = {
@@ -96,22 +67,6 @@ int levelStringToInt(const string& name)
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;
@@ -138,127 +93,22 @@ 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 mlen = mStream.str().size();
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
ScopedLock lock(gLogToLock);
// 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";
}
Log::Log(const char* name, const char* level, int facility)
{
mDummyInit = true;
gLogInit(name, level, facility);
}
ostringstream& Log::get()
{
assert(mPriority<numLevels);
@@ -268,64 +118,11 @@ ostringstream& Log::get()
void gLogInit(const char* name, const char* level, int facility)
void gLogInit(const char* level, char *fn)
{
// 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);
if (level)
config_log_level = levelStringToInt(level);
}
// vim: ts=4 sw=4

View File

@@ -32,19 +32,27 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <syslog.h>
#include <stdint.h>
#include <stdio.h>
#include <sstream>
#include <list>
#include <map>
#include <string>
extern int config_log_level;
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#define _LOG(level) \
Log(LOG_##level).get() << pthread_self() \
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
#define IS_LOG_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel)
#define IS_LOG_LEVEL(wLevel) (config_log_level>=LOG_##wLevel)
#ifdef NDEBUG
#define LOG(wLevel) \
@@ -54,40 +62,8 @@
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
#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
// (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 OBJLOG(wLevel) \
LOG(wLevel) << "obj: " << this << ' '
#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()
/**
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.
*/
@@ -99,28 +75,19 @@ class Log {
std::ostringstream mStream; ///< This is where we buffer up the log entry.
int mPriority; ///< Priority of current report.
bool mDummyInit;
public:
Log(int wPriority)
:mPriority(wPriority), mDummyInit(false)
:mPriority(wPriority)
{ }
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);
@@ -128,11 +95,7 @@ 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)));
void gLogInit(const char* level=NULL, char* fn=NULL);
//@}

View File

@@ -22,7 +22,7 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread
AM_CXXFLAGS = -Wall -O3 -g -lpthread
EXTRA_DIST = \
example.config \
@@ -36,59 +36,15 @@ libcommon_la_SOURCES = \
Sockets.cpp \
Threads.cpp \
Timeval.cpp \
Logger.cpp \
Configuration.cpp \
sqlite3util.cpp
noinst_PROGRAMS = \
BitVectorTest \
InterthreadTest \
SocketsTest \
TimevalTest \
VectorTest \
ConfigurationTest \
LogTest
# ReportingTest
Logger.cpp
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)
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
Logger.h

110
CommonLibs/PRBS.h Normal file
View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
*
* 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
*/
#ifndef PRBS_H
#define PRBS_H
#include <stdint.h>
#include <assert.h>
/** Pseudo-random binary sequence (PRBS) generator (a Galois LFSR implementation). */
class PRBS {
public:
PRBS(unsigned wLen, uint64_t wCoeff, uint64_t wState = 0x01)
: mCoeff(wCoeff), mStartState(wState), mState(wState), mLen(wLen)
{ assert(wLen<=64); }
/**@name Accessors */
//@{
uint64_t coeff() const { return mCoeff; }
uint64_t state() const { return mState; }
void state(uint64_t state) { mState = state & mask(); }
unsigned size() const { return mLen; }
//@}
/**
Calculate one bit of a PRBS
*/
unsigned generateBit()
{
const unsigned result = mState & 0x01;
processBit(result);
return result;
}
/**
Update the generator state by one bit.
If you want to synchronize your PRBS to a known state, call this function
size() times passing your PRBS to it bit by bit.
*/
void processBit(unsigned inBit)
{
mState >>= 1;
if (inBit) mState ^= mCoeff;
}
/** Return true when PRBS is wrapping through initial state */
bool isFinished() const { return mStartState == mState; }
protected:
uint64_t mCoeff; ///< polynomial coefficients. LSB is zero exponent.
uint64_t mStartState; ///< initial shift register state.
uint64_t mState; ///< shift register state.
unsigned mLen; ///< number of bits used in shift register
/** Return mask for the state register */
uint64_t mask() const { return (mLen==64)?0xFFFFFFFFFFFFFFFFUL:((1<<mLen)-1); }
};
/**
A standard 9-bit based pseudorandom binary sequence (PRBS) generator.
Polynomial: x^9 + x^5 + 1
*/
class PRBS9 : public PRBS {
public:
PRBS9(uint64_t wState = 0x01)
: PRBS(9, 0x0110, wState)
{}
};
/**
A standard 15-bit based pseudorandom binary sequence (PRBS) generator.
Polynomial: x^15 + x^14 + 1
*/
class PRBS15 : public PRBS {
public:
PRBS15(uint64_t wState = 0x01)
: PRBS(15, 0x6000, wState)
{}
};
/**
A standard 64-bit based pseudorandom binary sequence (PRBS) generator.
Polynomial: x^64 + x^63 + x^61 + x^60 + 1
*/
class PRBS64 : public PRBS {
public:
PRBS64(uint64_t wState = 0x01)
: PRBS(64, 0xD800000000000000ULL, wState)
{}
};
#endif // PRBS_H

View File

@@ -223,18 +223,18 @@ int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
UDPSocket::UDPSocket(unsigned short wSrcPort)
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort)
:DatagramSocket()
{
open(wSrcPort);
open(wSrcPort, wSrcIP);
}
UDPSocket::UDPSocket(unsigned short wSrcPort,
const char * wDestIP, unsigned short wDestPort )
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort,
const char *wDestIP, unsigned short wDestPort)
:DatagramSocket()
{
open(wSrcPort);
open(wSrcPort, wSrcIP);
destination(wDestPort, wDestIP);
}
@@ -246,7 +246,7 @@ void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
}
void UDPSocket::open(unsigned short localPort)
void UDPSocket::open(unsigned short localPort, const char *wlocalIP)
{
// create
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
@@ -265,7 +265,7 @@ void UDPSocket::open(unsigned short localPort)
size_t length = sizeof(address);
bzero(&address,length);
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
address.sin_addr.s_addr = inet_addr(wlocalIP);
address.sin_port = htons(localPort);
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
perror("bind() failed");
@@ -284,50 +284,4 @@ unsigned short UDPSocket::port() const
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

@@ -144,11 +144,11 @@ class UDPSocket : public DatagramSocket {
public:
/** Open a USP socket with an OS-assigned port and no default destination. */
UDPSocket( unsigned short localPort=0);
UDPSocket(const char *localIP, unsigned short localPort);
/** Given a full specification, open the socket and set the dest address. */
UDPSocket( unsigned short localPort,
const char * remoteIP, unsigned short remotePort);
UDPSocket(const char *localIP, unsigned short localPort,
const char *remoteIP, unsigned short remotePort);
/** Set the destination port. */
void destination( unsigned short wDestPort, const char * wDestIP );
@@ -157,7 +157,7 @@ public:
unsigned short port() const;
/** Open and bind the UDP socket to a local port. */
void open(unsigned short localPort=0);
void open(unsigned short localPort=0, const char *wlocalIP="127.0.0.1");
/** Give the return address of the most recently received packet. */
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
@@ -166,26 +166,6 @@ public:
};
/** 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

View File

@@ -118,8 +118,8 @@ template <class T> class Vector {
/** Build an empty Vector of a given size. */
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
/** Build a Vector by shifting the data block. */
Vector(Vector<T>& other)
/** Build a Vector by moving another. */
Vector(Vector<T>&& other)
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
{ other.mData=NULL; }

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

View File

@@ -2,32 +2,18 @@ Installation Requirements
OpenBTS compiles to a simple Unix binary and does not require special
osmo-trx 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).
To run osmo-trx, the following should be installed:
libuhd (https://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
See https://osmocom.org/projects/osmotrx/wiki/OsmoTRX 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,16 +21,17 @@
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 = \
CommonLibs \
GSM \
Transceiver52M
Transceiver52M \
tests
EXTRA_DIST = \
autogen.sh \
@@ -39,6 +40,9 @@ EXTRA_DIST = \
COPYING \
README
.PHONY: release
@RELMAKE@
dox: FORCE
doxygen doxconfig

View File

@@ -32,4 +32,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/arm/libarch.la
else
ARCH_LA = $(top_builddir)/Transceiver52M/x86/libarch.la
endif
MOSTLYCLEANFILES = *~

View File

@@ -25,7 +25,6 @@
#include <string.h>
#include <cstdio>
#include "Logger.h"
#include "Channelizer.h"
extern "C" {

View File

@@ -22,17 +22,11 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/common
AM_CXXFLAGS = -ldl -lpthread
AM_CXXFLAGS = -lpthread
SUBDIRS = arm x86
if ARCH_ARM
ARCH_LA = arm/libarch.la
else
ARCH_LA = x86/libarch.la
endif
if USRP1
if USRP1
AM_CPPFLAGS += $(USRP_CFLAGS)
else
AM_CPPFLAGS += $(UHD_CFLAGS)
@@ -97,12 +91,13 @@ osmo_trx_LDADD = \
libtransceiver.la \
$(ARCH_LA) \
$(GSM_LA) \
$(COMMON_LA) $(SQLITE3_LIBS)
$(COMMON_LA) \
$(FFTWF_LIBS)
if USRP1
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)
osmo_trx_LDADD += $(UHD_LIBS)
endif

View File

@@ -22,6 +22,7 @@
#include <string.h>
#include <malloc.h>
#include <iostream>
#include <algorithm>
#include "Resampler.h"
@@ -35,6 +36,8 @@ extern "C" {
#define MAX_OUTPUT_LEN 4096
using namespace std;
static float sinc(float x)
{
if (x == 0.0)
@@ -43,32 +46,19 @@ 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;
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));
}
auto proto = vector<float>(p * filt_len);
for (auto &part : partitions)
part = (complex<float> *) memalign(16, filt_len * sizeof(complex<float>));
/*
* Generate the prototype filter with a Blackman-harris window.
@@ -85,47 +75,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 +128,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;
@@ -180,8 +141,8 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
path = out_path[i];
convolve_real(in, in_len,
partitions[path], filt_len,
&out[2 * i], out_len - i,
reinterpret_cast<float *>(partitions[path]),
filt_len, &out[2 * i], out_len - i,
n, 1, 1, 0);
}
@@ -190,14 +151,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 +173,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 +182,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

@@ -20,6 +20,9 @@
#ifndef _RESAMPLER_H_
#define _RESAMPLER_H_
#include <vector>
#include <complex>
class Resampler {
public:
/* Constructor for rational sample rate conversion
@@ -63,14 +66,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

@@ -24,8 +24,8 @@
#include <assert.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include "Logger.h"
#include "Synthesis.h"
extern "C" {

View File

@@ -112,16 +112,17 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, un
}
Transceiver::Transceiver(int wBasePort,
const char *wTRXAddress,
const char *TRXAddress,
const char *GSMcoreAddress,
size_t tx_sps, size_t rx_sps, size_t chans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset)
: mBasePort(wBasePort), mAddr(wTRXAddress),
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
: mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
mClockSocket(TRXAddress, wBasePort, GSMcoreAddress, wBasePort + 100),
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
rssiOffset(wRssiOffset),
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false),
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
mWriteBurstToDiskMask(0)
{
@@ -197,8 +198,8 @@ bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay, bool edge)
d_srcport = mBasePort + 2 * i + 2;
d_dstport = mBasePort + 2 * i + 102;
mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
mCtrlSockets[i] = new UDPSocket(mLocalAddr.c_str(), c_srcport, mRemoteAddr.c_str(), c_dstport);
mDataSockets[i] = new UDPSocket(mLocalAddr.c_str(), d_srcport, mRemoteAddr.c_str(), d_dstport);
}
/* Randomize the central clock */
@@ -273,7 +274,7 @@ bool Transceiver::start()
TxUpperLoopAdapter, (void*) chan);
}
writeClockInterface();
mForceClockInterface = true;
mOn = true;
return true;
}
@@ -297,6 +298,10 @@ void Transceiver::stop()
LOG(NOTICE) << "Stopping the transceiver";
mTxLowerLoopThread->cancel();
mRxLowerLoopThread->cancel();
mTxLowerLoopThread->join();
mRxLowerLoopThread->join();
delete mTxLowerLoopThread;
delete mRxLowerLoopThread;
for (size_t i = 0; i < mChans; i++) {
mRxServiceLoopThreads[i]->cancel();
@@ -315,11 +320,6 @@ void Transceiver::stop()
mTxPriorityQueues[i].clear();
}
mTxLowerLoopThread->join();
mRxLowerLoopThread->join();
delete mTxLowerLoopThread;
delete mRxLowerLoopThread;
mOn = false;
LOG(NOTICE) << "Transceiver stopped";
}
@@ -430,7 +430,7 @@ void Transceiver::setModulus(size_t timeslot, size_t chan)
case V:
state->fillerModulus[timeslot] = 51;
break;
//case V:
//case V:
case VII:
state->fillerModulus[timeslot] = 102;
break;
@@ -545,7 +545,7 @@ void writeToFile(radioVector *radio_burst, size_t chan)
/*
* Pull bursts from the FIFO and handle according to the slot
* and burst correlation type. Equalzation is currently disabled.
* and burst correlation type. Equalzation is currently disabled.
*/
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
double &timingOffset, double &noise,
@@ -656,7 +656,7 @@ void Transceiver::reset()
mTxPriorityQueues[i].clear();
}
void Transceiver::driveControl(size_t chan)
{
int MAX_PACKET_LENGTH = 100;
@@ -678,9 +678,6 @@ void Transceiver::driveControl(size_t chan)
sscanf(buffer,"%3s %s",cmdcheck,command);
if (!chan)
writeClockInterface();
if (strcmp(cmdcheck,"CMD")!=0) {
LOG(WARNING) << "bogus message on control interface";
return;
@@ -805,7 +802,7 @@ void Transceiver::driveControl(size_t chan)
LOG(WARNING) << "bogus message on control interface";
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
return;
}
}
mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
setModulus(timeslot, chan);
sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
@@ -853,14 +850,14 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
int RSSI = (int) buffer[5];
BitVector newBurst(burstLen);
BitVector::iterator itr = newBurst.begin();
char *bufferItr = buffer+6;
while (itr < newBurst.end())
while (itr < newBurst.end())
*itr++ = *bufferItr++;
GSM::Time currTime = GSM::Time(frameNum,timeSlot);
addRadioVector(chan, newBurst, RSSI, currTime);
@@ -874,9 +871,9 @@ void Transceiver::driveReceiveRadio()
{
if (!mRadioInterface->driveReceiveRadio()) {
usleep(100000);
} else {
if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
writeClockInterface();
} else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
mForceClockInterface = false;
writeClockInterface();
}
}
@@ -946,7 +943,7 @@ void Transceiver::driveTxFIFO()
{
/**
Features a carefully controlled latency mechanism, to
Features a carefully controlled latency mechanism, to
assure that transmit packets arrive at the radio/USRP
before they need to be transmitted.
@@ -957,7 +954,7 @@ void Transceiver::driveTxFIFO()
RadioClock *radioClock = (mRadioInterface->getClock());
if (mOn) {
//radioClock->wait(); // wait until clock updates
LOG(DEBUG) << "radio clock " << radioClock->get();

View File

@@ -89,15 +89,17 @@ 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,
@@ -152,7 +154,8 @@ public:
private:
int mBasePort;
std::string mAddr;
std::string mLocalAddr;
std::string mRemoteAddr;
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
@@ -169,7 +172,7 @@ private:
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
@@ -208,6 +211,7 @@ private:
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
@@ -275,4 +279,3 @@ void *ControlServiceLoopAdapter(TransceiverChannel *);
/** transmit queueing thread loop */
void *TxUpperLoopAdapter(TransceiverChannel *);

View File

@@ -1,5 +1,5 @@
/*
* Device support for Ettus Research UHD driver
* Device support for Ettus Research UHD driver
*
* Copyright 2010,2011 Free Software Foundation, Inc.
* Copyright (C) 2015 Ettus Research LLC
@@ -21,6 +21,7 @@
* See the COPYING file in the main directory for details.
*/
#include <map>
#include "radioDevice.h"
#include "Threads.h"
#include "Logger.h"
@@ -37,12 +38,6 @@
#include <uhd/utils/msg.hpp>
#endif
#define B2XX_CLK_RT 26e6
#define B2XX_MCBTS_CLK_RT 51.2e6
#define E1XX_CLK_RT 52e6
#define LIMESDR_CLK_RT (GSMRATE*32)
#define B100_BASE_RT 400000
#define USRP2_BASE_RT 390625
#define USRP_TX_AMPL 0.3
#define UMTRX_TX_AMPL 0.7
#define LIMESDR_TX_AMPL 0.3
@@ -73,15 +68,6 @@ enum uhd_dev_type {
X3XX,
UMTRX,
LIMESDR,
NUM_USRP_TYPES,
};
struct uhd_dev_offset {
enum uhd_dev_type type;
size_t tx_sps;
size_t rx_sps;
double offset;
const std::string desc;
};
/*
@@ -109,76 +95,44 @@ struct uhd_dev_offset {
* Notes:
* USRP1 with timestamps is not supported by UHD.
*/
static struct uhd_dev_offset uhd_offsets[] = {
{ USRP1, 1, 1, 0.0, "USRP1 not supported" },
{ USRP1, 4, 1, 0.0, "USRP1 not supported"},
{ USRP2, 1, 1, 1.2184e-4, "N2XX 1 SPS" },
{ USRP2, 4, 1, 7.6547e-5, "N2XX 4/1 SPS" },
{ B100, 1, 1, 1.2104e-4, "B100 1 SPS" },
{ B100, 4, 1, 7.9307e-5, "B100 4 SPS" },
{ B200, 1, 1, B2XX_TIMING_1SPS, "B200 1 SPS" },
{ B200, 4, 1, B2XX_TIMING_4SPS, "B200 4/1 Tx/Rx SPS" },
{ B210, 1, 1, B2XX_TIMING_1SPS, "B210 1 SPS" },
{ B210, 4, 1, B2XX_TIMING_4SPS, "B210 4/1 Tx/Rx SPS" },
{ B2XX_MCBTS, 4, 4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" },
{ E1XX, 1, 1, 9.5192e-5, "E1XX 1 SPS" },
{ E1XX, 4, 1, 6.5571e-5, "E1XX 4/1 Tx/Rx SPS" },
{ E3XX, 1, 1, 1.84616e-4, "E3XX 1 SPS" },
{ E3XX, 4, 1, 1.29231e-4, "E3XX 4/1 Tx/Rx SPS" },
{ X3XX, 1, 1, 1.5360e-4, "X3XX 1 SPS"},
{ X3XX, 4, 1, 1.1264e-4, "X3XX 4/1 Tx/Rx SPS"},
{ UMTRX, 1, 1, 9.9692e-5, "UmTRX 1 SPS" },
{ UMTRX, 4, 1, 7.3846e-5, "UmTRX 4/1 Tx/Rx SPS" },
{ USRP2, 4, 4, 4.6080e-5, "N2XX 4 SPS" },
{ B200, 4, 4, B2XX_TIMING_4_4SPS, "B200 4 SPS" },
{ B210, 4, 4, B2XX_TIMING_4_4SPS, "B210 4 SPS" },
{ X3XX, 4, 4, 5.6567e-5, "X3XX 4 SPS"},
{ UMTRX, 4, 4, 5.1503e-5, "UmTRX 4 SPS" },
{ LIMESDR, 4, 4, 16.5/GSMRATE, "STREAM/LimeSDR (4 SPS TX/RX)" },
/* Device Type, Tx-SPS, Rx-SPS */
typedef std::tuple<uhd_dev_type, int, int> dev_key;
/* Device parameter descriptor */
struct dev_desc {
unsigned channels;
double mcr;
double rate;
double offset;
std::string str;
};
#define NUM_UHD_OFFSETS (sizeof(uhd_offsets)/sizeof(uhd_offsets[0]))
/*
* Select sample rate based on device type and requested samples-per-symbol.
* The base rate is either GSM symbol rate, 270.833 kHz, or the minimum
* usable channel spacing of 400 kHz.
*/
static double select_rate(uhd_dev_type type, int sps,
RadioDevice::InterfaceType iface)
{
if ((sps != 4) && (sps != 1))
return -9999.99;
if (iface == RadioDevice::MULTI_ARFCN) {
switch (type) {
case B2XX_MCBTS:
return 4 * MCBTS_SPACING;
default:
LOG(ALERT) << "Invalid device combination";
return -9999.99;
}
}
switch (type) {
case USRP2:
case X3XX:
return USRP2_BASE_RT * sps;
case B100:
return B100_BASE_RT * sps;
case B200:
case B210:
case E1XX:
case E3XX:
case UMTRX:
case LIMESDR:
return GSMRATE * sps;
default:
break;
}
LOG(ALERT) << "Unknown device type " << type;
return -9999.99;
}
static const std::map<dev_key, dev_desc> dev_param_map {
{ std::make_tuple(USRP2, 1, 1), { 1, 0.0, 390625, 1.2184e-4, "N2XX 1 SPS" } },
{ std::make_tuple(USRP2, 4, 1), { 1, 0.0, 390625, 7.6547e-5, "N2XX 4/1 Tx/Rx SPS" } },
{ std::make_tuple(USRP2, 4, 4), { 1, 0.0, 390625, 4.6080e-5, "N2XX 4 SPS" } },
{ std::make_tuple(B100, 1, 1), { 1, 0.0, 400000, 1.2104e-4, "B100 1 SPS" } },
{ std::make_tuple(B100, 4, 1), { 1, 0.0, 400000, 7.9307e-5, "B100 4/1 Tx/Rx SPS" } },
{ std::make_tuple(B200, 1, 1), { 1, 26e6, GSMRATE, B2XX_TIMING_1SPS, "B200 1 SPS" } },
{ std::make_tuple(B200, 4, 1), { 1, 26e6, GSMRATE, B2XX_TIMING_4SPS, "B200 4/1 Tx/Rx SPS" } },
{ std::make_tuple(B200, 4, 4), { 1, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "B200 4 SPS" } },
{ std::make_tuple(B210, 1, 1), { 2, 26e6, GSMRATE, B2XX_TIMING_1SPS, "B210 1 SPS" } },
{ std::make_tuple(B210, 4, 1), { 2, 26e6, GSMRATE, B2XX_TIMING_4SPS, "B210 4/1 Tx/Rx SPS" } },
{ std::make_tuple(B210, 4, 4), { 2, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "B210 4 SPS" } },
{ std::make_tuple(E1XX, 1, 1), { 1, 52e6, GSMRATE, 9.5192e-5, "E1XX 1 SPS" } },
{ std::make_tuple(E1XX, 4, 1), { 1, 52e6, GSMRATE, 6.5571e-5, "E1XX 4/1 Tx/Rx SPS" } },
{ std::make_tuple(E3XX, 1, 1), { 2, 26e6, GSMRATE, 1.8462e-4, "E3XX 1 SPS" } },
{ std::make_tuple(E3XX, 4, 1), { 2, 26e6, GSMRATE, 1.2923e-4, "E3XX 4/1 Tx/Rx SPS" } },
{ std::make_tuple(X3XX, 1, 1), { 2, 0.0, 390625, 1.5360e-4, "X3XX 1 SPS" } },
{ std::make_tuple(X3XX, 4, 1), { 2, 0.0, 390625, 1.1264e-4, "X3XX 4/1 Tx/Rx SPS" } },
{ std::make_tuple(X3XX, 4, 4), { 2, 0.0, 390625, 5.6567e-5, "X3XX 4 SPS" } },
{ std::make_tuple(UMTRX, 1, 1), { 2, 0.0, GSMRATE, 9.9692e-5, "UmTRX 1 SPS" } },
{ std::make_tuple(UMTRX, 4, 1), { 2, 0.0, GSMRATE, 7.3846e-5, "UmTRX 4/1 Tx/Rx SPS"} },
{ std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 8.9e-5, "LimeSDR 4 SPS" } },
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
};
/*
Sample Buffer - Allows reading and writing of timed samples using osmo-trx
@@ -189,8 +143,8 @@ class smpl_buf {
public:
/** Sample buffer constructor
@param len number of 32-bit samples the buffer should hold
@param rate sample clockrate
@param timestamp
@param rate sample clockrate
@param timestamp
*/
smpl_buf(size_t len, double rate);
~smpl_buf();
@@ -218,7 +172,7 @@ public:
*/
std::string str_status(size_t ts) const;
/** Formatted error string
/** Formatted error string
@param code an error code
@return a formatted error string
*/
@@ -254,7 +208,9 @@ private:
class uhd_device : public RadioDevice {
public:
uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
size_t chans, double offset);
size_t chans, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths);
~uhd_device();
int open(const std::string &args, int ref, bool swap_channels);
@@ -294,6 +250,11 @@ public:
double getRxFreq(size_t chan);
double getRxFreq();
bool setRxAntenna(const std::string &ant, size_t chan);
std::string getRxAntenna(size_t chan);
bool setTxAntenna(const std::string &ant, size_t chan);
std::string getTxAntenna(size_t chan);
inline double getSampleRate() { return tx_rate; }
inline double numberRead() { return rx_pkt_cnt; }
inline double numberWritten() { return 0; }
@@ -326,6 +287,7 @@ private:
std::vector<double> tx_gains, rx_gains;
std::vector<double> tx_freqs, rx_freqs;
std::vector<std::string> tx_paths, rx_paths;
size_t tx_spp, rx_spp;
bool started;
@@ -339,9 +301,9 @@ private:
std::vector<smpl_buf *> rx_buffers;
void init_gains();
double get_dev_offset();
int set_master_clk(double rate);
int set_rates(double tx_rate, double rx_rate);
void set_channels(bool swap);
void set_rates();
bool set_antennas();
bool parse_dev_type();
bool flush_recv(size_t num_pkts);
int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
@@ -400,18 +362,22 @@ static void thread_enable_cancel(bool cancel)
}
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
InterfaceType iface, size_t chans, double offset)
InterfaceType iface, size_t chans, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths)
: tx_gain_min(0.0), tx_gain_max(0.0),
rx_gain_min(0.0), rx_gain_max(0.0),
tx_spp(0), rx_spp(0),
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
prev_ts(0,0), ts_initial(0), ts_offset(0)
prev_ts(0,0), ts_initial(0), ts_offset(0), async_event_thrd(NULL)
{
this->tx_sps = tx_sps;
this->rx_sps = rx_sps;
this->chans = chans;
this->offset = offset;
this->iface = iface;
this->tx_paths = tx_paths;
this->rx_paths = rx_paths;
}
uhd_device::~uhd_device()
@@ -470,105 +436,49 @@ void uhd_device::init_gains()
}
double uhd_device::get_dev_offset()
void uhd_device::set_rates()
{
struct uhd_dev_offset *offset = NULL;
dev_desc desc = dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps));
if (desc.mcr != 0.0)
usrp_dev->set_master_clock_rate(desc.mcr);
/* Reject USRP1 */
if (dev_type == USRP1) {
LOG(ERR) << "Invalid device type";
return 0.0;
}
tx_rate = (dev_type != B2XX_MCBTS) ? desc.rate * tx_sps : desc.rate;
rx_rate = (dev_type != B2XX_MCBTS) ? desc.rate * rx_sps : desc.rate;
/* Search for matching offset value */
for (size_t i = 0; i < NUM_UHD_OFFSETS; i++) {
if ((dev_type == uhd_offsets[i].type) &&
(tx_sps == uhd_offsets[i].tx_sps) &&
(rx_sps == uhd_offsets[i].rx_sps)) {
offset = &uhd_offsets[i];
break;
usrp_dev->set_tx_rate(tx_rate);
usrp_dev->set_rx_rate(rx_rate);
tx_rate = usrp_dev->get_tx_rate();
rx_rate = usrp_dev->get_rx_rate();
ts_offset = static_cast<TIMESTAMP>(desc.offset * rx_rate);
LOG(INFO) << "Rates configured for " << desc.str;
}
bool uhd_device::set_antennas()
{
unsigned int i;
for (i = 0; i < tx_paths.size(); i++) {
if (tx_paths[i] == "")
continue;
LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i];
if (!setTxAntenna(tx_paths[i], i)) {
LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << tx_paths[i];
return false;
}
}
if (!offset) {
LOG(ERR) << "Invalid device configuration";
return 0.0;
for (i = 0; i < rx_paths.size(); i++) {
if (rx_paths[i] == "")
continue;
LOG(DEBUG) << "Configuring channel " << i << " with antenna " << rx_paths[i];
if (!setRxAntenna(rx_paths[i], i)) {
LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << rx_paths[i];
return false;
}
}
std::cout << "-- Setting " << offset->desc << std::endl;
return offset->offset;
}
int uhd_device::set_master_clk(double clk_rate)
{
double actual, offset, limit = 1.0;
try {
usrp_dev->set_master_clock_rate(clk_rate);
} catch (const std::exception &ex) {
LOG(ALERT) << "UHD clock rate setting failed: " << clk_rate;
LOG(ALERT) << ex.what();
return -1;
}
actual = usrp_dev->get_master_clock_rate();
offset = fabs(clk_rate - actual);
if (offset > limit) {
LOG(ALERT) << "Failed to set master clock rate";
LOG(ALERT) << "Requested clock rate " << clk_rate;
LOG(ALERT) << "Actual clock rate " << actual;
return -1;
}
return 0;
}
int uhd_device::set_rates(double tx_rate, double rx_rate)
{
double offset_limit = 1.0;
double tx_offset, rx_offset;
/* B2XX and E1xx are the only device where we set FPGA clocking */
if ((dev_type == B200) || (dev_type == B210) || (dev_type == E3XX)) {
if (set_master_clk(B2XX_CLK_RT) < 0)
return -1;
} else if (dev_type == E1XX) {
if (set_master_clk(E1XX_CLK_RT) < 0)
return -1;
} else if (dev_type == B2XX_MCBTS) {
if (set_master_clk(B2XX_MCBTS_CLK_RT) < 0)
return -1;
}
else if (dev_type == LIMESDR) {
if (set_master_clk(LIMESDR_CLK_RT) < 0)
return -1;
}
// Set sample rates
try {
usrp_dev->set_tx_rate(tx_rate);
usrp_dev->set_rx_rate(rx_rate);
} catch (const std::exception &ex) {
LOG(ALERT) << "UHD rate setting failed";
LOG(ALERT) << ex.what();
return -1;
}
this->tx_rate = usrp_dev->get_tx_rate();
this->rx_rate = usrp_dev->get_rx_rate();
tx_offset = fabs(this->tx_rate - tx_rate);
rx_offset = fabs(this->rx_rate - rx_rate);
if ((tx_offset > offset_limit) || (rx_offset > offset_limit)) {
LOG(ALERT) << "Actual sample rate differs from desired rate";
LOG(ALERT) << "Tx/Rx (" << this->tx_rate << "/"
<< this->rx_rate << ")";
return -1;
}
return 0;
LOG(INFO) << "Antennas configured successfully";
return true;
}
double uhd_device::setTxGain(double db, size_t chan)
@@ -641,86 +551,41 @@ double uhd_device::getRxGain(size_t chan)
*/
bool uhd_device::parse_dev_type()
{
std::string mboard_str, dev_str;
uhd::property_tree::sptr prop_tree;
size_t usrp1_str, usrp2_str, e100_str, e110_str, e310_str, e3xx_str,
b100_str, b200_str, b210_str, x300_str, x310_str, umtrx_str, limesdr_str;
uhd::property_tree::sptr prop_tree = usrp_dev->get_device()->get_tree();
std::string devString = prop_tree->access<std::string>("/name").get();
std::string mboardString = usrp_dev->get_mboard_name();
prop_tree = usrp_dev->get_device()->get_tree();
dev_str = prop_tree->access<std::string>("/name").get();
mboard_str = usrp_dev->get_mboard_name();
const std::map<std::string, std::pair<uhd_dev_type, TxWindowType>> devStringMap {
{ "B100", { B100, TX_WINDOW_USRP1 } },
{ "B200", { B200, TX_WINDOW_USRP1 } },
{ "B200mini", { B200, TX_WINDOW_USRP1 } },
{ "B205mini", { B200, TX_WINDOW_USRP1 } },
{ "B210", { B210, TX_WINDOW_USRP1 } },
{ "E100", { E1XX, TX_WINDOW_FIXED } },
{ "E110", { E1XX, TX_WINDOW_FIXED } },
{ "E310", { E3XX, TX_WINDOW_FIXED } },
{ "E3XX", { E3XX, TX_WINDOW_FIXED } },
{ "X300", { X3XX, TX_WINDOW_FIXED } },
{ "X310", { X3XX, TX_WINDOW_FIXED } },
{ "USRP2", { USRP2, TX_WINDOW_FIXED } },
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
{ "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } },
};
usrp1_str = dev_str.find("USRP1");
usrp2_str = dev_str.find("USRP2");
b100_str = mboard_str.find("B100");
b200_str = mboard_str.find("B200");
b210_str = mboard_str.find("B210");
e100_str = mboard_str.find("E100");
e110_str = mboard_str.find("E110");
e310_str = mboard_str.find("E310");
e3xx_str = mboard_str.find("E3XX");
x300_str = mboard_str.find("X300");
x310_str = mboard_str.find("X310");
umtrx_str = dev_str.find("UmTRX");
// LimeSDR is based on STREAM board, so it's advertized as such
limesdr_str = dev_str.find("STREAM");
if (usrp1_str != std::string::npos) {
LOG(ALERT) << "USRP1 is not supported using the UHD driver";
LOG(ALERT) << "Please compile with GNU Radio libusrp support";
dev_type = USRP1;
return false;
// Compare UHD motherboard and device strings */
auto mapIter = devStringMap.begin();
while (mapIter != devStringMap.end()) {
if (devString.find(mapIter->first) != std::string::npos ||
mboardString.find(mapIter->first) != std::string::npos) {
dev_type = std::get<0>(mapIter->second);
tx_window = std::get<1>(mapIter->second);
return true;
}
mapIter++;
}
if (b100_str != std::string::npos) {
tx_window = TX_WINDOW_USRP1;
dev_type = B100;
} else if (b200_str != std::string::npos) {
tx_window = TX_WINDOW_USRP1;
dev_type = B200;
} else if (b210_str != std::string::npos) {
tx_window = TX_WINDOW_USRP1;
dev_type = B210;
} else if (e100_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = E1XX;
} else if (e110_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = E1XX;
} else if (usrp2_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = USRP2;
} else if ((e310_str != std::string::npos) ||
(e3xx_str != std::string::npos)) {
tx_window = TX_WINDOW_FIXED;
dev_type = E3XX;
} else if (x300_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = X3XX;
} else if (x310_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = X3XX;
} else if (umtrx_str != std::string::npos) {
tx_window = TX_WINDOW_FIXED;
dev_type = UMTRX;
} else if (limesdr_str != std::string::npos) {
tx_window = TX_WINDOW_USRP1;
dev_type = LIMESDR;
} else {
LOG(ALERT) << "Unknown UHD device type "
<< dev_str << " " << mboard_str;
return false;
}
if (tx_window == TX_WINDOW_USRP1) {
LOG(INFO) << "Using USRP1 type transmit window for "
<< dev_str << " " << mboard_str;
} else {
LOG(INFO) << "Using fixed transmit window for "
<< dev_str << " " << mboard_str;
}
return true;
LOG(ALERT) << "Unsupported device " << devString;
return false;
}
/*
@@ -743,6 +608,45 @@ static bool uhd_e3xx_version_chk()
return true;
}
void uhd_device::set_channels(bool swap)
{
if (iface == MULTI_ARFCN) {
if (dev_type != B200 && dev_type != B210)
throw std::invalid_argument("Device does not support MCBTS");
dev_type = B2XX_MCBTS;
chans = 1;
}
if (chans > dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps)).channels)
throw std::invalid_argument("Device does not support number of requested channels");
std::string subdev_string;
switch (dev_type) {
case B210:
case E3XX:
if (chans == 1)
subdev_string = swap ? "A:B" : "A:A";
else if (chans == 2)
subdev_string = swap ? "A:B A:A" : "A:A A:B";
break;
case X3XX:
case UMTRX:
if (chans == 1)
subdev_string = swap ? "B:0" : "A:0";
else if (chans == 2)
subdev_string = swap ? "B:0 A:0" : "A:0 B:0";
break;
default:
break;
}
if (!subdev_string.empty()) {
uhd::usrp::subdev_spec_t spec(subdev_string);
usrp_dev->set_tx_subdev_spec(spec);
usrp_dev->set_rx_subdev_spec(spec);
}
}
int uhd_device::open(const std::string &args, int ref, bool swap_channels)
{
const char *refstr;
@@ -773,27 +677,15 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
return -1;
}
// Verify and set channels
if (iface == MULTI_ARFCN) {
if ((dev_type != B200) && (dev_type != B210)) {
LOG(ALERT) << "Unsupported device configuration";
return -1;
}
try {
set_channels(swap_channels);
} catch (const std::exception &e) {
LOG(ALERT) << "Channel setting failed - " << e.what();
return -1;
}
dev_type = B2XX_MCBTS;
chans = 1;
} else if (chans == 2) {
if (dev_type == B210) {
} else if (dev_type == UMTRX) {
uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
usrp_dev->set_tx_subdev_spec(subdev_spec);
usrp_dev->set_rx_subdev_spec(subdev_spec);
} else {
LOG(ALERT) << "Invalid device configuration";
return -1;
}
} else if (chans != 1) {
LOG(ALERT) << "Invalid channel combination for device";
if (!set_antennas()) {
LOG(ALERT) << "UHD antenna setting failed";
return -1;
}
@@ -820,14 +712,12 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
usrp_dev->set_clock_source(refstr);
// Set rates
double _rx_rate = select_rate(dev_type, rx_sps, iface);
double _tx_rate = select_rate(dev_type, tx_sps, iface);
if ((_tx_rate < 0.0) || (_rx_rate < 0.0))
return -1;
if (set_rates(_tx_rate, _rx_rate) < 0)
try {
set_rates();
} catch (const std::exception &e) {
LOG(ALERT) << "UHD rate setting failed - " << e.what();
return -1;
}
// Set RF frontend bandwidth
if (dev_type == UMTRX) {
@@ -860,18 +750,7 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
// Set receive chain sample offset. Trigger the EDGE offset
// table by checking for 4 SPS on the receive path. No other
// configuration supports using 4 SPS.
double offset = get_dev_offset();
if (offset == 0.0) {
LOG(ERR) << "Unsupported configuration, no correction applied";
ts_offset = 0;
} else {
ts_offset = (TIMESTAMP) (offset * rx_rate);
}
// Initialize and shadow gain values
// Initialize and shadow gain values
init_gains();
// Print configuration
@@ -1092,7 +971,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
rx_pkt_cnt++;
// Check for errors
// Check for errors
rc = check_rx_md_err(metadata, num_smpls);
switch (rc) {
case ERROR_UNRECOVERABLE:
@@ -1236,7 +1115,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
/* Find center frequency between channels */
rf_spread = fabs(freqs[!chan] - freq);
if (rf_spread > B2XX_CLK_RT) {
if (rf_spread > dev_param_map.at(dev_key(B210, tx_sps, rx_sps)).mcr) {
LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
return treq;
}
@@ -1331,6 +1210,78 @@ double uhd_device::getRxFreq(size_t chan)
return rx_freqs[chan];
}
bool uhd_device::setRxAntenna(const std::string &ant, size_t chan)
{
std::vector<std::string> avail;
if (chan >= rx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return false;
}
avail = usrp_dev->get_rx_antennas(chan);
if (std::find(avail.begin(), avail.end(), ant) == avail.end()) {
LOG(ALERT) << "Requested non-existent Rx antenna " << ant << " on channel " << chan;
LOG(INFO) << "Available Rx antennas: ";
for (std::vector<std::string>::const_iterator i = avail.begin(); i != avail.end(); ++i)
LOG(INFO) << "- '" << *i << "'";
return false;
}
usrp_dev->set_rx_antenna(ant, chan);
rx_paths[chan] = usrp_dev->get_rx_antenna(chan);
if (ant != rx_paths[chan]) {
LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << rx_paths[chan];
return false;
}
return true;
}
std::string uhd_device::getRxAntenna(size_t chan)
{
if (chan >= rx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return "";
}
return usrp_dev->get_rx_antenna(chan);
}
bool uhd_device::setTxAntenna(const std::string &ant, size_t chan)
{
std::vector<std::string> avail;
if (chan >= tx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return false;
}
avail = usrp_dev->get_tx_antennas(chan);
if (std::find(avail.begin(), avail.end(), ant) == avail.end()) {
LOG(ALERT) << "Requested non-existent Tx antenna " << ant << " on channel " << chan;
LOG(INFO) << "Available Tx antennas: ";
for (std::vector<std::string>::const_iterator i = avail.begin(); i != avail.end(); ++i)
LOG(INFO) << "- '" << *i << "'";
return false;
}
usrp_dev->set_tx_antenna(ant, chan);
tx_paths[chan] = usrp_dev->get_tx_antenna(chan);
if (ant != tx_paths[chan]) {
LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << tx_paths[chan];
return false;
}
return true;
}
std::string uhd_device::getTxAntenna(size_t chan)
{
if (chan >= tx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return "";
}
return usrp_dev->get_tx_antenna(chan);
}
/*
* Only allow sampling the Rx path lower than Tx and not vice-versa.
* Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed
@@ -1352,7 +1303,7 @@ TIMESTAMP uhd_device::initialReadTimestamp()
double uhd_device::fullScaleInputValue()
{
if (dev_type == LIMESDR)
return (double) 2047 * LIMESDR_TX_AMPL;
return (double) SHRT_MAX * LIMESDR_TX_AMPL;
if (dev_type == UMTRX)
return (double) SHRT_MAX * UMTRX_TX_AMPL;
else
@@ -1361,7 +1312,6 @@ double uhd_device::fullScaleInputValue()
double uhd_device::fullScaleOutputValue()
{
if (dev_type == LIMESDR) return (double) 2047;
return (double) SHRT_MAX;
}
@@ -1618,7 +1568,9 @@ std::string smpl_buf::str_code(ssize_t code)
}
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
InterfaceType iface, size_t chans, double offset)
InterfaceType iface, size_t chans, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths)
{
return new uhd_device(tx_sps, rx_sps, iface, chans, offset);
return new uhd_device(tx_sps, rx_sps, iface, chans, offset, tx_paths, rx_paths);
}

View File

@@ -27,17 +27,16 @@
Compilation Flags
SWLOOPBACK compile for software loopback testing
*/
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "Logger.h"
#include "Threads.h"
#include "USRPDevice.h"
#include <Logger.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -81,7 +80,7 @@ USRPDevice::USRPDevice(size_t sps)
else
pingOffset = 0;
#ifdef SWLOOPBACK
#ifdef SWLOOPBACK
samplePeriod = 1.0e6/actualSampleRate;
loopbackBufferSize = 0;
gettimeofday(&lastReadTime,NULL);
@@ -94,9 +93,9 @@ int USRPDevice::open(const std::string &, int, bool)
writeLock.unlock();
LOG(INFO) << "opening USRP device..";
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
string rbf = "std_inband.rbf";
//string rbf = "inband_1rxhb_1tx.rbf";
//string rbf = "inband_1rxhb_1tx.rbf";
m_uRx.reset();
if (!skipRx) {
try {
@@ -145,7 +144,7 @@ int USRPDevice::open(const std::string &, int, bool)
if (!skipRx) m_uRx->stop();
m_uTx->stop();
#endif
switch (dboardConfig) {
@@ -176,19 +175,19 @@ int USRPDevice::open(const std::string &, int, bool)
samplesRead = 0;
samplesWritten = 0;
started = false;
return NORMAL;
}
bool USRPDevice::start()
bool USRPDevice::start()
{
LOG(INFO) << "starting USRP...";
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
if (!m_uRx && !skipRx) return false;
if (!m_uTx) return false;
if (!skipRx) m_uRx->stop();
m_uTx->stop();
@@ -218,8 +217,8 @@ bool USRPDevice::start()
hi32Timestamp = 0;
isAligned = false;
if (!skipRx)
if (!skipRx)
started = (m_uRx->start() && m_uTx->start());
else
started = m_uTx->start();
@@ -230,14 +229,14 @@ bool USRPDevice::start()
#endif
}
bool USRPDevice::stop()
bool USRPDevice::stop()
{
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
if (!m_uRx) return false;
if (!m_uTx) return false;
delete[] currData;
started = !(m_uRx->stop() && m_uTx->stop());
return !started;
#else
@@ -258,7 +257,7 @@ double USRPDevice::minTxGain()
double USRPDevice::maxRxGain()
{
return m_dbRx->gain_max();
}
}
double USRPDevice::minRxGain()
{
@@ -314,28 +313,68 @@ double USRPDevice::setRxGain(double dB, size_t chan)
return dB;
}
bool USRPDevice::setRxAntenna(const std::string &ant, size_t chan)
{
if (chan >= rx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return false;
}
LOG(ALERT) << "Not implemented";
return true;
}
std::string USRPDevice::getRxAntenna(size_t chan)
{
if (chan >= rx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return "";
}
LOG(ALERT) << "Not implemented";
return "";
}
bool USRPDevice::setTxAntenna(const std::string &ant, size_t chan)
{
if (chan >= tx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return false;
}
LOG(ALERT) << "Not implemented";
return true;
}
std::string USRPDevice::getTxAntenna(size_t chan)
{
if (chan >= tx_paths.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return "";
}
LOG(ALERT) << "Not implemented";
return "";
}
// NOTE: Assumes sequential reads
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
if (!m_uRx)
return 0;
short *buf = bufs[0];
timestamp += timestampOffset;
if (timestamp + len < timeStart) {
memset(buf,0,len*2*sizeof(short));
return len;
}
if (underrun) *underrun = false;
uint32_t readBuf[2000];
while (1) {
//guestimate USB read size
int readLen=0;
@@ -345,7 +384,7 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
if (readLen > 8000) readLen= (8000/512)*512;
}
// read USRP packets, parse and save A/D data as needed
readLen = m_uRx->read((void *)readBuf,readLen,overrun);
for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
@@ -382,13 +421,13 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
continue;
}
if ((word0 >> 28) & 0x04) {
if (underrun) *underrun = true;
if (underrun) *underrun = true;
LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
}
if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
if (!isAligned) continue;
unsigned cursorStart = pktTimestamp - timeStart + dataStart;
while (cursorStart*2 > currDataSize) {
cursorStart -= currDataSize/2;
@@ -401,17 +440,17 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
else {
memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
}
if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
}
}
}
}
// copy desired data to buf
unsigned bufStart = dataStart+(timestamp-timeStart);
if (bufStart + len < currDataSize/2) {
if (bufStart + len < currDataSize/2) {
LOG(DEBUG) << "bufStart: " << bufStart;
memcpy(buf,data+bufStart*2,len*2*sizeof(short));
memset(data+bufStart*2,0,len*2*sizeof(short));
@@ -429,21 +468,21 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
timeStart = timestamp + len;
return len;
#else
if (loopbackBufferSize < 2) return 0;
int numSamples = 0;
struct timeval currTime;
gettimeofday(&currTime,NULL);
double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
(currTime.tv_usec - lastReadTime.tv_usec);
if (timeElapsed < samplePeriod) {return 0;}
int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
if (numSamplesToRead < len) return 0;
if (numSamplesToRead > len) numSamplesToRead = len;
if (numSamplesToRead > loopbackBufferSize/2) {
firstRead =false;
firstRead =false;
numSamplesToRead = loopbackBufferSize/2;
}
memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
@@ -461,7 +500,7 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
firstRead = true;
}
samplesRead += numSamples;
return numSamples;
#endif
}
@@ -472,7 +511,7 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
{
writeLock.lock();
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
if (!m_uTx)
return 0;
@@ -519,14 +558,14 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
samplesWritten += retVal;
loopbackBufferSize += retVal*2;
return retVal;
#endif
}
bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
{
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
short data[] = {0x00,0x02,0x00,0x00};
uint32_t *wordPtr = (uint32_t *) data;
*wordPtr = host_to_usrp_u32(*wordPtr);
@@ -543,7 +582,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
#endif
}
#ifndef SWLOOPBACK
#ifndef SWLOOPBACK
bool USRPDevice::setTxFreq(double wFreq, size_t chan)
{
usrp_tune_result result;
@@ -601,7 +640,9 @@ bool USRPDevice::setRxFreq(double wFreq) { return true;};
#endif
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
size_t chans, double)
InterfaceType iface, size_t chans, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths)
{
return new USRPDevice(tx_sps);
}

View File

@@ -83,10 +83,10 @@ private:
double rxGain;
#ifdef SWLOOPBACK
#ifdef SWLOOPBACK
short loopbackBuffer[1000000];
int loopbackBufferSize;
double samplePeriod;
double samplePeriod;
struct timeval startTime;
struct timeval lastReadTime;
@@ -179,6 +179,18 @@ private:
/** return minimum Rx Gain **/
double minTxGain(void);
/** sets the RX path to use, returns true if successful and false otherwise */
bool setRxAntenna(const std::string &ant, size_t chan = 0);
/* return the used RX path */
std::string getRxAntenna(size_t chan = 0);
/** sets the RX path to use, returns true if successful and false otherwise */
bool setTxAntenna(const std::string &ant, size_t chan = 0);
/* return the used RX path */
std::string getTxAntenna(size_t chan = 0);
/** Return internal status values */
inline double getTxFreq(size_t chan = 0) { return 0; }
inline double getRxFreq(size_t chan = 0) { return 0; }
@@ -186,7 +198,7 @@ private:
inline double numberRead() { return samplesRead; }
inline double numberWritten() { return samplesWritten; }
std::vector<std::string> tx_paths, rx_paths;
};
#endif // _USRP_DEVICE_H_

View File

@@ -28,6 +28,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 +57,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

@@ -27,10 +27,14 @@
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <GSMCommon.h>
#include <Logger.h>
#include <Configuration.h>
extern "C" {
#include "convolve.h"
@@ -61,7 +65,8 @@ extern "C" {
struct trx_config {
std::string log_level;
std::string addr;
std::string local_addr;
std::string remote_addr;
std::string dev_args;
unsigned port;
unsigned tx_sps;
@@ -77,10 +82,11 @@ struct trx_config {
double rssi_offset;
bool swap_channels;
bool edge;
int sched_rr;
std::vector<std::string> rx_paths;
std::vector<std::string> tx_paths;
};
ConfigurationTable gConfig;
volatile bool gshutdown = false;
/* Setup configuration values
@@ -93,6 +99,7 @@ volatile bool gshutdown = false;
bool trx_setup_config(struct trx_config *config)
{
std::string refstr, fillstr, divstr, mcstr, edgestr;
std::vector<std::string>::const_iterator si;
if (config->mcbts && config->chans > 5) {
std::cout << "Unsupported number of channels" << std::endl;
@@ -132,7 +139,8 @@ bool trx_setup_config(struct trx_config *config)
ost << " Log Level............... " << config->log_level << std::endl;
ost << " Device args............. " << config->dev_args << std::endl;
ost << " TRX Base Port........... " << config->port << std::endl;
ost << " TRX Address............. " << config->addr << std::endl;
ost << " TRX Address............. " << config->local_addr << std::endl;
ost << " GSM Core Address........." << config->remote_addr << std::endl;
ost << " Channels................ " << config->chans << std::endl;
ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl;
ost << " Rx Samples-per-Symbol... " << config->rx_sps << std::endl;
@@ -143,8 +151,16 @@ bool trx_setup_config(struct trx_config *config)
ost << " Tuning offset........... " << config->offset << std::endl;
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
ost << " Swap channels........... " << config->swap_channels << std::endl;
std::cout << ost << std::endl;
ost << " Tx Antennas.............";
for (si = config->tx_paths.begin(); si != config->tx_paths.end(); ++si)
ost << " '" << ((*si != "") ? *si : "<default>") << "'";
ost << std::endl;
ost << " Rx Antennas.............";
for (si = config->rx_paths.begin(); si != config->rx_paths.end(); ++si)
ost << " '" << ((*si != "") ? *si : "<default>") << "'";
ost << std::endl;
std::cout << ost << std::endl;
return true;
}
@@ -198,9 +214,10 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
Transceiver *trx;
VectorFIFO *fifo;
trx = new Transceiver(config->port, config->addr.c_str(),
config->tx_sps, config->rx_sps, config->chans,
GSM::Time(3,0), radio, config->rssi_offset);
trx = new Transceiver(config->port, config->local_addr.c_str(),
config->remote_addr.c_str(), config->tx_sps,
config->rx_sps, config->chans, GSM::Time(3,0),
radio, config->rssi_offset);
if (!trx->init(config->filler, config->rtsc,
config->rach_delay, config->edge)) {
LOG(ALERT) << "Failed to initialize transceiver";
@@ -239,6 +256,21 @@ static void setup_signal_handlers()
}
}
static std::vector<std::string> comma_delimited_to_vector(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;
}
static void print_help()
{
fprintf(stdout, "Options:\n"
@@ -246,6 +278,7 @@ static void print_help()
" -a UHD device args\n"
" -l Logging level (%s)\n"
" -i IP address of GSM core\n"
" -j IP address of osmo-trx\n"
" -p Base port number\n"
" -e Enable EDGE receiver\n"
" -m Enable multi-ARFCN transceiver (default=disabled)\n"
@@ -259,16 +292,21 @@ static void print_help()
" -r Random Normal Burst test mode with TSC\n"
" -A Random Access Burst test mode with delay\n"
" -R RSSI to dBm offset in dB (default=0)\n"
" -S Swap channels (UmTRX only)\n",
" -S Swap channels (UmTRX only)\n"
" -t SCHED_RR real-time priority (1..32)\n"
" -y comma-delimited list of Tx paths (num elements matches -c)\n"
" -z comma-delimited list of Rx paths (num elements matches -c)\n",
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
}
static void handle_options(int argc, char **argv, struct trx_config *config)
{
int option;
bool tx_path_set = false, rx_path_set = false;
config->log_level = "NOTICE";
config->addr = DEFAULT_TRX_IP;
config->local_addr = DEFAULT_TRX_IP;
config->remote_addr = DEFAULT_TRX_IP;
config->port = DEFAULT_TRX_PORT;
config->tx_sps = DEFAULT_TX_SPS;
config->rx_sps = DEFAULT_RX_SPS;
@@ -283,8 +321,11 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->rssi_offset = 0.0;
config->swap_channels = false;
config->edge = false;
config->sched_rr = -1;
config->tx_paths = std::vector<std::string>(DEFAULT_CHANS, "");
config->rx_paths = std::vector<std::string>(DEFAULT_CHANS, "");
while ((option = getopt(argc, argv, "ha:l:i:p:c:dmxgfo:s:b:r:A:R:Se")) != -1) {
while ((option = getopt(argc, argv, "ha:l:i:j:p:c:dmxgfo:s:b:r:A:R:Set:y:z:")) != -1) {
switch (option) {
case 'h':
print_help();
@@ -297,7 +338,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->log_level = optarg;
break;
case 'i':
config->addr = optarg;
config->remote_addr = optarg;
break;
case 'j':
config->local_addr = optarg;
break;
case 'p':
config->port = atoi(optarg);
@@ -343,6 +387,17 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
case 'e':
config->edge = true;
break;
case 't':
config->sched_rr = atoi(optarg);
break;
case 'y':
config->tx_paths = comma_delimited_to_vector(optarg);
tx_path_set = true;
break;
case 'z':
config->rx_paths = comma_delimited_to_vector(optarg);
rx_path_set = true;
break;
default:
print_help();
exit(0);
@@ -379,6 +434,19 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
goto bad_config;
}
if (!tx_path_set) {
config->tx_paths = std::vector<std::string>(config->chans, "");
} else if (config->tx_paths.size() != config->chans) {
printf("Num of channels and num of Tx Antennas doesn't match\n\n");
goto bad_config;
}
if (!rx_path_set) {
config->rx_paths = std::vector<std::string>(config->chans, "");
} else if (config->rx_paths.size() != config->chans) {
printf("Num of channels and num of Rx Antennas doesn't match\n\n");
goto bad_config;
}
return;
bad_config:
@@ -386,6 +454,21 @@ bad_config:
exit(0);
}
static int set_sched_rr(int prio)
{
struct sched_param param;
int rc;
memset(&param, 0, sizeof(param));
param.sched_priority = prio;
printf("Setting SCHED_RR priority(%d)\n", param.sched_priority);
rc = sched_setscheduler(getpid(), SCHED_RR, &param);
if (rc != 0) {
std::cerr << "Config: Setting SCHED_RR failed" << std::endl;
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int type, chans, ref;
@@ -397,18 +480,26 @@ int main(int argc, char *argv[])
#ifdef HAVE_SSE3
printf("Info: SSE3 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse3"))
printf(" and supported by CPU\n");
else
printf(", but not supported by CPU\n");
#else
printf(", but runtime SIMD detection disabled\n");
#endif
#endif
#ifdef HAVE_SSE4_1
printf("Info: SSE4.1 support compiled in");
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
if (__builtin_cpu_supports("sse4.1"))
printf(" and supported by CPU\n");
else
printf(", but not supported by CPU\n");
#else
printf(", but runtime SIMD detection disabled\n");
#endif
#endif
convolve_init();
@@ -416,6 +507,11 @@ int main(int argc, char *argv[])
handle_options(argc, argv, &config);
if (config.sched_rr != -1) {
if (set_sched_rr(config.sched_rr) < 0)
return EXIT_FAILURE;
}
setup_signal_handlers();
/* Check database sanity */
@@ -424,7 +520,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7);
gLogInit(config.log_level.c_str());
srandom(time(NULL));
@@ -440,7 +536,7 @@ int main(int argc, char *argv[])
ref = RadioDevice::REF_INTERNAL;
usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface,
config.chans, config.offset);
config.chans, config.offset, config.tx_paths, config.rx_paths);
type = usrp->open(config.dev_args, ref, config.swap_channels);
if (type < 0) {
LOG(ALERT) << "Failed to create radio device" << std::endl;

View File

@@ -50,7 +50,9 @@ class RadioDevice {
};
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;
@@ -136,6 +138,18 @@ class RadioDevice {
/** 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 internal status values */
virtual double getTxFreq(size_t chan = 0) = 0;
virtual double getRxFreq(size_t chan = 0) = 0;

View File

@@ -46,14 +46,10 @@ using namespace GSM;
#define CLIP_THRESH 30000.0f
/** Lookup tables for trigonometric approximation */
float cosTable[TABLESIZE+1]; // add 1 element for wrap around
float sinTable[TABLESIZE+1];
float sincTable[TABLESIZE+1];
static float sincTable[TABLESIZE+1]; // add 1 element for wrap around
/** Constants */
static const float M_PI_F = (float)M_PI;
static const float M_2PI_F = (float)(2.0*M_PI);
static const float M_1_2PI_F = 1/M_2PI_F;
/* Precomputed rotation vectors */
static signalVector *GMSKRotation4 = NULL;
@@ -64,7 +60,7 @@ static signalVector *GMSKReverseRotation1 = NULL;
/* Precomputed fractional delay filters */
static signalVector *delayFilters[DELAYFILTS];
static Complex<float> psk8_table[8] = {
static const Complex<float> psk8_table[8] = {
Complex<float>(-0.70710678, 0.70710678),
Complex<float>( 0.0, -1.0),
Complex<float>( 0.0, 1.0),
@@ -172,67 +168,7 @@ void sigProcLibDestroy()
GSMPulse4 = NULL;
}
// dB relative to 1.0.
// if > 1.0, then return 0 dB
float dB(float x) {
float arg = 1.0F;
float dB = 0.0F;
if (x >= 1.0F) return 0.0F;
if (x <= 0.0F) return -200.0F;
float prevArg = arg;
float prevdB = dB;
float stepSize = 16.0F;
float dBstepSize = 12.0F;
while (stepSize > 1.0F) {
do {
prevArg = arg;
prevdB = dB;
arg /= stepSize;
dB -= dBstepSize;
} while (arg > x);
arg = prevArg;
dB = prevdB;
stepSize *= 0.5F;
dBstepSize -= 3.0F;
}
return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
}
// 10^(-dB/10), inverse of dB func.
float dBinv(float x) {
float arg = 1.0F;
float dB = 0.0F;
if (x >= 0.0F) return 1.0F;
if (x <= -200.0F) return 0.0F;
float prevArg = arg;
float prevdB = dB;
float stepSize = 16.0F;
float dBstepSize = 12.0F;
while (stepSize > 1.0F) {
do {
prevArg = arg;
prevdB = dB;
arg /= stepSize;
dB -= dBstepSize;
} while (dB > x);
arg = prevArg;
dB = prevdB;
stepSize *= 0.5F;
dBstepSize -= 3.0F;
}
return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
}
float vectorNorm2(const signalVector &x)
static float vectorNorm2(const signalVector &x)
{
signalVector::const_iterator xPtr = x.begin();
float Energy = 0.0;
@@ -242,64 +178,6 @@ float vectorNorm2(const signalVector &x)
return Energy;
}
float vectorPower(const signalVector &x)
{
return vectorNorm2(x)/x.size();
}
/** compute cosine via lookup table */
float cosLookup(const float x)
{
float arg = x*M_1_2PI_F;
while (arg > 1.0F) arg -= 1.0F;
while (arg < 0.0F) arg += 1.0F;
const float argT = arg*((float)TABLESIZE);
const int argI = (int)argT;
const float delta = argT-argI;
const float iDelta = 1.0F-delta;
return iDelta*cosTable[argI] + delta*cosTable[argI+1];
}
/** compute sine via lookup table */
float sinLookup(const float x)
{
float arg = x*M_1_2PI_F;
while (arg > 1.0F) arg -= 1.0F;
while (arg < 0.0F) arg += 1.0F;
const float argT = arg*((float)TABLESIZE);
const int argI = (int)argT;
const float delta = argT-argI;
const float iDelta = 1.0F-delta;
return iDelta*sinTable[argI] + delta*sinTable[argI+1];
}
/** compute e^(-jx) via lookup table. */
static complex expjLookup(float x)
{
float arg = x*M_1_2PI_F;
while (arg > 1.0F) arg -= 1.0F;
while (arg < 0.0F) arg += 1.0F;
const float argT = arg*((float)TABLESIZE);
const int argI = (int)argT;
const float delta = argT-argI;
const float iDelta = 1.0F-delta;
return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
iDelta*sinTable[argI] + delta*sinTable[argI+1]);
}
/** Library setup functions */
static void initTrigTables() {
for (int i = 0; i < TABLESIZE+1; i++) {
cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
}
}
/*
* Initialize 4 sps and 1 sps rotation tables
*/
@@ -311,11 +189,11 @@ static void initGMSKRotationTables()
GMSKReverseRotation4 = new signalVector(len4);
signalVector::iterator rotPtr = GMSKRotation4->begin();
signalVector::iterator revPtr = GMSKReverseRotation4->begin();
float phase = 0.0;
auto phase = 0.0;
while (rotPtr != GMSKRotation4->end()) {
*rotPtr++ = expjLookup(phase);
*revPtr++ = expjLookup(-phase);
phase += M_PI_F / 2.0F / 4.0;
*rotPtr++ = complex(cos(phase), sin(phase));
*revPtr++ = complex(cos(-phase), sin(-phase));
phase += M_PI / 2.0 / 4.0;
}
GMSKRotation1 = new signalVector(len1);
@@ -324,9 +202,9 @@ static void initGMSKRotationTables()
revPtr = GMSKReverseRotation1->begin();
phase = 0.0;
while (rotPtr != GMSKRotation1->end()) {
*rotPtr++ = expjLookup(phase);
*revPtr++ = expjLookup(-phase);
phase += M_PI_F / 2.0F;
*rotPtr++ = complex(cos(phase), sin(phase));
*revPtr++ = complex(cos(-phase), sin(-phase));
phase += M_PI / 2.0;
}
}
@@ -401,11 +279,18 @@ static bool GMSKReverseRotate(signalVector &x, int sps)
return true;
}
signalVector *convolve(const signalVector *x,
const signalVector *h,
signalVector *y,
ConvType spanType, size_t start,
size_t len, size_t step, int offset)
/** Convolution type indicator */
enum ConvType {
START_ONLY,
NO_DELAY,
CUSTOM,
UNDEFINED,
};
static signalVector *convolve(const signalVector *x, const signalVector *h,
signalVector *y, ConvType spanType,
size_t start = 0, size_t len = 0,
size_t step = 1, int offset = 0)
{
int rc;
size_t head = 0, tail = 0;
@@ -654,29 +539,6 @@ static PulseSequence *generateGSMPulse(int sps)
return pulse;
}
signalVector* reverseConjugate(signalVector *b)
{
signalVector *tmp = new signalVector(b->size());
tmp->isReal(b->isReal());
signalVector::iterator bP = b->begin();
signalVector::iterator bPEnd = b->end();
signalVector::iterator tmpP = tmp->end()-1;
if (!b->isReal()) {
while (bP < bPEnd) {
*tmpP-- = bP->conj();
bP++;
}
}
else {
while (bP < bPEnd) {
*tmpP-- = bP->real();
bP++;
}
}
return tmp;
}
bool vectorSlicer(SoftVector *x)
{
SoftVector::iterator xP = x->begin();
@@ -696,7 +558,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
int guardPeriodLength, int sps)
{
int burst_len;
signalVector *pulse, rotated, *shaped;
signalVector *pulse, rotated;
signalVector::iterator itr;
pulse = GSMPulse1->empty;
@@ -713,11 +575,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
rotated.isReal(false);
/* Dummy filter operation */
shaped = convolve(&rotated, pulse, NULL, START_ONLY);
if (!shaped)
return NULL;
return shaped;
return convolve(&rotated, pulse, NULL, START_ONLY);
}
static void rotateBurst2(signalVector &burst, double phase)
@@ -737,8 +595,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
{
int burst_len, sps = 4;
float phase;
signalVector *c0_pulse, *c1_pulse, *c0_burst;
signalVector *c1_burst, *c0_shaped, *c1_shaped;
signalVector *c0_pulse, *c1_pulse, *c0_shaped, *c1_shaped;
signalVector::iterator c0_itr, c1_itr;
c0_pulse = GSMPulse4->c0;
@@ -749,13 +606,12 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
burst_len = 625;
c0_burst = new signalVector(burst_len, c0_pulse->size());
c0_burst->isReal(true);
c0_itr = c0_burst->begin();
signalVector c0_burst(burst_len, c0_pulse->size());
c0_burst.isReal(true);
c0_itr = c0_burst.begin();
c1_burst = new signalVector(burst_len, c1_pulse->size());
c1_burst->isReal(true);
c1_itr = c1_burst->begin();
signalVector c1_burst(burst_len, c1_pulse->size());
c1_itr = c1_burst.begin();
/* Padded differential tail bits */
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
@@ -771,10 +627,10 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
/* Generate C0 phase coefficients */
GMSKRotate(*c0_burst, sps);
c0_burst->isReal(false);
GMSKRotate(c0_burst, sps);
c0_burst.isReal(false);
c0_itr = c0_burst->begin();
c0_itr = c0_burst.begin();
c0_itr += sps * 2;
c1_itr += sps * 2;
@@ -799,8 +655,8 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
*c1_itr = *c0_itr * Complex<float>(0, phase);
/* Primary (C0) and secondary (C1) pulse shaping */
c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
/* Sum shaped outputs into C0 */
c0_itr = c0_shaped->begin();
@@ -808,10 +664,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
for (unsigned i = 0; i < c0_shaped->size(); i++ )
*c0_itr++ += *c1_itr++;
delete c0_burst;
delete c1_burst;
delete c1_shaped;
return c0_shaped;
}
@@ -885,7 +738,6 @@ static signalVector *mapEdgeSymbols(const BitVector &bits)
static signalVector *shapeEdgeBurst(const signalVector &symbols)
{
size_t nsyms, nsamps = 625, sps = 4;
signalVector *burst, *shape;
signalVector::iterator burst_itr;
nsyms = symbols.size();
@@ -893,10 +745,10 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
if (nsyms * sps > nsamps)
nsyms = 156;
burst = new signalVector(nsamps, GSMPulse4->c0->size());
signalVector burst(nsamps, GSMPulse4->c0->size());
/* Delay burst by 1 symbol */
burst_itr = burst->begin() + sps;
burst_itr = burst.begin() + sps;
for (size_t i = 0; i < nsyms; i++) {
float phase = i * 3.0f * M_PI / 8.0f;
Complex<float> rot = Complex<float>(cos(phase), sin(phase));
@@ -906,10 +758,7 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
}
/* Single Gaussian pulse approximation shaping */
shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
delete burst;
return shape;
return convolve(&burst, GSMPulse4->c0, NULL, START_ONLY);
}
/*
@@ -923,40 +772,36 @@ signalVector *genRandNormalBurst(int tsc, int sps, int tn)
return NULL;
int i = 0;
BitVector *bits = new BitVector(148);
signalVector *burst;
BitVector bits(148);
/* Tail bits */
for (; i < 3; i++)
(*bits)[i] = 0;
bits[i] = 0;
/* Random bits */
for (; i < 60; i++)
(*bits)[i] = rand() % 2;
bits[i] = rand() % 2;
/* Stealing bit */
(*bits)[i++] = 0;
bits[i++] = 0;
/* Training sequence */
for (int n = 0; i < 87; i++, n++)
(*bits)[i] = gTrainingSequence[tsc][n];
bits[i] = gTrainingSequence[tsc][n];
/* Stealing bit */
(*bits)[i++] = 0;
bits[i++] = 0;
/* Random bits */
for (; i < 145; i++)
(*bits)[i] = rand() % 2;
bits[i] = rand() % 2;
/* Tail bits */
for (; i < 148; i++)
(*bits)[i] = 0;
bits[i] = 0;
int guard = 8 + !(tn % 4);
burst = modulateBurst(*bits, guard, sps);
delete bits;
return burst;
return modulateBurst(bits, guard, sps);
}
/*
@@ -972,30 +817,26 @@ signalVector *genRandAccessBurst(int delay, int sps, int tn)
return NULL;
int i = 0;
BitVector *bits = new BitVector(88+delay);
signalVector *burst;
BitVector bits(88 + delay);
/* delay */
for (; i < delay; i++)
(*bits)[i] = 0;
bits[i] = 0;
/* head and synch bits */
for (int n = 0; i < 49+delay; i++, n++)
(*bits)[i] = gRACHBurst[n];
bits[i] = gRACHBurst[n];
/* Random bits */
for (; i < 85+delay; i++)
(*bits)[i] = rand() % 2;
bits[i] = rand() % 2;
/* Tail bits */
for (; i < 88+delay; i++)
(*bits)[i] = 0;
bits[i] = 0;
int guard = 68-delay + !(tn % 4);
burst = modulateBurst(*bits, guard, sps);
delete bits;
return burst;
return modulateBurst(bits, guard, sps);
}
signalVector *generateEmptyBurst(int sps, int tn)
@@ -1032,17 +873,17 @@ signalVector *generateEdgeBurst(int tsc)
if ((tsc < 0) || (tsc > 7))
return NULL;
signalVector *shape, *burst = new signalVector(148);
signalVector burst(148);
const BitVector *midamble = &gEdgeTrainingSequence[tsc];
/* Tail */
int n, i = 0;
for (; i < tail; i++)
(*burst)[i] = psk8_table[7];
burst[i] = psk8_table[7];
/* Body */
for (; i < tail + data; i++)
(*burst)[i] = psk8_table[rand() % 8];
burst[i] = psk8_table[rand() % 8];
/* TSC */
for (n = 0; i < tail + data + train; i++, n++) {
@@ -1050,21 +891,18 @@ signalVector *generateEdgeBurst(int tsc)
(((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
(((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
(*burst)[i] = psk8_table[index];
burst[i] = psk8_table[index];
}
/* Body */
for (; i < tail + data + train + data; i++)
(*burst)[i] = psk8_table[rand() % 8];
burst[i] = psk8_table[rand() % 8];
/* Tail */
for (; i < tail + data + train + data + tail; i++)
(*burst)[i] = psk8_table[7];
burst[i] = psk8_table[7];
shape = shapeEdgeBurst(*burst);
delete burst;
return shape;
return shapeEdgeBurst(burst);
}
/*
@@ -1100,7 +938,7 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
int guard_len, int sps)
{
int burst_len;
signalVector *pulse, *burst, *shaped;
signalVector *pulse;
signalVector::iterator burst_itr;
if (sps == 1)
@@ -1110,9 +948,9 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
burst_len = sps * (bits.size() + guard_len);
burst = new signalVector(burst_len, pulse->size());
burst->isReal(true);
burst_itr = burst->begin();
signalVector burst(burst_len, pulse->size());
burst.isReal(true);
burst_itr = burst.begin();
/* Raw bits are not differentially encoded */
for (unsigned i = 0; i < bits.size(); i++) {
@@ -1120,15 +958,11 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
burst_itr += sps;
}
GMSKRotate(*burst, sps);
burst->isReal(false);
GMSKRotate(burst, sps);
burst.isReal(false);
/* Single Gaussian pulse approximation shaping */
shaped = convolve(burst, pulse, NULL, START_ONLY);
delete burst;
return shaped;
return convolve(&burst, pulse, NULL, START_ONLY);
}
/* Assume input bits are not differentially encoded */
@@ -1145,20 +979,14 @@ signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
static void generateSincTable()
{
float x;
for (int i = 0; i < TABLESIZE; i++) {
x = (float) i / TABLESIZE * 8 * M_PI;
if (fabs(x) < 0.01) {
sincTable[i] = 1.0f;
continue;
}
sincTable[i] = sinf(x) / x;
auto x = (double) i / TABLESIZE * 8 * M_PI;
auto y = sin(x) / x;
sincTable[i] = std::isnan(y) ? 1.0 : y;
}
}
float sinc(float x)
static float sinc(float x)
{
if (fabs(x) >= 8 * M_PI)
return 0.0;
@@ -1173,7 +1001,7 @@ float sinc(float x)
* sinc function generator. The number of filters generated is specified
* by the DELAYFILTS value.
*/
void generateDelayFilters()
static void generateDelayFilters()
{
int h_len = 20;
complex *data;
@@ -1268,31 +1096,8 @@ signalVector *delayVector(const signalVector *in, signalVector *out, float delay
return out;
}
signalVector *gaussianNoise(int length,
float variance,
complex mean)
static complex interpolatePoint(const signalVector &inSig, float ix)
{
signalVector *noise = new signalVector(length);
signalVector::iterator nPtr = noise->begin();
float stddev = sqrtf(variance);
while (nPtr < noise->end()) {
float u1 = (float) rand()/ (float) RAND_MAX;
while (u1==0.0)
u1 = (float) rand()/ (float) RAND_MAX;
float u2 = (float) rand()/ (float) RAND_MAX;
float arg = 2.0*M_PI*u2;
*nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
nPtr++;
}
return noise;
}
complex interpolatePoint(const signalVector &inSig,
float ix)
{
int start = (int) (floor(ix) - 10);
if (start < 0) start = 0;
int end = (int) (floor(ix) + 11);
@@ -1332,12 +1137,9 @@ static complex fastPeakDetect(const signalVector &rxBurst, float *index)
return amp;
}
complex peakDetect(const signalVector &rxBurst,
float *peakIndex,
float *avgPwr)
static complex peakDetect(const signalVector &rxBurst,
float *peakIndex, float *avgPwr)
{
complex maxVal = 0.0;
float maxIndex = -1;
float sumPower = 0.0;
@@ -1410,7 +1212,7 @@ void scaleVector(signalVector &x,
}
/** in-place conjugation */
void conjugateVector(signalVector &x)
static void conjugateVector(signalVector &x)
{
if (x.isReal()) return;
signalVector::iterator xP = x.begin();
@@ -1421,37 +1223,6 @@ void conjugateVector(signalVector &x)
}
}
// in-place addition!!
bool addVector(signalVector &x,
signalVector &y)
{
signalVector::iterator xP = x.begin();
signalVector::iterator yP = y.begin();
signalVector::iterator xPEnd = x.end();
signalVector::iterator yPEnd = y.end();
while ((xP < xPEnd) && (yP < yPEnd)) {
*xP = *xP + *yP;
xP++; yP++;
}
return true;
}
// in-place multiplication!!
bool multVector(signalVector &x,
signalVector &y)
{
signalVector::iterator xP = x.begin();
signalVector::iterator yP = y.begin();
signalVector::iterator xPEnd = x.end();
signalVector::iterator yPEnd = y.end();
while ((xP < xPEnd) && (yP < yPEnd)) {
*xP = (*xP) * (*yP);
xP++; yP++;
}
return true;
}
static bool generateMidamble(int sps, int tsc)
{
bool status = true;
@@ -1528,7 +1299,7 @@ release:
return status;
}
CorrelationSequence *generateEdgeMidamble(int tsc)
static CorrelationSequence *generateEdgeMidamble(int tsc)
{
complex *data = NULL;
signalVector *midamble = NULL, *_midamble = NULL;
@@ -1682,6 +1453,21 @@ float energyDetect(const signalVector &rxBurst, unsigned windowLength)
return energy/windowLength;
}
static signalVector *downsampleBurst(const signalVector &burst)
{
signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
memcpy(in.begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
(float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
delete out;
out = NULL;
}
return out;
};
/*
* Detect a burst based on correlation and peak-to-average ratio
*
@@ -1771,7 +1557,6 @@ static int detectGeneralBurst(const signalVector &rxBurst,
{
int rc, start, len;
bool clipping = false;
signalVector *corr;
if ((sps != 1) && (sps != 4))
return -SIGERR_UNSUPPORTED;
@@ -1787,12 +1572,10 @@ static int detectGeneralBurst(const signalVector &rxBurst,
start = target - head - 1;
len = head + tail;
corr = new signalVector(len);
signalVector corr(len);
rc = detectBurst(rxBurst, *corr, sync,
rc = detectBurst(rxBurst, corr, sync,
thresh, sps, &amp, &toa, start, len);
delete corr;
if (rc < 0) {
return -SIGERR_INTERNAL;
} else if (!rc) {
@@ -1816,12 +1599,8 @@ static int detectGeneralBurst(const signalVector &rxBurst,
* head: Search 8 symbols before target
* tail: Search 8 symbols + maximum expected delay
*/
int detectRACHBurst(const signalVector &burst,
float threshold,
int sps,
complex &amplitude,
float &toa,
unsigned max_toa)
static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
complex &amplitude, float &toa, unsigned max_toa)
{
int rc, target, head, tail;
CorrelationSequence *sync;
@@ -1845,8 +1624,8 @@ int detectRACHBurst(const signalVector &burst,
* head: Search 6 symbols before target
* tail: Search 6 symbols + maximum expected delay
*/
int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
int sps, complex &amplitude, float &toa, unsigned max_toa)
static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
int sps, complex &amplitude, float &toa, unsigned max_toa)
{
int rc, target, head, tail;
CorrelationSequence *sync;
@@ -1864,8 +1643,8 @@ int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold
return rc;
}
int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
int sps, complex &amplitude, float &toa, unsigned max_toa)
static int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
int sps, complex &amplitude, float &toa, unsigned max_toa)
{
int rc, target, head, tail;
CorrelationSequence *sync;
@@ -1915,41 +1694,6 @@ int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
return rc;
}
signalVector *downsampleBurst(const signalVector &burst)
{
signalVector *in, *out;
in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
out = new signalVector(DOWNSAMPLE_OUT_LEN);
memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
if (dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
(float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
delete out;
out = NULL;
}
delete in;
return out;
};
signalVector *decimateVector(signalVector &wVector, size_t factor)
{
signalVector *dec;
if (factor <= 1)
return NULL;
dec = new signalVector(wVector.size() / factor);
dec->isReal(wVector.isReal());
signalVector::iterator itr = dec->begin();
for (size_t i = 0; i < wVector.size(); i += factor)
*itr++ = wVector[i];
return dec;
}
/*
* Soft 8-PSK decoding using Manhattan distance metric
*/
@@ -2046,8 +1790,8 @@ static signalVector *demodCommon(const signalVector &burst, int sps,
* 4 SPS (if activated) to minimize distortion through the fractional
* delay filters. Symbol rotation and after always operates at 1 SPS.
*/
SoftVector *demodGmskBurst(const signalVector &rxBurst, int sps,
complex channel, float TOA)
static SoftVector *demodGmskBurst(const signalVector &rxBurst,
int sps, complex channel, float TOA)
{
SoftVector *bits;
signalVector *dec;
@@ -2075,8 +1819,8 @@ SoftVector *demodGmskBurst(const signalVector &rxBurst, int sps,
* through the fractional delay filters at 1 SPS renders signal
* nearly unrecoverable.
*/
SoftVector *demodEdgeBurst(const signalVector &burst, int sps,
complex chan, float toa)
static SoftVector *demodEdgeBurst(const signalVector &burst,
int sps, complex chan, float toa)
{
SoftVector *bits;
signalVector *dec, *rot, *eq;
@@ -2110,7 +1854,6 @@ SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
bool sigProcLibSetup()
{
initTrigTables();
generateSincTable();
initGMSKRotationTables();
@@ -2137,26 +1880,3 @@ fail:
sigProcLibDestroy();
return false;
}
std::string corrTypeToString(CorrType corr) {
switch (corr) {
case OFF:
return "OFF";
case TSC:
return "TSC";
case RACH:
return "RACH";
case EDGE:
return "EDGE";
case IDLE:
return "IDLE";
default:
return "unknown";
}
}
std::ostream& operator<<(std::ostream& os, CorrType corr)
{
os << corrTypeToString(corr);
return os;
}

View File

@@ -25,14 +25,6 @@
#define EDGE_BURST_NBITS 444
#define EDGE_BURST_NSYMS (EDGE_BURST_NBITS / 3)
/** Convolution type indicator */
enum ConvType {
START_ONLY,
NO_DELAY,
CUSTOM,
UNDEFINED,
};
/** Codes for burst types of received bursts*/
enum CorrType{
OFF, ///< timeslot is off
@@ -41,8 +33,6 @@ enum CorrType{
EDGE, ///< timeslot should contain an EDGE burst
IDLE ///< timeslot is an idle (or dummy) burst
};
std::string corrTypeToString(CorrType corr);
std::ostream& operator<<(std::ostream& os, CorrType corr);
enum SignalError {
SIGERR_NONE,
@@ -61,66 +51,12 @@ enum SignalError {
*/
#define BURST_THRESH 4.0
/** Convert a linear number to a dB value */
float dB(float x);
/** Convert a dB value into a linear value */
float dBinv(float x);
/** Compute the energy of a vector */
float vectorNorm2(const signalVector &x);
/** Compute the average power of a vector */
float vectorPower(const signalVector &x);
/** Setup the signal processing library */
bool sigProcLibSetup();
/** Destroy the signal processing library */
void sigProcLibDestroy(void);
/**
Convolve two vectors.
@param a,b The vectors to be convolved.
@param c, A preallocated vector to hold the convolution result.
@param spanType The type/span of the convolution.
@return The convolution result or NULL on error.
*/
signalVector *convolve(const signalVector *a, const signalVector *b,
signalVector *c, ConvType spanType,
size_t start = 0, size_t len = 0,
size_t step = 1, int offset = 0);
/**
Frequency shift a vector.
@param y The frequency shifted vector.
@param x The vector to-be-shifted.
@param freq The digital frequency shift
@param startPhase The starting phase of the oscillator
@param finalPhase The final phase of the oscillator
@return The frequency shifted vector.
*/
signalVector* frequencyShift(signalVector *y,
signalVector *x,
float freq = 0.0,
float startPhase = 0.0,
float *finalPhase=NULL);
/**
Correlate two vectors.
@param a,b The vectors to be correlated.
@param c, A preallocated vector to hold the correlation result.
@param spanType The type/span of the correlation.
@return The correlation result.
*/
signalVector* correlate(signalVector *a,
signalVector *b,
signalVector *c,
ConvType spanType,
bool bReversedConjugated = false,
unsigned startIx = 0,
unsigned len = 0);
/** Operate soft slicer on a soft-bit vector */
bool vectorSlicer(SoftVector *x);
@@ -148,45 +84,6 @@ signalVector *genRandAccessBurst(int delay, int sps, int tn);
/** Generate a dummy GSM burst - 4 or 1 SPS */
signalVector *generateDummyBurst(int sps, int tn);
/** Sinc function */
float sinc(float x);
/** Delay a vector */
signalVector *delayVector(const signalVector *in, signalVector *out, float delay);
/** Add two vectors in-place */
bool addVector(signalVector &x,
signalVector &y);
/** Multiply two vectors in-place*/
bool multVector(signalVector &x,
signalVector &y);
/** Generate a vector of gaussian noise */
signalVector *gaussianNoise(int length,
float variance = 1.0,
complex mean = complex(0.0));
/**
Given a non-integer index, interpolate a sample.
@param inSig The signal from which to interpolate.
@param ix The index.
@return The interpolated signal value.
*/
complex interpolatePoint(const signalVector &inSig,
float ix);
/**
Given a correlator output, locate the correlation peak.
@param rxBurst The correlator result.
@param peakIndex Pointer to value to receive interpolated peak index.
@param avgPower Power to value to receive mean power.
@return Peak value.
*/
complex peakDetect(const signalVector &rxBurst,
float *peakIndex,
float *avgPwr);
/**
Apply a scalar to a vector.
@param x The vector of interest.
@@ -203,68 +100,6 @@ void scaleVector(signalVector &x,
*/
float energyDetect(const signalVector &rxBurst,
unsigned windowLength);
/**
RACH aka Access Burst correlator/detector.
@param burst The received GSM burst of interest.
@param threshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
@param sps The number of samples per GSM symbol.
@param amplitude The estimated amplitude of received RACH burst.
@param toa The estimate time-of-arrival of received RACH burst.
@param max_toa The maximum expected time-of-arrival
@return 1 if threshold value is reached,
negative value (-SignalError) on error,
zero (SIGERR_NONE) if no burst is detected
*/
int detectRACHBurst(const signalVector &burst,
float threshold,
int sps,
complex &amplitude,
float &toa,
unsigned max_toa);
/**
GMSK Normal Burst correlator/detector.
@param rxBurst The received GSM burst of interest.
@param tsc Midamble type (0..7) also known as TSC
@param threshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
@param sps The number of samples per GSM symbol.
@param amplitude The estimated amplitude of received TSC burst.
@param toa The estimate time-of-arrival of received TSC burst.
@param max_toa The maximum expected time-of-arrival
@return 1 if threshold value is reached,
negative value (-SignalError) on error,
zero (SIGERR_NONE) if no burst is detected
*/
int analyzeTrafficBurst(const signalVector &burst,
unsigned tsc,
float threshold,
int sps,
complex &amplitude,
float &toa,
unsigned max_toa);
/**
EDGE/8-PSK Normal Burst correlator/detector
@param burst The received GSM burst of interest
@param tsc Midamble type (0..7) also known as TSC
@param threshold The threshold that the received burst's post-correlator SNR is compared against to determine validity.
@param sps The number of samples per GSM symbol.
@param amplitude The estimated amplitude of received TSC burst.
@param toa The estimate time-of-arrival of received TSC burst.
@param max_toa The maximum expected time-of-arrival
@return 1 if threshold value is reached,
negative value (-SignalError) on error,
zero (SIGERR_NONE) if no burst is detected
*/
int detectEdgeBurst(const signalVector &burst,
unsigned tsc,
float threshold,
int sps,
complex &amplitude,
float &toa,
unsigned max_toa);
/**
8-PSK/GMSK/RACH burst detector
@param burst The received GSM burst of interest
@@ -287,44 +122,6 @@ int detectAnyBurst(const signalVector &burst,
float &toa,
unsigned max_toa);
/**
Downsample 4 SPS to 1 SPS using a polyphase filterbank
@param burst Input burst of at least 624 symbols
@return Decimated signal vector of 156 symbols
*/
signalVector *downsampleBurst(const signalVector &burst);
/**
Decimate a vector.
@param wVector The vector of interest.
@param factor Decimation factor.
@return The decimated signal vector.
*/
signalVector *decimateVector(signalVector &wVector, size_t factor);
/**
Demodulates a GMSK burst using a soft-slicer.
@param rxBurst The burst to be demodulated.
@param gsmPulse The GSM pulse.
@param sps The number of samples per GSM symbol.
@param channel The amplitude estimate of the received burst.
@param TOA The time-of-arrival of the received burst.
@return The demodulated bit sequence.
*/
SoftVector *demodGmskBurst(const signalVector &rxBurst, int sps,
complex channel, float TOA);
/**
Demodulate 8-PSK EDGE burst with soft symbol ooutput
@param rxBurst The burst to be demodulated.
@param sps The number of samples per GSM symbol.
@param channel The amplitude estimate of the received burst.
@param TOA The time-of-arrival of the received burst.
@return The demodulated bit sequence.
*/
SoftVector *demodEdgeBurst(const signalVector &rxBurst, int sps,
complex channel, float TOA);
/** Demodulate burst basde on type and output soft bits */
SoftVector *demodAnyBurst(const signalVector &burst, int sps,
complex amp, float toa, CorrType type);

View File

@@ -46,6 +46,7 @@ void convert_init(void)
c.convert_si16_ps_16n = base_convert_short_float;
c.convert_si16_ps = base_convert_short_float;
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
#ifdef HAVE_SSE4_1
if (__builtin_cpu_supports("sse4.1")) {
c.convert_si16_ps_16n = &_sse_convert_si16_ps_16n;
@@ -60,6 +61,7 @@ void convert_init(void)
c.convert_scale_ps_si16 = _sse_convert_scale_ps_si16;
}
#endif
#endif
}
void convert_float_short(short *out, const float *in, float scale, int len)

View File

@@ -82,7 +82,7 @@ void convolve_init(void)
c.conv_real4n = (void *)_base_convolve_real;
c.conv_real = (void *)_base_convolve_real;
#ifdef HAVE_SSE3
#if defined(HAVE_SSE3) && defined(HAVE___BUILTIN_CPU_SUPPORTS)
if (__builtin_cpu_supports("sse3")) {
c.conv_cmplx_4n = sse_conv_cmplx_4n;
c.conv_cmplx_8n = sse_conv_cmplx_8n;

View File

@@ -0,0 +1,982 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 7
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AX_REQUIRE_DEFINED([AC_MSG_WARN])
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
if test x$ac_success = xyes; then
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
fi
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual void f() {}
};
struct Derived : public Base
{
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus <= 201402L
#error "This is not a C++17 compiler"
#else
#if defined(__clang__)
#define REALLY_CLANG
#else
#if defined(__GNUC__)
#define REALLY_GCC
#endif
#endif
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
#if !defined(REALLY_CLANG)
namespace test_constexpr_lambdas
{
// TODO: test it with clang++ from git
constexpr int foo = [](){return 42;}();
}
#endif // !defined(REALLY_CLANG)
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
#if !defined(REALLY_CLANG)
namespace test_template_argument_deduction_for_class_templates
{
// TODO: test it with clang++ from git
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
#endif // !defined(REALLY_CLANG)
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
#if !defined(REALLY_CLANG)
namespace test_structured_bindings
{
// TODO: test it with clang++ from git
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
#endif // !defined(REALLY_CLANG)
#if !defined(REALLY_CLANG)
namespace test_exception_spec_type_system
{
// TODO: test it with clang++ from git
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
#endif // !defined(REALLY_CLANG)
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus <= 201402L
]])

View File

@@ -0,0 +1,39 @@
# =============================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# =============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXX and CXXCPP to enable
# support.
#
# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
# macro with the version set to C++11. The two optional arguments are
# forwarded literally as the second and third argument respectively.
# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
# more information. If you want to use this macro, you also need to
# download the ax_cxx_compile_stdcxx.m4 file.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 18
AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])

View File

@@ -1,79 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_x86_avx_xgetbv.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_X86_AVX_XGETBV
#
# DESCRIPTION
#
# On later x86 processors with AVX SIMD support, with gcc or a compiler
# that has a compatible syntax for inline assembly instructions, run a
# small program that executes the xgetbv instruction with input OP. This
# can be used to detect if the OS supports AVX instruction usage.
#
# On output, the values of the eax and edx registers are stored as
# hexadecimal strings as "eax:edx" in the cache variable
# ax_cv_gcc_x86_avx_xgetbv.
#
# If the xgetbv instruction fails (because you are running a
# cross-compiler, or because you are not using gcc, or because you are on
# a processor that doesn't have this instruction),
# ax_cv_gcc_x86_avx_xgetbv_OP is set to the string "unknown".
#
# This macro mainly exists to be used in AX_EXT.
#
# LICENSE
#
# Copyright (c) 2013 Michael Petch <mpetch@capp-sysware.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 1
AC_DEFUN([AX_GCC_X86_AVX_XGETBV],
[AC_REQUIRE([AC_PROG_CC])
AC_LANG_PUSH([C])
AC_CACHE_CHECK(for x86-AVX xgetbv $1 output, ax_cv_gcc_x86_avx_xgetbv_$1,
[AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
int op = $1, eax, edx;
FILE *f;
/* Opcodes for xgetbv */
__asm__(".byte 0x0f, 0x01, 0xd0"
: "=a" (eax), "=d" (edx)
: "c" (op));
f = fopen("conftest_xgetbv", "w"); if (!f) return 1;
fprintf(f, "%x:%x\n", eax, edx);
fclose(f);
return 0;
])],
[ax_cv_gcc_x86_avx_xgetbv_$1=`cat conftest_xgetbv`; rm -f conftest_xgetbv],
[ax_cv_gcc_x86_avx_xgetbv_$1=unknown; rm -f conftest_xgetbv],
[ax_cv_gcc_x86_avx_xgetbv_$1=unknown])])
AC_LANG_POP([C])
])

View File

@@ -1,79 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_X86_CPUID(OP)
#
# DESCRIPTION
#
# On Pentium and later x86 processors, with gcc or a compiler that has a
# compatible syntax for inline assembly instructions, run a small program
# that executes the cpuid instruction with input OP. This can be used to
# detect the CPU type.
#
# On output, the values of the eax, ebx, ecx, and edx registers are stored
# as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable
# ax_cv_gcc_x86_cpuid_OP.
#
# If the cpuid instruction fails (because you are running a
# cross-compiler, or because you are not using gcc, or because you are on
# a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP
# is set to the string "unknown".
#
# This macro mainly exists to be used in AX_GCC_ARCHFLAG.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2008 Matteo Frigo
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AC_DEFUN([AX_GCC_X86_CPUID],
[AC_REQUIRE([AC_PROG_CC])
AC_LANG_PUSH([C])
AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1,
[AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
int op = $1, eax, ebx, ecx, edx;
FILE *f;
__asm__("cpuid"
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
: "a" (op));
f = fopen("conftest_cpuid", "w"); if (!f) return 1;
fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
fclose(f);
return 0;
])],
[ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid],
[ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid],
[ax_cv_gcc_x86_cpuid_$1=unknown])])
AC_LANG_POP([C])
])

View File

@@ -4,14 +4,13 @@
#
# SYNOPSIS
#
# AX_EXT
# AX_SSE
#
# DESCRIPTION
#
# Find supported SIMD extensions by requesting cpuid. When an SIMD
# extension is found, the -m"simdextensionname" is added to SIMD_FLAGS if
# compiler supports it. For example, if "sse2" is available, then "-msse2"
# is added to SIMD_FLAGS.
# Find SIMD extensions supported by compiler. The -m"simdextensionname" is
# added to SIMD_FLAGS if compiler supports it. For example, if "sse2" is
# available, then "-msse2" is added to SIMD_FLAGS.
#
# This macro calls:
#
@@ -19,7 +18,7 @@
#
# And defines:
#
# HAVE_MMX / HAVE_SSE / HAVE_SSE2 / HAVE_SSE3 / HAVE_SSSE3 / HAVE_SSE4.1 / HAVE_SSE4.2 / HAVE_AVX
# HAVE_SSE3 / HAVE_SSE4.1
#
# LICENSE
#
@@ -41,32 +40,29 @@ AC_DEFUN([AX_SSE],
[
AC_REQUIRE([AC_CANONICAL_HOST])
AM_CONDITIONAL(HAVE_SSE3, false)
AM_CONDITIONAL(HAVE_SSE4_1, false)
case $host_cpu in
i[[3456]]86*|x86_64*|amd64*)
AC_REQUIRE([AX_GCC_X86_CPUID])
AC_REQUIRE([AX_GCC_X86_AVX_XGETBV])
AX_GCC_X86_CPUID(0x00000001)
AX_CHECK_COMPILE_FLAG(-msse3, ax_cv_support_sse3_ext=yes, [])
if test x"$ax_cv_support_sse3_ext" = x"yes"; then
SIMD_FLAGS="$SIMD_FLAGS -msse3"
AC_DEFINE(HAVE_SSE3,,[Support SSE3 (Streaming SIMD Extensions 3) instructions])
AM_CONDITIONAL(HAVE_SSE3, true)
AC_DEFINE(HAVE_SSE3,,
[Support SSE3 (Streaming SIMD Extensions 3) instructions])
AM_CONDITIONAL(HAVE_SSE3, true)
else
AC_MSG_WARN([Your compiler does not support sse3 instructions, can you try another compiler?])
AM_CONDITIONAL(HAVE_SSE3, false)
AC_MSG_WARN([Your compiler does not support SSE3 instructions])
fi
AX_CHECK_COMPILE_FLAG(-msse4.1, ax_cv_support_sse41_ext=yes, [])
if test x"$ax_cv_support_sse41_ext" = x"yes"; then
SIMD_FLAGS="$SIMD_FLAGS -msse4.1"
AC_DEFINE(HAVE_SSE4_1,,[Support SSE4.1 (Streaming SIMD Extensions 4.1) instructions])
AM_CONDITIONAL(HAVE_SSE4_1, true)
AC_DEFINE(HAVE_SSE4_1,,
[Support SSE4.1 (Streaming SIMD Extensions 4.1) instructions])
AM_CONDITIONAL(HAVE_SSE4_1, true)
else
AC_MSG_WARN([Your compiler does not support sse4.1 instructions, can you try another compiler?])
AM_CONDITIONAL(HAVE_SSE4_1, false)
AC_MSG_WARN([Your compiler does not support SSE4.1])
fi
;;
esac

View File

@@ -18,12 +18,15 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
dnl
AC_INIT(openbts,P2.8TRUNK)
AC_INIT([osmo-trx],
m4_esyscmd([./git-version-gen .tarball-veresion]),
[openbsc@lists.osmocom.org])
AC_PREREQ(2.57)
AC_CONFIG_SRCDIR([Transceiver52M/Makefile.am])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([config])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_TESTDIR(tests)
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
@@ -34,13 +37,25 @@ AM_INIT_AUTOMAKE([subdir-objects])
dnl Linux kernel KBuild style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
AM_PROG_AS
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_11
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm])
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
AC_MSG_WARN([You need to install pkg-config])
fi
PKG_PROG_PKG_CONFIG([0.20])
AC_LIBTOOL_WIN32_DLL
AC_ENABLE_SHARED dnl do build shared libraries
AC_DISABLE_STATIC dnl don't build static libraries
@@ -105,7 +120,6 @@ AS_IF([test "x$with_usrp1" != "xyes"],[
)]
)
AC_DEFINE(USE_UHD, 1, All UHD versions)
PKG_CHECK_MODULES(FFTWF, fftw3f)
])
AS_IF([test "x$with_singledb" = "xyes"], [
@@ -120,14 +134,39 @@ AS_IF([test "x$with_sse" != "xno"], [
AM_CONDITIONAL(HAVE_SSE4_1, false)
])
dnl Check if the compiler supports specified GCC's built-in function
AC_DEFUN([CHECK_BUILTIN_SUPPORT], [
AC_CACHE_CHECK(
[whether ${CC} has $1 built-in],
[osmo_cv_cc_has_builtin], [
AC_LINK_IFELSE([
AC_LANG_PROGRAM([], [
__builtin_cpu_supports("sse");
])
],
[AS_VAR_SET([osmo_cv_cc_has_builtin], [yes])],
[AS_VAR_SET([osmo_cv_cc_has_builtin], [no])])
]
)
AS_IF([test yes = AS_VAR_GET([osmo_cv_cc_has_builtin])], [
AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1,
[Define to 1 if compiler has the '$1' built-in function])
], [
AC_MSG_WARN($2)
])
])
dnl Check if the compiler supports runtime SIMD detection
CHECK_BUILTIN_SUPPORT([__builtin_cpu_supports],
[Runtime SIMD detection will be disabled])
AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])
AC_CHECK_LIB(sqlite3, sqlite3_open, , AC_MSG_ERROR(sqlite3 is not available))
PKG_CHECK_MODULES(LIBUSB, libusb-1.0)
PKG_CHECK_MODULES(SQLITE3, sqlite3)
PKG_CHECK_MODULES(FFTWF, fftw3f)
AC_CHECK_HEADER([boost/config.hpp],[],
[AC_MSG_ERROR([boost/config.hpp not found, install e.g. libboost-dev])])
@@ -140,6 +179,9 @@ AC_CONFIG_FILES([\
Transceiver52M/Makefile \
Transceiver52M/arm/Makefile \
Transceiver52M/x86/Makefile \
tests/Makefile \
tests/CommonLibs/Makefile \
tests/Transceiver52M/Makefile \
])
AC_OUTPUT

View File

@@ -1,7 +1,63 @@
#!/bin/sh
set -ex
substr() { [ -z "${2##*$1*}" ]; }
#apt-get install qemu qemu-user-static qemu-system-arm debootstrap fakeroot proot
mychroot_nocwd() {
# LC_ALL + LANGUAGE set to avoid lots of print errors due to locale not being set inside container
# PATH is needed to be able to reach binaries like ldconfig without logging in to root, which adds the paths to PATH.
# PROOT_NO_SECCOMP is requried due to proot bug #106
LC_ALL=C LANGUAGE=C PATH="$PATH:/usr/sbin:/sbin" PROOT_NO_SECCOMP=1 proot -r "$ROOTFS" -w / -b /proc --root-id -q qemu-arm-static "$@"
}
mychroot() {
mychroot_nocwd -w / "$@"
}
if [ -z "${INSIDE_CHROOT}" ]; then
osmo-clean-workspace.sh
# Only use ARM chroot if host is not ARM and the target is ARM:
if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then
OSMOTRX_DIR="$PWD" # we assume we are called as contrib/jenkins.sh
ROOTFS_PREFIX="${ROOTFS_PREFIX:-/opt}"
ROOTFS="${ROOTFS_PREFIX}/qemu-img"
mkdir -p "${ROOTFS_PREFIX}"
# Prepare chroot:
if [ ! -d "$ROOTFS" ]; then
mkdir -p "$ROOTFS"
if [ "x${USE_DEBOOTSTRAP}" = "x1" ]; then
fakeroot qemu-debootstrap --foreign --include="linux-image-armmp-lpae" --arch=armhf stretch "$ROOTFS" http://ftp.de.debian.org/debian/
# Hack to avoid debootstrap trying to mount /proc, as it will fail with "no permissions" and anyway proot takes care of it:
sed -i "s/setup_proc//g" "$ROOTFS/debootstrap/suite-script"
mychroot /debootstrap/debootstrap --second-stage --verbose http://ftp.de.debian.org/debian/
else
YESTERDAY=$(python -c 'import datetime ; print((datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d"))')
wget -nc -q "https://uk.images.linuxcontainers.org/images/debian/stretch/armhf/default/${YESTERDAY}_22:42/rootfs.tar.xz"
tar -xf rootfs.tar.xz -C "$ROOTFS/" || true
echo "nameserver 8.8.8.8" > "$ROOTFS/etc/resolv.conf"
fi
mychroot -b /dev apt-get update
mychroot apt-get -y install build-essential dh-autoreconf pkg-config libuhd-dev libusb-1.0-0-dev libusb-dev git
fi
# Run jenkins.sh inside the chroot:
INSIDE_CHROOT=1 mychroot_nocwd -w /osmo-trx -b "$OSMOTRX_DIR:/osmo-trx" -b "$(which osmo-clean-workspace.sh):/usr/bin/osmo-clean-workspace.sh" ./contrib/jenkins.sh
exit 0
fi
fi
### BUILD osmo-trx
autoreconf --install --force
./configure
./configure $INSTR
$MAKE $PARALLEL_MAKE
$MAKE check \
|| cat-testlogs.sh
if [ -z "x${INSIDE_CHROOT}" ]; then
osmo-clean-workspace.sh
fi

235
debian/changelog vendored
View File

@@ -1,3 +1,238 @@
osmo-trx (0.3.0) unstable; urgency=medium
[ Neels Hofmeyr ]
* jenkins: use osmo-clean-workspace.sh before and after build
[ Harald Welte ]
* SocketsTest: Fix printing of non-nul-terminated string
[ Piotr Krysik ]
* UHDDevice.cpp: add USRP B205mini support
[ Max ]
* Mark release target as virtual
* Remove outdated references to OpenBTS
* Remove unused headers
* Update installation instructions
* Update legal disclaimer
* Update license notes
* tests: null-terminate buffer
[ Pau Espin Pedrol ]
* cosmetic: Remove trailing whitespace
* Logger: Stop using Log.Alarms.Max from config
* Logger: Stop using Log.File and Log.Level from config
* Drop use of ConfigurationTable gConfig
* Remove Configuration module and libsqlite dependency
* cosmetic: AUTHORS: fix trailing whitespace
* Set up GNU Autotest infrastructure
* tests: InterThread: adapt to have reproducible output and enable autotest
* tests: Timeval: adapt to have reproducible output and enable autotest
* tests: Log: adapt to have reproducible output and enable autotest
* Sockets.cpp: Fix initialization of UDD socket
* tests: Sockets: adapt to have reproducible output and enable autotest
* utils/convolvtest: Remove uneeded libosmocore dependency
* Move ARCH_LA to Makefile.common
* tests: Migrate convtest util to autotest infrastructure
* arm/convert.c: Fix compilation error
* arm/convert.c: Add missing convert_init implementation
* .gitignore: Add missing test related files
* Remove UDDSocket class
* tests: SocketTests: Pick OS-assigned instead of setting one manually
* tests: SocketsTest: Avoid hang forever if test fails
* tests: SocketsTest: Fail test on write fail
* tests: TimevalTest: refactor and avoid double comparison
* contrib/jenkins.sh: Use qemu+proot+debootstrap to run tests with ARM instruction set
* tests: convolve: Disable due to difference in output in different archs
* Remove unneeded libdl dependency
* Fix whitespace
* Add support to set Rx/TxAntenna
* UHDDevice: Initialize async_event_thrd in constructor
* Logger: Drop unused gLogEarly
* Logger: Remove unused logging macros
* Logger: get rid of alarm APIs
* Logger: Drop syslog support
* Logger: Drop support to log into file
* Logger: Remove unused includes
* Logger: Remove gLogToConsole flag
* configure.ac: Check for pkg-config
[ Alexander Huemer ]
* Unbreak `./configure --with-usrp1` build
* Fix USRP1 build with support for setting Rx/TxAntenna
[ Alexander Couzens ]
* jenkins.sh: fix the download url if the qemu image wasn't setup
-- Pau Espin Pedrol <pespin@sysmocom.de> Mon, 05 Mar 2018 16:49:42 +0100
osmo-trx (0.2.0) unstable; urgency=medium
[ 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()
-- Harald Welte <laforge@gnumonks.org> Sat, 28 Oct 2017 17:52:32 +0200
osmo-trx (0.1.9) trusty; urgency=medium
* Ask Ivan, really

4
debian/control vendored
View File

@@ -5,8 +5,6 @@ Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
Build-Depends: debhelper (>= 9),
autotools-dev,
autoconf-archive,
libdbd-sqlite3,
libsqlite3-dev,
pkg-config,
dh-autoreconf,
libuhd-dev,
@@ -20,7 +18,7 @@ Homepage: https://projects.osmocom.org/projects/osmotrx
Package: osmo-trx
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SDR transceiver that implements Layer 1 of a GSM BTS
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:

14
debian/copyright vendored
View File

@@ -52,20 +52,6 @@ Copyright: 2005-2009 United States Government as represented by
the U.S. Army Research Laboratory.
License: BSD-3-clause
Files: CommonLibs/sqlite3util.cpp
Copyright: 2010 Kestrel Signal Processing Inc.
License: none
No license described for file.
Comment: In the previous version of the file in the git repository
at upstream it is written:
Written by David A. Burgess, Kestrel Signal Processing, Inc., 2010
The author disclaims copyright to this source code.
In the git log, this is written:
I do not claim any copyright over this change, as it's very basic.
Looking forward to see it merged into mainline.
See revision e766abbf82f02473038a83fd2f78befd08544cab at
https://github.com/osmocom/osmo-trx
Files: debian/*
Copyright: 2015 Ruben Undheim <ruben.undheim@gmail.com>
License: GPL-3+

151
git-version-gen Executable file
View File

@@ -0,0 +1,151 @@
#!/bin/sh
# Print a version string.
scriptversion=2010-01-28.01
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
# - from a non-git-repo directory containing a .tarball-version file, which
# presumes this script is invoked like "./git-version-gen .tarball-version".
# In order to use intra-version strings in your project, you will need two
# separate generated version string files:
#
# .tarball-version - present only in a distribution tarball, and not in
# a checked-out repository. Created with contents that were learned at
# the last time autoconf was run, and used by git-version-gen. Must not
# be present in either $(srcdir) or $(builddir) for git-version-gen to
# give accurate answers during normal development with a checked out tree,
# but must be present in a tarball when there is no version control system.
# Therefore, it cannot be used in any dependencies. GNUmakefile has
# hooks to force a reconfigure at distribution time to get the value
# correct, without penalizing normal development with extra reconfigures.
#
# .version - present in a checked-out repository and in a distribution
# tarball. Usable in dependencies, particularly for files that don't
# want to depend on config.h but do want to track version changes.
# Delete this file prior to any autoconf run where you want to rebuild
# files to pick up a version string change; and leave it stale to
# minimize rebuild time after unrelated changes to configure sources.
#
# It is probably wise to add these two files to .gitignore, so that you
# don't accidentally commit either generated file.
#
# Use the following line in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([GNU project],
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
# [bug-project@example])
#
# Then use the following lines in your Makefile.am, so that .version
# will be present for dependencies, and so that .tarball-version will
# exist in distribution tarballs.
#
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo $(VERSION) > $(distdir)/.tarball-version
case $# in
1) ;;
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
esac
tarball_version_file=$1
nl='
'
# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f $tarball_version_file
then
v=`cat $tarball_version_file` || exit 1
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test -z "$v" \
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
fi
if test -n "$v"
then
: # use $v
elif
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in
[0-9]*) ;;
v[0-9]*) ;;
*) (exit 1) ;;
esac
then
# Is this a new git that lists number of commits since the last
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
: git describe is older two part flavor
# Recreate the number of commits and rewrite such that the
# result is the same as if we were using the newer version
# of git describe.
vtag=`echo "$v" | sed 's/-.*//'`
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
;;
esac
# Change the first '-' to a '.', so version-comparing tools work properly.
# Remove the "g" in git describe's output string, to save a byte.
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
else
v=UNKNOWN
fi
v=`echo "$v" |sed 's/^v//'`
# Don't declare a version "dirty" merely because a time stamp has changed.
git status > /dev/null 2>&1
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
case "$dirty" in
'') ;;
*) # Append the suffix only if there isn't one already.
case $v in
*-dirty) ;;
*) v="$v-dirty" ;;
esac ;;
esac
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$v" | tr -d '\012'
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View File

@@ -0,0 +1,8 @@
15 15 240
000011110000
101011110000
175
111101010000
ts=abcdefgh
tp=0110000101100010011000110110010001100101011001100110011101101000000000
ts=abcdefgh

View File

@@ -35,14 +35,20 @@ using namespace std;
InterthreadQueue<int> gQ;
InterthreadMap<int,int> gMap;
int q_last_read_val = -1;
int q_last_write_val;
int m_last_read_val;
int m_last_write_val;
void* qWriter(void*)
{
int *p;
for (int i=0; i<20; i++) {
p = new int;
*p = i;
COUT("queue write " << *p);
CERR("queue write " << *p);
gQ.write(p);
q_last_write_val = i;
if (random()%2) sleep(1);
}
p = new int;
@@ -56,8 +62,14 @@ void* qReader(void*)
bool done = false;
while (!done) {
int *p = gQ.read();
COUT("queue read " << *p);
if (*p<0) done=true;
CERR("queue read " << *p);
if (*p<0) {
assert(q_last_read_val == 19 && *p == -1);
done = true;
} else {
assert(q_last_read_val == *p - 1);
q_last_read_val = *p;
}
delete p;
}
return NULL;
@@ -70,8 +82,9 @@ void* mapWriter(void*)
for (int i=0; i<20; i++) {
p = new int;
*p = i;
COUT("map write " << *p);
CERR("map write " << *p);
gMap.write(i,p);
m_last_write_val = i;
if (random()%2) sleep(1);
}
return NULL;
@@ -81,7 +94,9 @@ void* mapReader(void*)
{
for (int i=0; i<20; i++) {
int *p = gMap.read(i);
COUT("map read " << *p);
CERR("map read " << *p);
assert(*p == i);
m_last_read_val = *p;
// InterthreadMap will delete the pointers
// delete p;
}
@@ -109,6 +124,13 @@ int main(int argc, char *argv[])
qWriterThread.join();
mapReaderThread.join();
mapWriterThread.join();
assert(q_last_write_val == 19);
assert(q_last_read_val == 19);
assert(m_last_write_val == 19);
assert(m_last_read_val == 19);
printf("Done\n");
}

View File

@@ -0,0 +1 @@
Done

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2009 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
@@ -23,23 +24,25 @@
*/
#include "Timeval.h"
#include <iostream>
#include <iterator>
using namespace std;
#include "Logger.h"
int main(int argc, char *argv[])
{
gLogInit("NOTICE");
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;
Log(LOG_EMERG).get() << " testing the logger.";
Log(LOG_ALERT).get() << " testing the logger.";
Log(LOG_CRIT).get() << " testing the logger.";
Log(LOG_ERR).get() << " testing the logger.";
Log(LOG_WARNING).get() << " testing the logger.";
Log(LOG_NOTICE).get() << " testing the logger.";
Log(LOG_INFO).get() << " testing the logger.";
Log(LOG_DEBUG).get() << " testing the logger.";
std::cout << "----------- generating 20 alarms ----------" << std::endl;
for (int i = 0 ; i < 20 ; ++i) {
Log(LOG_ALERT).get() << i;
}
}

View File

@@ -0,0 +1,24 @@
EMERG testing the logger.
ALERT testing the logger.
CRIT testing the logger.
ERR testing the logger.
ALERT 0
ALERT 1
ALERT 2
ALERT 3
ALERT 4
ALERT 5
ALERT 6
ALERT 7
ALERT 8
ALERT 9
ALERT 10
ALERT 11
ALERT 12
ALERT 13
ALERT 14
ALERT 15
ALERT 16
ALERT 17
ALERT 18
ALERT 19

View File

@@ -0,0 +1,29 @@
EMERG testing the logger.
ALERT testing the logger.
CRIT testing the logger.
ERR testing the logger.
WARNING testing the logger.
NOTICE testing the logger.
INFO testing the logger.
DEBUG testing the logger.
----------- generating 20 alarms ----------
ALERT 0
ALERT 1
ALERT 2
ALERT 3
ALERT 4
ALERT 5
ALERT 6
ALERT 7
ALERT 8
ALERT 9
ALERT 10
ALERT 11
ALERT 12
ALERT 13
ALERT 14
ALERT 15
ALERT 16
ALERT 17
ALERT 18
ALERT 19

View File

@@ -0,0 +1,44 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall -I$(top_srcdir)/CommonLibs $(STD_DEFINES_AND_INCLUDES) -g
EXTRA_DIST = BitVectorTest.ok \
PRBSTest.ok \
InterthreadTest.ok \
SocketsTest.ok \
TimevalTest.ok \
VectorTest.ok \
LogTest.ok
noinst_PROGRAMS = \
BitVectorTest \
PRBSTest \
InterthreadTest \
SocketsTest \
TimevalTest \
VectorTest \
LogTest
BitVectorTest_SOURCES = BitVectorTest.cpp
BitVectorTest_LDADD = $(COMMON_LA)
PRBSTest_SOURCES = PRBSTest.cpp
InterthreadTest_SOURCES = InterthreadTest.cpp
InterthreadTest_LDADD = $(COMMON_LA)
InterthreadTest_LDFLAGS = -lpthread
SocketsTest_SOURCES = SocketsTest.cpp
SocketsTest_LDADD = $(COMMON_LA)
SocketsTest_LDFLAGS = -lpthread
TimevalTest_SOURCES = TimevalTest.cpp
TimevalTest_LDADD = $(COMMON_LA)
VectorTest_SOURCES = VectorTest.cpp
VectorTest_LDADD = $(COMMON_LA)
LogTest_SOURCES = LogTest.cpp
LogTest_LDADD = $(COMMON_LA)
MOSTLYCLEANFILES += testSource testDestination

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
*
* 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 "PRBS.h"
#include <iostream>
#include <cstdlib>
#include <assert.h>
void testPrbs(PRBS &prbs, uint64_t expectedPeriod)
{
uint64_t period = 0;
do {
std::cout << prbs.generateBit();
period++;
} while (!prbs.isFinished());
std::cout << std::endl;
std::cout << "Period: " << period << std::endl;
assert(period == expectedPeriod);
}
int main(int argc, char *argv[])
{
PRBS9 prbs9(0x01);
testPrbs(prbs9, (1<<9)-1);
PRBS15 prbs15(0x01);
testPrbs(prbs15, (1<<15)-1);
}

File diff suppressed because one or more lines are too long

View File

@@ -30,21 +30,27 @@
#include "Threads.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
static const int gNumToSend = 10;
void *testReaderIP(void *)
static void sigalarm_handler(int foo)
{
UDPSocket readSocket(5934, "localhost", 5061);
readSocket.nonblocking();
printf("FAIL: test did not run successfully\n");
exit(EXIT_FAILURE);
}
void *testReaderIP(void *param)
{
UDPSocket *readSocket = (UDPSocket *)param;
readSocket->nonblocking();
int rc = 0;
while (rc<gNumToSend) {
char buf[MAX_UDP_LENGTH];
int count = readSocket.read(buf, MAX_UDP_LENGTH);
char buf[MAX_UDP_LENGTH] = { 0 };
int count = readSocket->read(buf, MAX_UDP_LENGTH);
if (count>0) {
COUT("read: " << buf);
CERR("read: " << buf);
rc++;
} else {
sleep(2);
@@ -53,51 +59,42 @@ void *testReaderIP(void *)
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[] )
{
int count;
if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
/* If the test takes longer than 2*gNumToSend seconds, abort it */
alarm(2* gNumToSend);
UDPSocket readSocket("127.0.0.1", 0);
UDPSocket socket1("127.0.0.1", 0, "localhost", readSocket.port());
CERR("socket1: " << socket1.port() << ", readSocket: " << readSocket.port());
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());
readerThreadIP.start(testReaderIP, &readSocket);
// 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);
CERR("write");
count = socket1.write("Hello IP land");
if (count < 0) {
COUT("FAIL: write");
exit(EXIT_FAILURE);
}
sleep(1);
}
readerThreadIP.join();
readerThreadUnix.join();
printf("Done\n");
}
// vim: ts=4 sw=4

View File

@@ -0,0 +1 @@
Done

View File

@@ -0,0 +1,64 @@
/*
* 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>
#include <assert.h>
#include <sys/time.h>
using namespace std;
int main(int argc, char *argv[])
{
long last_remaining = 10000;
Timeval then(last_remaining);
assert(then.elapsed() == -last_remaining);
cerr << then << " elapsed: " << then.elapsed() << endl;
/* Check that last_remaining parameter affects setting time in the future */
usleep(10000);
double increased_time_secs = Timeval().seconds();
assert(increased_time_secs <= then.seconds());
struct timespec invariant_time = then.timespec();
int loops = 0;
while (!then.passed()) {
struct timespec tspecnow = then.timespec();
cerr << "now: " << Timeval().seconds() << " then: " << then << " remaining: " << then.remaining() << endl;
assert(last_remaining >= then.remaining());
assert(tspecnow.tv_sec == invariant_time.tv_sec && tspecnow.tv_nsec == invariant_time.tv_nsec);
usleep(500000);
loops++;
}
cerr << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
assert(then.remaining() <= 0);
assert(loops >= 18);
printf("Done\n");
}

View File

@@ -0,0 +1 @@
Done

View File

@@ -28,10 +28,6 @@
#include "Vector.h"
#include <iostream>
// We must have a gConfig now to include Vector.
#include "Configuration.h"
ConfigurationTable gConfig;
using namespace std;
typedef Vector<int> TestVector;

View File

@@ -0,0 +1,10 @@
0 1 2 3 4
10 11 12 13 14
0 1 2 3 4 10 11 12 13 14
0 1 2
3 4 10 11 12 13 14
8 8 8 8 8 8 8 8 8 8
8 8 8 0 1 2 3 4 8 8
1 2 3
8 8 8 0 9 9 9 4 8 8
9 9 9

41
tests/Makefile.am Normal file
View File

@@ -0,0 +1,41 @@
SUBDIRS = \
CommonLibs \
Transceiver52M \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
:;{ \
echo '# Signature of the current package.' && \
echo 'm4_define([AT_PACKAGE_NAME],' && \
echo ' [$(PACKAGE_NAME)])' && \
echo 'm4_define([AT_PACKAGE_TARNAME],' && \
echo ' [$(PACKAGE_TARNAME)])' && \
echo 'm4_define([AT_PACKAGE_VERSION],' && \
echo ' [$(PACKAGE_VERSION)])' && \
echo 'm4_define([AT_PACKAGE_STRING],' && \
echo ' [$(PACKAGE_STRING)])' && \
echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \
echo ' [$(PACKAGE_BUGREPORT)])'; \
echo 'm4_define([AT_PACKAGE_URL],' && \
echo ' [$(PACKAGE_URL)])'; \
} >'$(srcdir)/package.m4'
EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
TESTSUITE = $(srcdir)/testsuite
DISTCLEANFILES = atconfig $(NULL)
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
installcheck-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
clean-local:
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te
AUTOTEST = $(AUTOM4TE) --language=autotest
$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4
$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
mv $@.tmp $@

View File

@@ -0,0 +1,17 @@
include $(top_srcdir)/Makefile.common
AM_CFLAGS = -Wall -I$(top_srcdir)/Transciever52 $(STD_DEFINES_AND_INCLUDES) -g
EXTRA_DIST = convolve_test.ok
noinst_PROGRAMS = \
convolve_test
convolve_test_SOURCES = convolve_test.c
convolve_test_LDADD = $(COMMON_LA) $(ARCH_LA)
if HAVE_SSE3
convolve_test_CFLAGS = $(AM_CFLAGS) $(SIMD_FLAGS)
endif
if HAVE_SSE4_1
convolve_test_CFLAGS = $(AM_CFLAGS) $(SIMD_FLAGS)
endif

View File

@@ -1,6 +1,6 @@
#include <stdio.h>
#include <string.h>
#include <osmocom/core/utils.h>
#include <stdlib.h>
#include "../../Transceiver52M/common/convolve.h"
#define TESTVEC_LEN 1000

53
tests/testsuite.at Normal file
View File

@@ -0,0 +1,53 @@
AT_INIT
AT_BANNER([Regression tests.])
AT_SETUP([BitVectorTest])
AT_KEYWORDS([BitVectorTest])
cat $abs_srcdir/CommonLibs/BitVectorTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/BitVectorTest], [], [expout], [])
AT_CLEANUP
AT_SETUP([InterthreadTest])
AT_KEYWORDS([InterthreadTest])
cat $abs_srcdir/CommonLibs/InterthreadTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/InterthreadTest], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([LogTest])
AT_KEYWORDS([LogTest])
cat $abs_srcdir/CommonLibs/LogTest.ok > expout
cat $abs_srcdir/CommonLibs/LogTest.err > experr
AT_CHECK([$abs_top_builddir/tests/CommonLibs/LogTest], [], [expout], [experr])
AT_CLEANUP
AT_SETUP([PRBSTest])
AT_KEYWORDS([PRBSTest])
cat $abs_srcdir/CommonLibs/PRBSTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/PRBSTest], [], [expout], [])
AT_CLEANUP
AT_SETUP([SocketsTest])
AT_KEYWORDS([SocketsTest])
cat $abs_srcdir/CommonLibs/SocketsTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/SocketsTest], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([TimevalTest])
AT_KEYWORDS([TimevalTest])
cat $abs_srcdir/CommonLibs/TimevalTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/TimevalTest], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([VectorTest])
AT_KEYWORDS([VectorTest])
cat $abs_srcdir/CommonLibs/VectorTest.ok > expout
AT_CHECK([$abs_top_builddir/tests/CommonLibs/VectorTest], [], [expout], [])
AT_CLEANUP
AT_SETUP([convolve_test])
AT_KEYWORDS([convolve_test])
# Different results for i686, x86_64 and ARM. see OS#2826, OS#2828, and https://lists.osmocom.org/pipermail/openbsc/2018-January/011655.html
AT_SKIP_IF(true)
cat $abs_srcdir/Transceiver52M/convolve_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/Transceiver52M/convolve_test], [], [expout], [])
AT_CLEANUP

View File

@@ -1,18 +0,0 @@
all: main.o convolve_base.o convolve.o convolve_sse_3.o
gcc -g -Wall ./*.o -o convtest -losmocore
clean:
rm -f ./*.o
rm -f ./convtest
main.o: main.c
gcc -g -Wall -c main.c
convolve_base.o: ../../Transceiver52M/common/convolve_base.c
gcc -std=c99 -c ../../Transceiver52M/common/convolve_base.c
convolve.o: ../../Transceiver52M/x86/convolve.c
gcc -std=c99 -c ../../Transceiver52M/x86/convolve.c -I ../../Transceiver52M/common/ -msse3 -DHAVE_SSE3
convolve_sse_3.o: ../../Transceiver52M/x86/convolve_sse_3.c
gcc -std=c99 -c ../../Transceiver52M/x86/convolve_sse_3.c -I ../../Transceiver52M/common/ -msse3 -DHAVE_SSE3