Compare commits

...

75 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
61 changed files with 1452 additions and 2984 deletions

27
.gitignore vendored
View File

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

83
AUTHORS
View File

@@ -1,18 +1,18 @@
# #
# Copyright 2008, 2009 Free Software Foundation, Inc. # Copyright 2008, 2009 Free Software Foundation, Inc.
# #
# This file is part of GNU Radio # This file is part of GNU Radio
# #
# GNU Radio is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option) # the Free Software Foundation; either version 3, or (at your option)
# any later version. # any later version.
# #
# GNU Radio is distributed in the hope that it will be useful, # GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License along # 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., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -23,34 +23,17 @@ David A. Burgess, dburgess@kestrelsp.com:
CLI/CLI.h CLI/CLI.h
CommonLibs/Assert.h CommonLibs/Assert.h
CommonLibs/BitVector.cpp CommonLibs/BitVector.cpp
CommonLibs/BitVectorTest.cpp
CommonLibs/Configuration.cpp
CommonLibs/Configuration.h
CommonLibs/ConfigurationTest.cpp
CommonLibs/Interthread.h CommonLibs/Interthread.h
CommonLibs/InterthreadTest.cpp
CommonLibs/LinkedLists.cpp CommonLibs/LinkedLists.cpp
CommonLibs/LinkedLists.h CommonLibs/LinkedLists.h
CommonLibs/Regexp.h CommonLibs/Regexp.h
CommonLibs/RegexpTest.cpp
CommonLibs/Sockets.cpp CommonLibs/Sockets.cpp
CommonLibs/Sockets.h CommonLibs/Sockets.h
CommonLibs/SocketsTest.cpp
CommonLibs/Threads.cpp CommonLibs/Threads.cpp
CommonLibs/Threads.h CommonLibs/Threads.h
CommonLibs/Timeval.cpp CommonLibs/Timeval.cpp
CommonLibs/Timeval.h CommonLibs/Timeval.h
CommonLibs/TimevalTest.cpp
CommonLibs/Vector.h 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.cpp
GSM/GSM610Tables.h GSM/GSM610Tables.h
GSM/GSMCommon.cpp GSM/GSMCommon.cpp
@@ -82,29 +65,15 @@ David A. Burgess, dburgess@kestrelsp.com:
GSM/GSMTransfer.cpp GSM/GSMTransfer.cpp
GSM/GSMTransfer.h GSM/GSMTransfer.h
LICENSEBLOCK LICENSEBLOCK
SIP/SIPEngine.h
SIP/SIPInterface.h
SMS/SMSMessages.cpp
SMS/SMSMessages.h
SMS/SMSTransfer.cpp
SMS/SMSTransfer.h
TRXManager/TRXManager.cpp TRXManager/TRXManager.cpp
Transceiver/Complex.h Transceiver/Complex.h
apps/OpenBTS900.cpp tests/CommonLibs/BitVectorTest.cpp
apps/OpenBTS850.cpp tests/CommonLibs/InterthreadTest.cpp
apps/OpenBTS25c3.cpp tests/CommonLibs/SocketsTest.cpp
tests/AGCHTest.cpp tests/CommonLibs/TimevalTest.cpp
tests/BeaconTest.cpp tests/CommonLibs/VectorTest.cpp
tests/CallTest.cpp
tests/CallTest2.cpp
tests/LAPDmTest.cpp
tests/LoopbackTest.cpp
tests/RegistrationTest.cpp
tests/TRXSimulator.cpp
Harvind S. Samra, hssamra@kestrelsp.com: Harvind S. Samra, hssamra@kestrelsp.com:
Control/PagerTest.cpp
Control/RadioResource.cpp
GSM/GSMConfig.h GSM/GSMConfig.h
GSM/GSMTransfer.h GSM/GSMTransfer.h
LICENSEBLOCK LICENSEBLOCK
@@ -126,13 +95,6 @@ Harvind S. Samra, hssamra@kestrelsp.com:
Transceiver/testRadio.cpp Transceiver/testRadio.cpp
Raffi Sevlian, raffisev@gmail.com: 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/GSMCommon.h
GSM/GSMConfig.h GSM/GSMConfig.h
GSM/GSML1FEC.h GSM/GSML1FEC.h
@@ -157,36 +119,9 @@ Raffi Sevlian, raffisev@gmail.com:
GSM/GSMSAPMux.h GSM/GSMSAPMux.h
GSM/GSMTransfer.h GSM/GSMTransfer.h
LICENSEBLOCK 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 TRXManager/TRXManager.h
Alon Levy, alonlevy1@gmail.com Alon Levy, alonlevy1@gmail.com
RRLPMessages.cpp RRLPMessages.cpp
RRLPMessages.h RRLPMessages.h
RRLPTest.cpp 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 Permissive Terms Supplementing the License
1. Remote Interaction Through IP Networks. 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 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 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 subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
Network Interaction; Use with the GNU General Public License"). 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. 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 END OF ADDITIONAL TERMS
@@ -712,13 +701,8 @@ END OF ADDITIONAL TERMS
How to comply with Section 13 of the AGPLv3 license. How to comply with Section 13 of the AGPLv3 license.
The recommended method for compliance with Section 13 of the AGPLv3 license is 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 to deliver a text message to each handset that attaches to the cellular
network. At a minimum, that text message should include the string "OpenBTS network which uses OsmoTRX. At a minimum, that text message should include the string
AGPLv3" and a URL that can be used to access the OpenBTS source code. This "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 message need not be delivered to handsets that are denied registration with the
network, since those handsets have been denied service. 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 <stdarg.h>
#include <sys/time.h> // For gettimeofday #include <sys/time.h> // For gettimeofday
#include "Configuration.h"
#include "Logger.h" #include "Logger.h"
#include "Threads.h" // pat added #include "Threads.h" // pat added
using namespace std; 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; Mutex gLogToLock;
// Global log level threshold:
// Reference to a global config table, used all over the system. int config_log_level;
extern ConfigurationTable gConfig;
/**@ The global alarms table. */
//@{
Mutex alarmsLock;
list<string> alarmsList;
void addAlarm(const string&);
//@}
// (pat) If Log messages are printed before the classes in this module are inited
// (which happens when static classes have constructors that do work)
// the OpenBTS just crashes.
// Prevent that by setting sLoggerInited to true when this module is inited.
static bool sLoggerInited = 0;
static struct CheckLoggerInitStatus {
CheckLoggerInitStatus() { sLoggerInited = 1; }
} sCheckloggerInitStatus;
/** Names of the logging levels. */ /** Names of the logging levels. */
const char *levelNames[] = { const char *levelNames[] = {
@@ -96,22 +67,6 @@ int levelStringToInt(const string& name)
return -1; 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, ...) static std::string format(const char *fmt, ...)
{ {
va_list ap; va_list ap;
@@ -138,127 +93,22 @@ std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
return os << ss.str(); 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() Log::~Log()
{ {
if (mDummyInit) return;
// Anything at or above LOG_CRIT is an "alarm". // 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 (mPriority <= LOG_ERR) {
if (sLoggerInited) addAlarm(mStream.str().c_str());
cerr << mStream.str() << endl; cerr << mStream.str() << endl;
} }
// Current logging level was already checked by the macro. So just log.
// Log to syslog int mlen = mStream.str().size();
if (gLogToSyslog) { int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
syslog(mPriority, "%s", mStream.str().c_str()); ScopedLock lock(gLogToLock);
} // The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
// Log to file and console // so just use std::cout.
if (gLogToConsole||gLogToFile) { std::cout << mStream.str();
int mlen = mStream.str().size(); if (neednl) std::cout<<"\n";
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);
}
}
} }
Log::Log(const char* name, const char* level, int facility)
{
mDummyInit = true;
gLogInit(name, level, facility);
}
ostringstream& Log::get() ostringstream& Log::get()
{ {
assert(mPriority<numLevels); 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. // Set the level if one has been specified.
if (level) { if (level)
gConfig.set("Log.Level",level); config_log_level = levelStringToInt(level);
}
// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
string str = gConfig.getStr("Log.File");
if (gLogToFile==NULL && str.length() && 0==strncmp(gCmdName,"Open",4)) {
const char *fn = str.c_str();
if (fn && *fn && strlen(fn)>3) { // strlen because a garbage char is getting in sometimes.
gLogToFile = fopen(fn,"w"); // New log file each time we start.
if (gLogToFile) {
time_t now;
time(&now);
fprintf(gLogToFile,"Starting at %s",ctime(&now));
fflush(gLogToFile);
std::cout << "Logging to file: " << fn << "\n";
}
}
}
// Open the log connection.
openlog(name,0,facility);
}
void gLogEarly(int level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (gLogToSyslog) {
va_list args_copy;
va_copy(args_copy, args);
vsyslog(level | LOG_USER, fmt, args_copy);
va_end(args_copy);
}
if (gLogToConsole) {
va_list args_copy;
va_copy(args_copy, args);
vprintf(fmt, args_copy);
printf("\n");
va_end(args_copy);
}
if (gLogToFile) {
va_list args_copy;
va_copy(args_copy, args);
vfprintf(gLogToFile, fmt, args_copy);
fprintf(gLogToFile, "\n");
va_end(args_copy);
}
va_end(args);
} }
// vim: ts=4 sw=4 // vim: ts=4 sw=4

View File

@@ -32,19 +32,27 @@
#ifndef LOGGER_H #ifndef LOGGER_H
#define LOGGER_H #define LOGGER_H
#include <syslog.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <list>
#include <map>
#include <string> #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) \ #define _LOG(level) \
Log(LOG_##level).get() << pthread_self() \ Log(LOG_##level).get() << pthread_self() \
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": " << 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 #ifdef NDEBUG
#define LOG(wLevel) \ #define LOG(wLevel) \
@@ -54,40 +62,8 @@
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel) if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
#endif #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. 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; This object is NOT the global logger;
every log record is an object of this class. 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. std::ostringstream mStream; ///< This is where we buffer up the log entry.
int mPriority; ///< Priority of current report. int mPriority; ///< Priority of current report.
bool mDummyInit;
public: public:
Log(int wPriority) 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. // Most of the work is in the destructor.
/** The destructor actually generates the log entry. */ /** The destructor actually generates the log entry. */
~Log(); ~Log();
std::ostringstream& get(); 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. const std::string timestr(); // A timestamp to print in messages.
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss); 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. */ /**@ Global control and initialization of the logging system. */
//@{ //@{
/** Initialize the global logging system. */ /** Initialize the global logging system. */
void gLogInit(const char* name, const char* level=NULL, int facility=LOG_USER); void gLogInit(const char* level=NULL, char* fn=NULL);
/** 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)));
//@} //@}

View File

@@ -22,7 +22,7 @@
include $(top_srcdir)/Makefile.common include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread AM_CXXFLAGS = -Wall -O3 -g -lpthread
EXTRA_DIST = \ EXTRA_DIST = \
example.config \ example.config \
@@ -36,21 +36,7 @@ libcommon_la_SOURCES = \
Sockets.cpp \ Sockets.cpp \
Threads.cpp \ Threads.cpp \
Timeval.cpp \ Timeval.cpp \
Logger.cpp \ Logger.cpp
Configuration.cpp \
sqlite3util.cpp
noinst_PROGRAMS = \
BitVectorTest \
PRBSTest \
InterthreadTest \
SocketsTest \
TimevalTest \
VectorTest \
ConfigurationTest \
LogTest
# ReportingTest
noinst_HEADERS = \ noinst_HEADERS = \
BitVector.h \ BitVector.h \
@@ -61,38 +47,4 @@ noinst_HEADERS = \
Threads.h \ Threads.h \
Timeval.h \ Timeval.h \
Vector.h \ Vector.h \
Configuration.h \ Logger.h
Logger.h \
sqlite3util.h
BitVectorTest_SOURCES = BitVectorTest.cpp
BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
PRBSTest_SOURCES = PRBSTest.cpp
InterthreadTest_SOURCES = InterthreadTest.cpp
InterthreadTest_LDADD = libcommon.la
InterthreadTest_LDFLAGS = -lpthread
SocketsTest_SOURCES = SocketsTest.cpp
SocketsTest_LDADD = libcommon.la
SocketsTest_LDFLAGS = -lpthread
TimevalTest_SOURCES = TimevalTest.cpp
TimevalTest_LDADD = libcommon.la
VectorTest_SOURCES = VectorTest.cpp
VectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
ConfigurationTest_SOURCES = ConfigurationTest.cpp
ConfigurationTest_LDADD = libcommon.la $(SQLITE3_LIBS)
# ReportingTest_SOURCES = ReportingTest.cpp
# ReportingTest_LDADD = libcommon.la $(SQLITE_LA)
LogTest_SOURCES = LogTest.cpp
LogTest_LDADD = libcommon.la $(SQLITE3_LIBS)
MOSTLYCLEANFILES += testSource testDestination

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() :DatagramSocket()
{ {
open(wSrcPort); open(wSrcPort, wSrcIP);
} }
UDPSocket::UDPSocket(unsigned short wSrcPort, UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort,
const char * wDestIP, unsigned short wDestPort ) const char *wDestIP, unsigned short wDestPort)
:DatagramSocket() :DatagramSocket()
{ {
open(wSrcPort); open(wSrcPort, wSrcIP);
destination(wDestPort, wDestIP); 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 // create
mSocketFD = socket(AF_INET,SOCK_DGRAM,0); mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
@@ -265,7 +265,7 @@ void UDPSocket::open(unsigned short localPort)
size_t length = sizeof(address); size_t length = sizeof(address);
bzero(&address,length); bzero(&address,length);
address.sin_family = AF_INET; 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); address.sin_port = htons(localPort);
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) { if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
perror("bind() failed"); perror("bind() failed");
@@ -284,50 +284,4 @@ unsigned short UDPSocket::port() const
return ntohs(name.sin_port); 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 // vim:ts=4:sw=4

View File

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

View File

@@ -118,8 +118,8 @@ template <class T> class Vector {
/** Build an empty Vector of a given size. */ /** Build an empty Vector of a given size. */
Vector(size_t wSize=0):mData(NULL) { resize(wSize); } Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
/** Build a Vector by shifting the data block. */ /** Build a Vector by moving another. */
Vector(Vector<T>& other) Vector(Vector<T>&& other)
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd) :mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
{ other.mData=NULL; } { 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. installation.
One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to
running configure. running configure.
To run OpenBTS, the following should be installed: To run osmo-trx, the following should be installed:
libuhd (https://gnuradio.org).
Asterisk (http://www.asterisk.org), running SIP on port 5060.
libosip2 (http://www.gnu.org/software/osip/)
libortp (http://freshmeat.net/projects/ortp/)
libusrp (http://gnuradio.org).
This is part of the GNURadio installation. 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 For information on specific executables, see tests/README.tests and
apps/README.apps. 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. information.

20
LEGAL
View File

@@ -1,5 +1,8 @@
OpenBTS 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. Most parts copyright 2008-2011 Free Software Foundation.
Some parts copyright 2010 Kestrel Signal Processing, Inc. Some parts copyright 2010 Kestrel Signal Processing, Inc.
Some parts copyright 2011 Range Networks, 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. 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 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 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 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. 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 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 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," "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 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 Note to US Government Contractors
GPL is not compatible with "government purpose rights" (GPR). If you receive 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 of GPL and possibly subject to enforcement actions by the original authors and
copyright holders, including the Free Software Foundation, Inc. copyright holders, including the Free Software Foundation, Inc.
Software Licensing and Distribution Software Licensing and Distribution
A subset of OpenBTS is distributed publicly under AGPLv3. Range reserves the right to The OsmoTRX is distributed publicly under AGPLv3. See the COPYING file
distribute most of this source code other licenses as well. See the COPYING file
for more information on the license for this distribution. for more information on the license for this distribution.

View File

@@ -21,16 +21,17 @@
include $(top_srcdir)/Makefile.common include $(top_srcdir)/Makefile.common
ACLOCAL_AMFLAGS = -I config ACLOCAL_AMFLAGS = -I config
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES) $(SQLITE3_CFLAGS) AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES)
AM_CXXFLAGS = -Wall -pthread -ldl AM_CXXFLAGS = -Wall -pthread
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread -ldl #AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread -ldl #AM_CFLAGS = -Wall -O2 -NDEBUG -pthread
# Order must be preserved # Order must be preserved
SUBDIRS = \ SUBDIRS = \
CommonLibs \ CommonLibs \
GSM \ GSM \
Transceiver52M Transceiver52M \
tests
EXTRA_DIST = \ EXTRA_DIST = \
autogen.sh \ autogen.sh \
@@ -39,6 +40,9 @@ EXTRA_DIST = \
COPYING \ COPYING \
README README
.PHONY: release
@RELMAKE@
dox: FORCE dox: FORCE
doxygen doxconfig doxygen doxconfig

View File

@@ -32,4 +32,10 @@ STD_DEFINES_AND_INCLUDES = \
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
GSM_LA = $(top_builddir)/GSM/libGSM.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 = *~ MOSTLYCLEANFILES = *~

View File

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

View File

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

View File

@@ -22,6 +22,7 @@
#include <string.h> #include <string.h>
#include <malloc.h> #include <malloc.h>
#include <iostream> #include <iostream>
#include <algorithm>
#include "Resampler.h" #include "Resampler.h"
@@ -35,6 +36,8 @@ extern "C" {
#define MAX_OUTPUT_LEN 4096 #define MAX_OUTPUT_LEN 4096
using namespace std;
static float sinc(float x) static float sinc(float x)
{ {
if (x == 0.0) if (x == 0.0)
@@ -43,32 +46,19 @@ static float sinc(float x)
return sin(M_PI * x) / (M_PI * 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 cutoff;
float *proto, val, cutoff;
float sum = 0.0f, scale = 0.0f; float sum = 0.0f, scale = 0.0f;
float midpt = (float) (proto_len - 1.0) / 2.0;
/* /*
* Allocate partition filters and the temporary prototype filter * Allocate partition filters and the temporary prototype filter
* according to numerator of the rational rate. Coefficients are * according to numerator of the rational rate. Coefficients are
* real only and must be 16-byte memory aligned for SSE usage. * real only and must be 16-byte memory aligned for SSE usage.
*/ */
proto = new float[proto_len]; auto proto = vector<float>(p * filt_len);
if (!proto) for (auto &part : partitions)
return false; part = (complex<float> *) memalign(16, filt_len * sizeof(complex<float>));
partitions = (float **) malloc(sizeof(float *) * p);
if (!partitions) {
delete[] proto;
return false;
}
for (size_t i = 0; i < p; i++) {
partitions[i] = (float *)
memalign(16, filt_len * 2 * sizeof(float));
}
/* /*
* Generate the prototype filter with a Blackman-harris window. * Generate the prototype filter with a Blackman-harris window.
@@ -85,47 +75,26 @@ bool Resampler::initFilters(float bw)
else else
cutoff = (float) q; 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] = sinc(((float) i - midpt) / cutoff * bw);
proto[i] *= a0 - proto[i] *= a0 -
a1 * cos(2 * M_PI * i / (proto_len - 1)) + a1 * cos(2 * M_PI * i / (proto.size() - 1)) +
a2 * cos(4 * M_PI * i / (proto_len - 1)) - a2 * cos(4 * M_PI * i / (proto.size() - 1)) -
a3 * cos(6 * M_PI * i / (proto_len - 1)); a3 * cos(6 * M_PI * i / (proto.size() - 1));
sum += proto[i]; sum += proto[i];
} }
scale = p / sum; scale = p / sum;
/* Populate filter partitions from the prototype filter */ /* Populate filter partitions from the prototype filter */
for (size_t i = 0; i < filt_len; i++) { for (size_t i = 0; i < filt_len; i++) {
for (size_t n = 0; n < p; n++) { for (size_t n = 0; n < p; n++)
partitions[n][2 * i + 0] = proto[i * p + n] * scale; partitions[n][i] = complex<float>(proto[i * p + n] * scale);
partitions[n][2 * i + 1] = 0.0f;
}
} }
/* For convolution, we store the filter taps in reverse */ /* Store filter taps in reverse */
for (size_t n = 0; n < p; n++) { for (auto &part : partitions)
for (size_t i = 0; i < filt_len / 2; i++) { reverse(&part[0], &part[filt_len]);
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;
} }
static bool check_vec_len(int in_len, int out_len, int p, int q) 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; 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 Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
{ {
int n, path; 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]; path = out_path[i];
convolve_real(in, in_len, convolve_real(in, in_len,
partitions[path], filt_len, reinterpret_cast<float *>(partitions[path]),
&out[2 * i], out_len - i, filt_len, &out[2 * i], out_len - i,
n, 1, 1, 0); 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) bool Resampler::init(float bw)
{ {
if (p == 0 || q == 0 || filt_len == 0) return false;
/* Filterbank filter internals */ /* Filterbank filter internals */
if (!initFilters(bw)) initFilters(bw);
return false;
/* Precompute filterbank paths */ /* Precompute filterbank paths */
in_index = new size_t[MAX_OUTPUT_LEN]; int i = 0;
out_path = new size_t[MAX_OUTPUT_LEN]; for (auto &index : in_index)
computePath(); index = (q * i++) / p;
i = 0;
for (auto &path : out_path)
path = (q * i++) % p;
return true; return true;
} }
@@ -208,7 +173,7 @@ size_t Resampler::len()
} }
Resampler::Resampler(size_t p, size_t q, size_t filt_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->p = p;
this->q = q; this->q = q;
@@ -217,8 +182,6 @@ Resampler::Resampler(size_t p, size_t q, size_t filt_len)
Resampler::~Resampler() Resampler::~Resampler()
{ {
releaseFilters(); for (auto &part : partitions)
free(part);
delete in_index;
delete out_path;
} }

View File

@@ -20,6 +20,9 @@
#ifndef _RESAMPLER_H_ #ifndef _RESAMPLER_H_
#define _RESAMPLER_H_ #define _RESAMPLER_H_
#include <vector>
#include <complex>
class Resampler { class Resampler {
public: public:
/* Constructor for rational sample rate conversion /* Constructor for rational sample rate conversion
@@ -63,14 +66,11 @@ private:
size_t p; size_t p;
size_t q; size_t q;
size_t filt_len; size_t filt_len;
size_t *in_index; std::vector<size_t> in_index;
size_t *out_path; std::vector<size_t> out_path;
std::vector<std::complex<float> *> partitions;
float **partitions; void initFilters(float bw);
bool initFilters(float bw);
void releaseFilters();
void computePath();
}; };
#endif /* _RESAMPLER_H_ */ #endif /* _RESAMPLER_H_ */

View File

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

View File

@@ -89,15 +89,17 @@ struct TransceiverState {
/** The Transceiver class, responsible for physical layer of basestation */ /** The Transceiver class, responsible for physical layer of basestation */
class Transceiver { class Transceiver {
public: public:
/** Transceiver constructor /** Transceiver constructor
@param wBasePort base port number of UDP sockets @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 wSPS number of samples per GSM symbol
@param wTransmitLatency initial setting of transmit latency @param wTransmitLatency initial setting of transmit latency
@param radioInterface associated radioInterface object @param radioInterface associated radioInterface object
*/ */
Transceiver(int wBasePort, Transceiver(int wBasePort,
const char *TRXAddress, const char *TRXAddress,
const char *GSMcoreAddress,
size_t tx_sps, size_t rx_sps, size_t chans, size_t tx_sps, size_t rx_sps, size_t chans,
GSM::Time wTransmitLatency, GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface, RadioInterface *wRadioInterface,
@@ -152,7 +154,8 @@ public:
private: private:
int mBasePort; 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 *> mDataSockets; ///< socket for writing to/reading from GSM core
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands 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 mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
GSM::Time mLatencyUpdateTime; ///< last time latency was updated 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 GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
RadioInterface *mRadioInterface; ///< associated radioInterface object RadioInterface *mRadioInterface; ///< associated radioInterface object
@@ -208,6 +211,7 @@ private:
bool mEdge; bool mEdge;
bool mOn; ///< flag to indicate that transceiver is powered on 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 bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
double mTxFreq; ///< the transmit frequency double mTxFreq; ///< the transmit frequency
double mRxFreq; ///< the receive frequency double mRxFreq; ///< the receive frequency
@@ -275,4 +279,3 @@ void *ControlServiceLoopAdapter(TransceiverChannel *);
/** transmit queueing thread loop */ /** transmit queueing thread loop */
void *TxUpperLoopAdapter(TransceiverChannel *); 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 2010,2011 Free Software Foundation, Inc.
* Copyright (C) 2015 Ettus Research LLC * Copyright (C) 2015 Ettus Research LLC
@@ -130,7 +130,7 @@ static const std::map<dev_key, dev_desc> dev_param_map {
{ std::make_tuple(UMTRX, 1, 1), { 2, 0.0, GSMRATE, 9.9692e-5, "UmTRX 1 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, 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(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 16.5/GSMRATE, "STREAM/LimeSDR (4 SPS TX/RX)" } }, { 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" } }, { std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
}; };
@@ -143,8 +143,8 @@ class smpl_buf {
public: public:
/** Sample buffer constructor /** Sample buffer constructor
@param len number of 32-bit samples the buffer should hold @param len number of 32-bit samples the buffer should hold
@param rate sample clockrate @param rate sample clockrate
@param timestamp @param timestamp
*/ */
smpl_buf(size_t len, double rate); smpl_buf(size_t len, double rate);
~smpl_buf(); ~smpl_buf();
@@ -172,7 +172,7 @@ public:
*/ */
std::string str_status(size_t ts) const; std::string str_status(size_t ts) const;
/** Formatted error string /** Formatted error string
@param code an error code @param code an error code
@return a formatted error string @return a formatted error string
*/ */
@@ -208,7 +208,9 @@ private:
class uhd_device : public RadioDevice { class uhd_device : public RadioDevice {
public: public:
uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type, 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(); ~uhd_device();
int open(const std::string &args, int ref, bool swap_channels); int open(const std::string &args, int ref, bool swap_channels);
@@ -248,6 +250,11 @@ public:
double getRxFreq(size_t chan); double getRxFreq(size_t chan);
double getRxFreq(); 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 getSampleRate() { return tx_rate; }
inline double numberRead() { return rx_pkt_cnt; } inline double numberRead() { return rx_pkt_cnt; }
inline double numberWritten() { return 0; } inline double numberWritten() { return 0; }
@@ -280,6 +287,7 @@ private:
std::vector<double> tx_gains, rx_gains; std::vector<double> tx_gains, rx_gains;
std::vector<double> tx_freqs, rx_freqs; std::vector<double> tx_freqs, rx_freqs;
std::vector<std::string> tx_paths, rx_paths;
size_t tx_spp, rx_spp; size_t tx_spp, rx_spp;
bool started; bool started;
@@ -295,6 +303,7 @@ private:
void init_gains(); void init_gains();
void set_channels(bool swap); void set_channels(bool swap);
void set_rates(); void set_rates();
bool set_antennas();
bool parse_dev_type(); bool parse_dev_type();
bool flush_recv(size_t num_pkts); bool flush_recv(size_t num_pkts);
int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls); int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
@@ -353,18 +362,22 @@ static void thread_enable_cancel(bool cancel)
} }
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps, 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), : tx_gain_min(0.0), tx_gain_max(0.0),
rx_gain_min(0.0), rx_gain_max(0.0), rx_gain_min(0.0), rx_gain_max(0.0),
tx_spp(0), rx_spp(0), tx_spp(0), rx_spp(0),
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(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->tx_sps = tx_sps;
this->rx_sps = rx_sps; this->rx_sps = rx_sps;
this->chans = chans; this->chans = chans;
this->offset = offset; this->offset = offset;
this->iface = iface; this->iface = iface;
this->tx_paths = tx_paths;
this->rx_paths = rx_paths;
} }
uhd_device::~uhd_device() uhd_device::~uhd_device()
@@ -437,10 +450,37 @@ void uhd_device::set_rates()
tx_rate = usrp_dev->get_tx_rate(); tx_rate = usrp_dev->get_tx_rate();
rx_rate = usrp_dev->get_rx_rate(); rx_rate = usrp_dev->get_rx_rate();
ts_offset = (TIMESTAMP) desc.offset * rx_rate; ts_offset = static_cast<TIMESTAMP>(desc.offset * rx_rate);
LOG(INFO) << "Rates configured for " << desc.str; 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;
}
}
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;
}
}
LOG(INFO) << "Antennas configured successfully";
return true;
}
double uhd_device::setTxGain(double db, size_t chan) double uhd_device::setTxGain(double db, size_t chan)
{ {
if (iface == MULTI_ARFCN) if (iface == MULTI_ARFCN)
@@ -519,6 +559,7 @@ bool uhd_device::parse_dev_type()
{ "B100", { B100, TX_WINDOW_USRP1 } }, { "B100", { B100, TX_WINDOW_USRP1 } },
{ "B200", { B200, TX_WINDOW_USRP1 } }, { "B200", { B200, TX_WINDOW_USRP1 } },
{ "B200mini", { B200, TX_WINDOW_USRP1 } }, { "B200mini", { B200, TX_WINDOW_USRP1 } },
{ "B205mini", { B200, TX_WINDOW_USRP1 } },
{ "B210", { B210, TX_WINDOW_USRP1 } }, { "B210", { B210, TX_WINDOW_USRP1 } },
{ "E100", { E1XX, TX_WINDOW_FIXED } }, { "E100", { E1XX, TX_WINDOW_FIXED } },
{ "E110", { E1XX, TX_WINDOW_FIXED } }, { "E110", { E1XX, TX_WINDOW_FIXED } },
@@ -526,25 +567,25 @@ bool uhd_device::parse_dev_type()
{ "E3XX", { E3XX, TX_WINDOW_FIXED } }, { "E3XX", { E3XX, TX_WINDOW_FIXED } },
{ "X300", { X3XX, TX_WINDOW_FIXED } }, { "X300", { X3XX, TX_WINDOW_FIXED } },
{ "X310", { X3XX, TX_WINDOW_FIXED } }, { "X310", { X3XX, TX_WINDOW_FIXED } },
{ "USRP2", { USRP2, TX_WINDOW_FIXED } },
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } }, { "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
{ "STREAM", { LIMESDR, TX_WINDOW_USRP1 } }, { "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } },
}; };
// Compare UHD motherboard and device strings */ // Compare UHD motherboard and device strings */
std::string found; auto mapIter = devStringMap.begin();
if (devStringMap.find(devString) != devStringMap.end()) while (mapIter != devStringMap.end()) {
found = devString; if (devString.find(mapIter->first) != std::string::npos ||
else if (devStringMap.find(mboardString) != devStringMap.end()) mboardString.find(mapIter->first) != std::string::npos) {
found = mboardString; dev_type = std::get<0>(mapIter->second);
tx_window = std::get<1>(mapIter->second);
if (found.empty()) { return true;
LOG(ALERT) << "Unsupported device " << devString; }
return false; mapIter++;
} }
dev_type = devStringMap.at(found).first; LOG(ALERT) << "Unsupported device " << devString;
tx_window = devStringMap.at(found).second; return false;
return true;
} }
/* /*
@@ -576,7 +617,7 @@ void uhd_device::set_channels(bool swap)
chans = 1; chans = 1;
} }
if (chans > dev_param_map.at(dev_key(dev_type, 1, 1)).channels) 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"); throw std::invalid_argument("Device does not support number of requested channels");
std::string subdev_string; std::string subdev_string;
@@ -643,6 +684,11 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
return -1; return -1;
} }
if (!set_antennas()) {
LOG(ALERT) << "UHD antenna setting failed";
return -1;
}
tx_freqs.resize(chans); tx_freqs.resize(chans);
rx_freqs.resize(chans); rx_freqs.resize(chans);
tx_gains.resize(chans); tx_gains.resize(chans);
@@ -704,7 +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++) for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(buf_len, rx_rate); rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
// Initialize and shadow gain values // Initialize and shadow gain values
init_gains(); init_gains();
// Print configuration // Print configuration
@@ -925,7 +971,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
rx_pkt_cnt++; rx_pkt_cnt++;
// Check for errors // Check for errors
rc = check_rx_md_err(metadata, num_smpls); rc = check_rx_md_err(metadata, num_smpls);
switch (rc) { switch (rc) {
case ERROR_UNRECOVERABLE: case ERROR_UNRECOVERABLE:
@@ -1069,7 +1115,7 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
/* Find center frequency between channels */ /* Find center frequency between channels */
rf_spread = fabs(freqs[!chan] - freq); rf_spread = fabs(freqs[!chan] - freq);
if (rf_spread > dev_param_map.at(dev_key(B210, 1, 1)).mcr) { 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"; LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
return treq; return treq;
} }
@@ -1164,6 +1210,78 @@ double uhd_device::getRxFreq(size_t chan)
return rx_freqs[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. * 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 * Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed
@@ -1185,7 +1303,7 @@ TIMESTAMP uhd_device::initialReadTimestamp()
double uhd_device::fullScaleInputValue() double uhd_device::fullScaleInputValue()
{ {
if (dev_type == LIMESDR) if (dev_type == LIMESDR)
return (double) 2047 * LIMESDR_TX_AMPL; return (double) SHRT_MAX * LIMESDR_TX_AMPL;
if (dev_type == UMTRX) if (dev_type == UMTRX)
return (double) SHRT_MAX * UMTRX_TX_AMPL; return (double) SHRT_MAX * UMTRX_TX_AMPL;
else else
@@ -1194,7 +1312,6 @@ double uhd_device::fullScaleInputValue()
double uhd_device::fullScaleOutputValue() double uhd_device::fullScaleOutputValue()
{ {
if (dev_type == LIMESDR) return (double) 2047;
return (double) SHRT_MAX; return (double) SHRT_MAX;
} }
@@ -1451,7 +1568,9 @@ std::string smpl_buf::str_code(ssize_t code)
} }
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, 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 Compilation Flags
SWLOOPBACK compile for software loopback testing SWLOOPBACK compile for software loopback testing
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "Logger.h"
#include "Threads.h" #include "Threads.h"
#include "USRPDevice.h" #include "USRPDevice.h"
#include <Logger.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
@@ -81,7 +80,7 @@ USRPDevice::USRPDevice(size_t sps)
else else
pingOffset = 0; pingOffset = 0;
#ifdef SWLOOPBACK #ifdef SWLOOPBACK
samplePeriod = 1.0e6/actualSampleRate; samplePeriod = 1.0e6/actualSampleRate;
loopbackBufferSize = 0; loopbackBufferSize = 0;
gettimeofday(&lastReadTime,NULL); gettimeofday(&lastReadTime,NULL);
@@ -94,9 +93,9 @@ int USRPDevice::open(const std::string &, int, bool)
writeLock.unlock(); writeLock.unlock();
LOG(INFO) << "opening USRP device.."; LOG(INFO) << "opening USRP device..";
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
string rbf = "std_inband.rbf"; string rbf = "std_inband.rbf";
//string rbf = "inband_1rxhb_1tx.rbf"; //string rbf = "inband_1rxhb_1tx.rbf";
m_uRx.reset(); m_uRx.reset();
if (!skipRx) { if (!skipRx) {
try { try {
@@ -145,7 +144,7 @@ int USRPDevice::open(const std::string &, int, bool)
if (!skipRx) m_uRx->stop(); if (!skipRx) m_uRx->stop();
m_uTx->stop(); m_uTx->stop();
#endif #endif
switch (dboardConfig) { switch (dboardConfig) {
@@ -176,19 +175,19 @@ int USRPDevice::open(const std::string &, int, bool)
samplesRead = 0; samplesRead = 0;
samplesWritten = 0; samplesWritten = 0;
started = false; started = false;
return NORMAL; return NORMAL;
} }
bool USRPDevice::start() bool USRPDevice::start()
{ {
LOG(INFO) << "starting USRP..."; LOG(INFO) << "starting USRP...";
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
if (!m_uRx && !skipRx) return false; if (!m_uRx && !skipRx) return false;
if (!m_uTx) return false; if (!m_uTx) return false;
if (!skipRx) m_uRx->stop(); if (!skipRx) m_uRx->stop();
m_uTx->stop(); m_uTx->stop();
@@ -218,8 +217,8 @@ bool USRPDevice::start()
hi32Timestamp = 0; hi32Timestamp = 0;
isAligned = false; isAligned = false;
if (!skipRx) if (!skipRx)
started = (m_uRx->start() && m_uTx->start()); started = (m_uRx->start() && m_uTx->start());
else else
started = m_uTx->start(); started = m_uTx->start();
@@ -230,14 +229,14 @@ bool USRPDevice::start()
#endif #endif
} }
bool USRPDevice::stop() bool USRPDevice::stop()
{ {
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
if (!m_uRx) return false; if (!m_uRx) return false;
if (!m_uTx) return false; if (!m_uTx) return false;
delete[] currData; delete[] currData;
started = !(m_uRx->stop() && m_uTx->stop()); started = !(m_uRx->stop() && m_uTx->stop());
return !started; return !started;
#else #else
@@ -258,7 +257,7 @@ double USRPDevice::minTxGain()
double USRPDevice::maxRxGain() double USRPDevice::maxRxGain()
{ {
return m_dbRx->gain_max(); return m_dbRx->gain_max();
} }
double USRPDevice::minRxGain() double USRPDevice::minRxGain()
{ {
@@ -314,28 +313,68 @@ double USRPDevice::setRxGain(double dB, size_t chan)
return dB; 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 // NOTE: Assumes sequential reads
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{ {
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
if (!m_uRx) if (!m_uRx)
return 0; return 0;
short *buf = bufs[0]; short *buf = bufs[0];
timestamp += timestampOffset; timestamp += timestampOffset;
if (timestamp + len < timeStart) { if (timestamp + len < timeStart) {
memset(buf,0,len*2*sizeof(short)); memset(buf,0,len*2*sizeof(short));
return len; return len;
} }
if (underrun) *underrun = false; if (underrun) *underrun = false;
uint32_t readBuf[2000]; uint32_t readBuf[2000];
while (1) { while (1) {
//guestimate USB read size //guestimate USB read size
int readLen=0; 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)); readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
if (readLen > 8000) readLen= (8000/512)*512; if (readLen > 8000) readLen= (8000/512)*512;
} }
// read USRP packets, parse and save A/D data as needed // read USRP packets, parse and save A/D data as needed
readLen = m_uRx->read((void *)readBuf,readLen,overrun); readLen = m_uRx->read((void *)readBuf,readLen,overrun);
for(int pktNum = 0; pktNum < (readLen/512); pktNum++) { for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
@@ -382,13 +421,13 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
continue; continue;
} }
if ((word0 >> 28) & 0x04) { if ((word0 >> 28) & 0x04) {
if (underrun) *underrun = true; if (underrun) *underrun = true;
LOG(DEBUG) << "UNDERRUN in TRX->USRP interface"; LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
} }
if (RSSI) *RSSI = (word0 >> 21) & 0x3f; if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
if (!isAligned) continue; if (!isAligned) continue;
unsigned cursorStart = pktTimestamp - timeStart + dataStart; unsigned cursorStart = pktTimestamp - timeStart + dataStart;
while (cursorStart*2 > currDataSize) { while (cursorStart*2 > currDataSize) {
cursorStart -= currDataSize/2; cursorStart -= currDataSize/2;
@@ -401,17 +440,17 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
else { else {
memcpy(data+cursorStart*2,tmpBuf+2,payloadSz); 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); timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp; LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
} }
} }
// copy desired data to buf // copy desired data to buf
unsigned bufStart = dataStart+(timestamp-timeStart); unsigned bufStart = dataStart+(timestamp-timeStart);
if (bufStart + len < currDataSize/2) { if (bufStart + len < currDataSize/2) {
LOG(DEBUG) << "bufStart: " << bufStart; LOG(DEBUG) << "bufStart: " << bufStart;
memcpy(buf,data+bufStart*2,len*2*sizeof(short)); memcpy(buf,data+bufStart*2,len*2*sizeof(short));
memset(data+bufStart*2,0,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; timeStart = timestamp + len;
return len; return len;
#else #else
if (loopbackBufferSize < 2) return 0; if (loopbackBufferSize < 2) return 0;
int numSamples = 0; int numSamples = 0;
struct timeval currTime; struct timeval currTime;
gettimeofday(&currTime,NULL); 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); (currTime.tv_usec - lastReadTime.tv_usec);
if (timeElapsed < samplePeriod) {return 0;} if (timeElapsed < samplePeriod) {return 0;}
int numSamplesToRead = (int) floor(timeElapsed/samplePeriod); int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
if (numSamplesToRead < len) return 0; if (numSamplesToRead < len) return 0;
if (numSamplesToRead > len) numSamplesToRead = len; if (numSamplesToRead > len) numSamplesToRead = len;
if (numSamplesToRead > loopbackBufferSize/2) { if (numSamplesToRead > loopbackBufferSize/2) {
firstRead =false; firstRead =false;
numSamplesToRead = loopbackBufferSize/2; numSamplesToRead = loopbackBufferSize/2;
} }
memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead); memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
@@ -461,7 +500,7 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
firstRead = true; firstRead = true;
} }
samplesRead += numSamples; samplesRead += numSamples;
return numSamples; return numSamples;
#endif #endif
} }
@@ -472,7 +511,7 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
{ {
writeLock.lock(); writeLock.lock();
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
if (!m_uTx) if (!m_uTx)
return 0; return 0;
@@ -519,14 +558,14 @@ int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len); memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
samplesWritten += retVal; samplesWritten += retVal;
loopbackBufferSize += retVal*2; loopbackBufferSize += retVal*2;
return retVal; return retVal;
#endif #endif
} }
bool USRPDevice::updateAlignment(TIMESTAMP timestamp) bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
{ {
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
short data[] = {0x00,0x02,0x00,0x00}; short data[] = {0x00,0x02,0x00,0x00};
uint32_t *wordPtr = (uint32_t *) data; uint32_t *wordPtr = (uint32_t *) data;
*wordPtr = host_to_usrp_u32(*wordPtr); *wordPtr = host_to_usrp_u32(*wordPtr);
@@ -543,7 +582,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
#endif #endif
} }
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
bool USRPDevice::setTxFreq(double wFreq, size_t chan) bool USRPDevice::setTxFreq(double wFreq, size_t chan)
{ {
usrp_tune_result result; usrp_tune_result result;
@@ -601,7 +640,9 @@ bool USRPDevice::setRxFreq(double wFreq) { return true;};
#endif #endif
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, 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); return new USRPDevice(tx_sps);
} }

View File

@@ -83,10 +83,10 @@ private:
double rxGain; double rxGain;
#ifdef SWLOOPBACK #ifdef SWLOOPBACK
short loopbackBuffer[1000000]; short loopbackBuffer[1000000];
int loopbackBufferSize; int loopbackBufferSize;
double samplePeriod; double samplePeriod;
struct timeval startTime; struct timeval startTime;
struct timeval lastReadTime; struct timeval lastReadTime;
@@ -179,6 +179,18 @@ private:
/** return minimum Rx Gain **/ /** return minimum Rx Gain **/
double minTxGain(void); 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 */ /** Return internal status values */
inline double getTxFreq(size_t chan = 0) { return 0; } inline double getTxFreq(size_t chan = 0) { return 0; }
inline double getRxFreq(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 numberRead() { return samplesRead; }
inline double numberWritten() { return samplesWritten; } inline double numberWritten() { return samplesWritten; }
std::vector<std::string> tx_paths, rx_paths;
}; };
#endif // _USRP_DEVICE_H_ #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_ps_si16_4n(short *, const float *, const float *, int);
void neon_convert_si16_ps_4n(float *, const short *, int); void neon_convert_si16_ps_4n(float *, const short *, int);
void convert_init(void) {
}
/* 4*N 16-bit signed integer conversion with remainder */ /* 4*N 16-bit signed integer conversion with remainder */
static void neon_convert_si16_ps(float *out, static void neon_convert_si16_ps(float *out,
const short *in, const short *in,
@@ -54,7 +57,6 @@ static void neon_convert_ps_si16(short *out,
for (int i = 0; i < len % 4; i++) for (int i = 0; i < len % 4; i++)
out[start + i] = (short) (in[start + i] * (*scale)); out[start + i] = (short) (in[start + i] * (*scale));
} }
#endif
void convert_float_short(short *out, const float *in, float scale, int len) void convert_float_short(short *out, const float *in, float scale, int len)
{ {

View File

@@ -27,10 +27,14 @@
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sched.h>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <GSMCommon.h> #include <GSMCommon.h>
#include <Logger.h> #include <Logger.h>
#include <Configuration.h>
extern "C" { extern "C" {
#include "convolve.h" #include "convolve.h"
@@ -61,7 +65,8 @@ extern "C" {
struct trx_config { struct trx_config {
std::string log_level; std::string log_level;
std::string addr; std::string local_addr;
std::string remote_addr;
std::string dev_args; std::string dev_args;
unsigned port; unsigned port;
unsigned tx_sps; unsigned tx_sps;
@@ -77,10 +82,11 @@ struct trx_config {
double rssi_offset; double rssi_offset;
bool swap_channels; bool swap_channels;
bool edge; bool edge;
int sched_rr;
std::vector<std::string> rx_paths;
std::vector<std::string> tx_paths;
}; };
ConfigurationTable gConfig;
volatile bool gshutdown = false; volatile bool gshutdown = false;
/* Setup configuration values /* Setup configuration values
@@ -93,6 +99,7 @@ volatile bool gshutdown = false;
bool trx_setup_config(struct trx_config *config) bool trx_setup_config(struct trx_config *config)
{ {
std::string refstr, fillstr, divstr, mcstr, edgestr; std::string refstr, fillstr, divstr, mcstr, edgestr;
std::vector<std::string>::const_iterator si;
if (config->mcbts && config->chans > 5) { if (config->mcbts && config->chans > 5) {
std::cout << "Unsupported number of channels" << std::endl; 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 << " Log Level............... " << config->log_level << std::endl;
ost << " Device args............. " << config->dev_args << std::endl; ost << " Device args............. " << config->dev_args << std::endl;
ost << " TRX Base Port........... " << config->port << 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 << " Channels................ " << config->chans << std::endl;
ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl; ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl;
ost << " Rx Samples-per-Symbol... " << config->rx_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 << " Tuning offset........... " << config->offset << std::endl;
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl; ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
ost << " Swap channels........... " << config->swap_channels << 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; return true;
} }
@@ -198,9 +214,10 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
Transceiver *trx; Transceiver *trx;
VectorFIFO *fifo; VectorFIFO *fifo;
trx = new Transceiver(config->port, config->addr.c_str(), trx = new Transceiver(config->port, config->local_addr.c_str(),
config->tx_sps, config->rx_sps, config->chans, config->remote_addr.c_str(), config->tx_sps,
GSM::Time(3,0), radio, config->rssi_offset); config->rx_sps, config->chans, GSM::Time(3,0),
radio, config->rssi_offset);
if (!trx->init(config->filler, config->rtsc, if (!trx->init(config->filler, config->rtsc,
config->rach_delay, config->edge)) { config->rach_delay, config->edge)) {
LOG(ALERT) << "Failed to initialize transceiver"; 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() static void print_help()
{ {
fprintf(stdout, "Options:\n" fprintf(stdout, "Options:\n"
@@ -246,6 +278,7 @@ static void print_help()
" -a UHD device args\n" " -a UHD device args\n"
" -l Logging level (%s)\n" " -l Logging level (%s)\n"
" -i IP address of GSM core\n" " -i IP address of GSM core\n"
" -j IP address of osmo-trx\n"
" -p Base port number\n" " -p Base port number\n"
" -e Enable EDGE receiver\n" " -e Enable EDGE receiver\n"
" -m Enable multi-ARFCN transceiver (default=disabled)\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" " -r Random Normal Burst test mode with TSC\n"
" -A Random Access Burst test mode with delay\n" " -A Random Access Burst test mode with delay\n"
" -R RSSI to dBm offset in dB (default=0)\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"); "EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
} }
static void handle_options(int argc, char **argv, struct trx_config *config) static void handle_options(int argc, char **argv, struct trx_config *config)
{ {
int option; int option;
bool tx_path_set = false, rx_path_set = false;
config->log_level = "NOTICE"; 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->port = DEFAULT_TRX_PORT;
config->tx_sps = DEFAULT_TX_SPS; config->tx_sps = DEFAULT_TX_SPS;
config->rx_sps = DEFAULT_RX_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->rssi_offset = 0.0;
config->swap_channels = false; config->swap_channels = false;
config->edge = 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) { switch (option) {
case 'h': case 'h':
print_help(); print_help();
@@ -297,7 +338,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->log_level = optarg; config->log_level = optarg;
break; break;
case 'i': case 'i':
config->addr = optarg; config->remote_addr = optarg;
break;
case 'j':
config->local_addr = optarg;
break; break;
case 'p': case 'p':
config->port = atoi(optarg); config->port = atoi(optarg);
@@ -343,6 +387,17 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
case 'e': case 'e':
config->edge = true; config->edge = true;
break; 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: default:
print_help(); print_help();
exit(0); exit(0);
@@ -379,6 +434,19 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
goto bad_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; return;
bad_config: bad_config:
@@ -386,6 +454,21 @@ bad_config:
exit(0); 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 main(int argc, char *argv[])
{ {
int type, chans, ref; int type, chans, ref;
@@ -424,6 +507,11 @@ int main(int argc, char *argv[])
handle_options(argc, argv, &config); handle_options(argc, argv, &config);
if (config.sched_rr != -1) {
if (set_sched_rr(config.sched_rr) < 0)
return EXIT_FAILURE;
}
setup_signal_handlers(); setup_signal_handlers();
/* Check database sanity */ /* Check database sanity */
@@ -432,7 +520,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7); gLogInit(config.log_level.c_str());
srandom(time(NULL)); srandom(time(NULL));
@@ -448,7 +536,7 @@ int main(int argc, char *argv[])
ref = RadioDevice::REF_INTERNAL; ref = RadioDevice::REF_INTERNAL;
usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface, 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); type = usrp->open(config.dev_args, ref, config.swap_channels);
if (type < 0) { if (type < 0) {
LOG(ALERT) << "Failed to create radio device" << std::endl; 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, 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 */ /** Initialize the USRP */
virtual int open(const std::string &args, int ref, bool swap_channels)=0; virtual int open(const std::string &args, int ref, bool swap_channels)=0;
@@ -136,6 +138,18 @@ class RadioDevice {
/** return minimum Tx Gain **/ /** return minimum Tx Gain **/
virtual double minTxGain(void) = 0; 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 */ /** Return internal status values */
virtual double getTxFreq(size_t chan = 0) = 0; virtual double getTxFreq(size_t chan = 0) = 0;
virtual double getRxFreq(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 #define CLIP_THRESH 30000.0f
/** Lookup tables for trigonometric approximation */ /** Lookup tables for trigonometric approximation */
static float cosTable[TABLESIZE+1]; // add 1 element for wrap around static float sincTable[TABLESIZE+1]; // add 1 element for wrap around
static float sinTable[TABLESIZE+1];
static float sincTable[TABLESIZE+1];
/** Constants */ /** Constants */
static const float M_PI_F = (float)M_PI; 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 */ /* Precomputed rotation vectors */
static signalVector *GMSKRotation4 = NULL; static signalVector *GMSKRotation4 = NULL;
@@ -182,29 +178,6 @@ static float vectorNorm2(const signalVector &x)
return Energy; return Energy;
} }
/** 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 * Initialize 4 sps and 1 sps rotation tables
*/ */
@@ -216,11 +189,11 @@ static void initGMSKRotationTables()
GMSKReverseRotation4 = new signalVector(len4); GMSKReverseRotation4 = new signalVector(len4);
signalVector::iterator rotPtr = GMSKRotation4->begin(); signalVector::iterator rotPtr = GMSKRotation4->begin();
signalVector::iterator revPtr = GMSKReverseRotation4->begin(); signalVector::iterator revPtr = GMSKReverseRotation4->begin();
float phase = 0.0; auto phase = 0.0;
while (rotPtr != GMSKRotation4->end()) { while (rotPtr != GMSKRotation4->end()) {
*rotPtr++ = expjLookup(phase); *rotPtr++ = complex(cos(phase), sin(phase));
*revPtr++ = expjLookup(-phase); *revPtr++ = complex(cos(-phase), sin(-phase));
phase += M_PI_F / 2.0F / 4.0; phase += M_PI / 2.0 / 4.0;
} }
GMSKRotation1 = new signalVector(len1); GMSKRotation1 = new signalVector(len1);
@@ -229,9 +202,9 @@ static void initGMSKRotationTables()
revPtr = GMSKReverseRotation1->begin(); revPtr = GMSKReverseRotation1->begin();
phase = 0.0; phase = 0.0;
while (rotPtr != GMSKRotation1->end()) { while (rotPtr != GMSKRotation1->end()) {
*rotPtr++ = expjLookup(phase); *rotPtr++ = complex(cos(phase), sin(phase));
*revPtr++ = expjLookup(-phase); *revPtr++ = complex(cos(-phase), sin(-phase));
phase += M_PI_F / 2.0F; phase += M_PI / 2.0;
} }
} }
@@ -585,7 +558,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
int guardPeriodLength, int sps) int guardPeriodLength, int sps)
{ {
int burst_len; int burst_len;
signalVector *pulse, rotated, *shaped; signalVector *pulse, rotated;
signalVector::iterator itr; signalVector::iterator itr;
pulse = GSMPulse1->empty; pulse = GSMPulse1->empty;
@@ -602,11 +575,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
rotated.isReal(false); rotated.isReal(false);
/* Dummy filter operation */ /* Dummy filter operation */
shaped = convolve(&rotated, pulse, NULL, START_ONLY); return convolve(&rotated, pulse, NULL, START_ONLY);
if (!shaped)
return NULL;
return shaped;
} }
static void rotateBurst2(signalVector &burst, double phase) static void rotateBurst2(signalVector &burst, double phase)
@@ -626,8 +595,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
{ {
int burst_len, sps = 4; int burst_len, sps = 4;
float phase; float phase;
signalVector *c0_pulse, *c1_pulse, *c0_burst; signalVector *c0_pulse, *c1_pulse, *c0_shaped, *c1_shaped;
signalVector *c1_burst, *c0_shaped, *c1_shaped;
signalVector::iterator c0_itr, c1_itr; signalVector::iterator c0_itr, c1_itr;
c0_pulse = GSMPulse4->c0; c0_pulse = GSMPulse4->c0;
@@ -638,13 +606,12 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
burst_len = 625; burst_len = 625;
c0_burst = new signalVector(burst_len, c0_pulse->size()); signalVector c0_burst(burst_len, c0_pulse->size());
c0_burst->isReal(true); c0_burst.isReal(true);
c0_itr = c0_burst->begin(); c0_itr = c0_burst.begin();
c1_burst = new signalVector(burst_len, c1_pulse->size()); signalVector c1_burst(burst_len, c1_pulse->size());
c1_burst->isReal(true); c1_itr = c1_burst.begin();
c1_itr = c1_burst->begin();
/* Padded differential tail bits */ /* Padded differential tail bits */
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0; *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
@@ -660,10 +627,10 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0; *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
/* Generate C0 phase coefficients */ /* Generate C0 phase coefficients */
GMSKRotate(*c0_burst, sps); GMSKRotate(c0_burst, sps);
c0_burst->isReal(false); c0_burst.isReal(false);
c0_itr = c0_burst->begin(); c0_itr = c0_burst.begin();
c0_itr += sps * 2; c0_itr += sps * 2;
c1_itr += sps * 2; c1_itr += sps * 2;
@@ -688,8 +655,8 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
*c1_itr = *c0_itr * Complex<float>(0, phase); *c1_itr = *c0_itr * Complex<float>(0, phase);
/* Primary (C0) and secondary (C1) pulse shaping */ /* Primary (C0) and secondary (C1) pulse shaping */
c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY); c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY); c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
/* Sum shaped outputs into C0 */ /* Sum shaped outputs into C0 */
c0_itr = c0_shaped->begin(); c0_itr = c0_shaped->begin();
@@ -697,10 +664,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits)
for (unsigned i = 0; i < c0_shaped->size(); i++ ) for (unsigned i = 0; i < c0_shaped->size(); i++ )
*c0_itr++ += *c1_itr++; *c0_itr++ += *c1_itr++;
delete c0_burst;
delete c1_burst;
delete c1_shaped; delete c1_shaped;
return c0_shaped; return c0_shaped;
} }
@@ -774,7 +738,6 @@ static signalVector *mapEdgeSymbols(const BitVector &bits)
static signalVector *shapeEdgeBurst(const signalVector &symbols) static signalVector *shapeEdgeBurst(const signalVector &symbols)
{ {
size_t nsyms, nsamps = 625, sps = 4; size_t nsyms, nsamps = 625, sps = 4;
signalVector *burst, *shape;
signalVector::iterator burst_itr; signalVector::iterator burst_itr;
nsyms = symbols.size(); nsyms = symbols.size();
@@ -782,10 +745,10 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
if (nsyms * sps > nsamps) if (nsyms * sps > nsamps)
nsyms = 156; nsyms = 156;
burst = new signalVector(nsamps, GSMPulse4->c0->size()); signalVector burst(nsamps, GSMPulse4->c0->size());
/* Delay burst by 1 symbol */ /* Delay burst by 1 symbol */
burst_itr = burst->begin() + sps; burst_itr = burst.begin() + sps;
for (size_t i = 0; i < nsyms; i++) { for (size_t i = 0; i < nsyms; i++) {
float phase = i * 3.0f * M_PI / 8.0f; float phase = i * 3.0f * M_PI / 8.0f;
Complex<float> rot = Complex<float>(cos(phase), sin(phase)); Complex<float> rot = Complex<float>(cos(phase), sin(phase));
@@ -795,10 +758,7 @@ static signalVector *shapeEdgeBurst(const signalVector &symbols)
} }
/* Single Gaussian pulse approximation shaping */ /* Single Gaussian pulse approximation shaping */
shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY); return convolve(&burst, GSMPulse4->c0, NULL, START_ONLY);
delete burst;
return shape;
} }
/* /*
@@ -812,40 +772,36 @@ signalVector *genRandNormalBurst(int tsc, int sps, int tn)
return NULL; return NULL;
int i = 0; int i = 0;
BitVector *bits = new BitVector(148); BitVector bits(148);
signalVector *burst;
/* Tail bits */ /* Tail bits */
for (; i < 3; i++) for (; i < 3; i++)
(*bits)[i] = 0; bits[i] = 0;
/* Random bits */ /* Random bits */
for (; i < 60; i++) for (; i < 60; i++)
(*bits)[i] = rand() % 2; bits[i] = rand() % 2;
/* Stealing bit */ /* Stealing bit */
(*bits)[i++] = 0; bits[i++] = 0;
/* Training sequence */ /* Training sequence */
for (int n = 0; i < 87; i++, n++) for (int n = 0; i < 87; i++, n++)
(*bits)[i] = gTrainingSequence[tsc][n]; bits[i] = gTrainingSequence[tsc][n];
/* Stealing bit */ /* Stealing bit */
(*bits)[i++] = 0; bits[i++] = 0;
/* Random bits */ /* Random bits */
for (; i < 145; i++) for (; i < 145; i++)
(*bits)[i] = rand() % 2; bits[i] = rand() % 2;
/* Tail bits */ /* Tail bits */
for (; i < 148; i++) for (; i < 148; i++)
(*bits)[i] = 0; bits[i] = 0;
int guard = 8 + !(tn % 4); int guard = 8 + !(tn % 4);
burst = modulateBurst(*bits, guard, sps); return modulateBurst(bits, guard, sps);
delete bits;
return burst;
} }
/* /*
@@ -861,30 +817,26 @@ signalVector *genRandAccessBurst(int delay, int sps, int tn)
return NULL; return NULL;
int i = 0; int i = 0;
BitVector *bits = new BitVector(88+delay); BitVector bits(88 + delay);
signalVector *burst;
/* delay */ /* delay */
for (; i < delay; i++) for (; i < delay; i++)
(*bits)[i] = 0; bits[i] = 0;
/* head and synch bits */ /* head and synch bits */
for (int n = 0; i < 49+delay; i++, n++) for (int n = 0; i < 49+delay; i++, n++)
(*bits)[i] = gRACHBurst[n]; bits[i] = gRACHBurst[n];
/* Random bits */ /* Random bits */
for (; i < 85+delay; i++) for (; i < 85+delay; i++)
(*bits)[i] = rand() % 2; bits[i] = rand() % 2;
/* Tail bits */ /* Tail bits */
for (; i < 88+delay; i++) for (; i < 88+delay; i++)
(*bits)[i] = 0; bits[i] = 0;
int guard = 68-delay + !(tn % 4); int guard = 68-delay + !(tn % 4);
burst = modulateBurst(*bits, guard, sps); return modulateBurst(bits, guard, sps);
delete bits;
return burst;
} }
signalVector *generateEmptyBurst(int sps, int tn) signalVector *generateEmptyBurst(int sps, int tn)
@@ -921,17 +873,17 @@ signalVector *generateEdgeBurst(int tsc)
if ((tsc < 0) || (tsc > 7)) if ((tsc < 0) || (tsc > 7))
return NULL; return NULL;
signalVector *shape, *burst = new signalVector(148); signalVector burst(148);
const BitVector *midamble = &gEdgeTrainingSequence[tsc]; const BitVector *midamble = &gEdgeTrainingSequence[tsc];
/* Tail */ /* Tail */
int n, i = 0; int n, i = 0;
for (; i < tail; i++) for (; i < tail; i++)
(*burst)[i] = psk8_table[7]; burst[i] = psk8_table[7];
/* Body */ /* Body */
for (; i < tail + data; i++) for (; i < tail + data; i++)
(*burst)[i] = psk8_table[rand() % 8]; burst[i] = psk8_table[rand() % 8];
/* TSC */ /* TSC */
for (n = 0; i < tail + data + train; i++, n++) { for (n = 0; i < tail + data + train; i++, n++) {
@@ -939,21 +891,18 @@ signalVector *generateEdgeBurst(int tsc)
(((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) | (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
(((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2); (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
(*burst)[i] = psk8_table[index]; burst[i] = psk8_table[index];
} }
/* Body */ /* Body */
for (; i < tail + data + train + data; i++) for (; i < tail + data + train + data; i++)
(*burst)[i] = psk8_table[rand() % 8]; burst[i] = psk8_table[rand() % 8];
/* Tail */ /* Tail */
for (; i < tail + data + train + data + tail; i++) for (; i < tail + data + train + data + tail; i++)
(*burst)[i] = psk8_table[7]; burst[i] = psk8_table[7];
shape = shapeEdgeBurst(*burst); return shapeEdgeBurst(burst);
delete burst;
return shape;
} }
/* /*
@@ -989,7 +938,7 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
int guard_len, int sps) int guard_len, int sps)
{ {
int burst_len; int burst_len;
signalVector *pulse, *burst, *shaped; signalVector *pulse;
signalVector::iterator burst_itr; signalVector::iterator burst_itr;
if (sps == 1) if (sps == 1)
@@ -999,9 +948,9 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
burst_len = sps * (bits.size() + guard_len); burst_len = sps * (bits.size() + guard_len);
burst = new signalVector(burst_len, pulse->size()); signalVector burst(burst_len, pulse->size());
burst->isReal(true); burst.isReal(true);
burst_itr = burst->begin(); burst_itr = burst.begin();
/* Raw bits are not differentially encoded */ /* Raw bits are not differentially encoded */
for (unsigned i = 0; i < bits.size(); i++) { for (unsigned i = 0; i < bits.size(); i++) {
@@ -1009,15 +958,11 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
burst_itr += sps; burst_itr += sps;
} }
GMSKRotate(*burst, sps); GMSKRotate(burst, sps);
burst->isReal(false); burst.isReal(false);
/* Single Gaussian pulse approximation shaping */ /* Single Gaussian pulse approximation shaping */
shaped = convolve(burst, pulse, NULL, START_ONLY); return convolve(&burst, pulse, NULL, START_ONLY);
delete burst;
return shaped;
} }
/* Assume input bits are not differentially encoded */ /* Assume input bits are not differentially encoded */
@@ -1034,16 +979,10 @@ signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
static void generateSincTable() static void generateSincTable()
{ {
float x;
for (int i = 0; i < TABLESIZE; i++) { for (int i = 0; i < TABLESIZE; i++) {
x = (float) i / TABLESIZE * 8 * M_PI; auto x = (double) i / TABLESIZE * 8 * M_PI;
if (fabs(x) < 0.01) { auto y = sin(x) / x;
sincTable[i] = 1.0f; sincTable[i] = std::isnan(y) ? 1.0 : y;
continue;
}
sincTable[i] = sinf(x) / x;
} }
} }
@@ -1516,19 +1455,16 @@ float energyDetect(const signalVector &rxBurst, unsigned windowLength)
static signalVector *downsampleBurst(const signalVector &burst) static signalVector *downsampleBurst(const signalVector &burst)
{ {
signalVector *in, *out; 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));
in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len()); if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_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) { (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
delete out; delete out;
out = NULL; out = NULL;
} }
delete in;
return out; return out;
}; };
@@ -1621,7 +1557,6 @@ static int detectGeneralBurst(const signalVector &rxBurst,
{ {
int rc, start, len; int rc, start, len;
bool clipping = false; bool clipping = false;
signalVector *corr;
if ((sps != 1) && (sps != 4)) if ((sps != 1) && (sps != 4))
return -SIGERR_UNSUPPORTED; return -SIGERR_UNSUPPORTED;
@@ -1637,12 +1572,10 @@ static int detectGeneralBurst(const signalVector &rxBurst,
start = target - head - 1; start = target - head - 1;
len = head + tail; 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); thresh, sps, &amp, &toa, start, len);
delete corr;
if (rc < 0) { if (rc < 0) {
return -SIGERR_INTERNAL; return -SIGERR_INTERNAL;
} else if (!rc) { } else if (!rc) {
@@ -1921,7 +1854,6 @@ SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
bool sigProcLibSetup() bool sigProcLibSetup()
{ {
initTrigTables();
generateSincTable(); generateSincTable();
initGMSKRotationTables(); initGMSKRotationTables();

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 along with this program. If not, see <http://www.gnu.org/licenses/>.
dnl 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_PREREQ(2.57)
AC_CONFIG_SRCDIR([Transceiver52M/Makefile.am]) AC_CONFIG_SRCDIR([Transceiver52M/Makefile.am])
AC_CONFIG_AUX_DIR([.]) AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([config]) AC_CONFIG_MACRO_DIR([config])
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
AC_CONFIG_TESTDIR(tests)
AC_CANONICAL_BUILD AC_CANONICAL_BUILD
AC_CANONICAL_HOST AC_CANONICAL_HOST
@@ -34,6 +37,10 @@ AM_INIT_AUTOMAKE([subdir-objects])
dnl Linux kernel KBuild style compile messages dnl Linux kernel KBuild style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
AM_PROG_AS AM_PROG_AS
AC_PROG_CXX AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_11 AX_CXX_COMPILE_STDCXX_11
@@ -42,6 +49,13 @@ AC_PROG_MAKE_SET
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm]) 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_LIBTOOL_WIN32_DLL
AC_ENABLE_SHARED dnl do build shared libraries AC_ENABLE_SHARED dnl do build shared libraries
AC_DISABLE_STATIC dnl don't build static libraries AC_DISABLE_STATIC dnl don't build static libraries
@@ -106,7 +120,6 @@ AS_IF([test "x$with_usrp1" != "xyes"],[
)] )]
) )
AC_DEFINE(USE_UHD, 1, All UHD versions) AC_DEFINE(USE_UHD, 1, All UHD versions)
PKG_CHECK_MODULES(FFTWF, fftw3f)
]) ])
AS_IF([test "x$with_singledb" = "xyes"], [ AS_IF([test "x$with_singledb" = "xyes"], [
@@ -152,10 +165,8 @@ 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, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
AM_CONDITIONAL(ARCH_ARM_A15, [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(LIBUSB, libusb-1.0)
PKG_CHECK_MODULES(SQLITE3, sqlite3) PKG_CHECK_MODULES(FFTWF, fftw3f)
AC_CHECK_HEADER([boost/config.hpp],[], AC_CHECK_HEADER([boost/config.hpp],[],
[AC_MSG_ERROR([boost/config.hpp not found, install e.g. libboost-dev])]) [AC_MSG_ERROR([boost/config.hpp not found, install e.g. libboost-dev])])
@@ -168,6 +179,9 @@ AC_CONFIG_FILES([\
Transceiver52M/Makefile \ Transceiver52M/Makefile \
Transceiver52M/arm/Makefile \ Transceiver52M/arm/Makefile \
Transceiver52M/x86/Makefile \ Transceiver52M/x86/Makefile \
tests/Makefile \
tests/CommonLibs/Makefile \
tests/Transceiver52M/Makefile \
]) ])
AC_OUTPUT AC_OUTPUT

View File

@@ -1,7 +1,63 @@
#!/bin/sh #!/bin/sh
set -ex 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 autoreconf --install --force
./configure ./configure $INSTR
$MAKE $PARALLEL_MAKE $MAKE $PARALLEL_MAKE
$MAKE check \ $MAKE check \
|| cat-testlogs.sh || 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 osmo-trx (0.1.9) trusty; urgency=medium
* Ask Ivan, really * Ask Ivan, really

4
debian/control vendored
View File

@@ -5,8 +5,6 @@ Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
Build-Depends: debhelper (>= 9), Build-Depends: debhelper (>= 9),
autotools-dev, autotools-dev,
autoconf-archive, autoconf-archive,
libdbd-sqlite3,
libsqlite3-dev,
pkg-config, pkg-config,
dh-autoreconf, dh-autoreconf,
libuhd-dev, libuhd-dev,
@@ -20,7 +18,7 @@ Homepage: https://projects.osmocom.org/projects/osmotrx
Package: osmo-trx Package: osmo-trx
Architecture: any 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 Description: SDR transceiver that implements Layer 1 of a GSM BTS
OsmoTRX is a software-defined radio transceiver that implements the Layer 1 OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications: 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. the U.S. Army Research Laboratory.
License: BSD-3-clause 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/* Files: debian/*
Copyright: 2015 Ruben Undheim <ruben.undheim@gmail.com> Copyright: 2015 Ruben Undheim <ruben.undheim@gmail.com>
License: GPL-3+ 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; InterthreadQueue<int> gQ;
InterthreadMap<int,int> gMap; 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*) void* qWriter(void*)
{ {
int *p; int *p;
for (int i=0; i<20; i++) { for (int i=0; i<20; i++) {
p = new int; p = new int;
*p = i; *p = i;
COUT("queue write " << *p); CERR("queue write " << *p);
gQ.write(p); gQ.write(p);
q_last_write_val = i;
if (random()%2) sleep(1); if (random()%2) sleep(1);
} }
p = new int; p = new int;
@@ -56,8 +62,14 @@ void* qReader(void*)
bool done = false; bool done = false;
while (!done) { while (!done) {
int *p = gQ.read(); int *p = gQ.read();
COUT("queue read " << *p); CERR("queue read " << *p);
if (*p<0) done=true; 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; delete p;
} }
return NULL; return NULL;
@@ -70,8 +82,9 @@ void* mapWriter(void*)
for (int i=0; i<20; i++) { for (int i=0; i<20; i++) {
p = new int; p = new int;
*p = i; *p = i;
COUT("map write " << *p); CERR("map write " << *p);
gMap.write(i,p); gMap.write(i,p);
m_last_write_val = i;
if (random()%2) sleep(1); if (random()%2) sleep(1);
} }
return NULL; return NULL;
@@ -81,7 +94,9 @@ void* mapReader(void*)
{ {
for (int i=0; i<20; i++) { for (int i=0; i<20; i++) {
int *p = gMap.read(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 // InterthreadMap will delete the pointers
// delete p; // delete p;
} }
@@ -109,6 +124,13 @@ int main(int argc, char *argv[])
qWriterThread.join(); qWriterThread.join();
mapReaderThread.join(); mapReaderThread.join();
mapWriterThread.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. * This software is distributed under the terms of the GNU Affero Public License.
@@ -23,23 +24,25 @@
*/ */
#include "Timeval.h"
#include <iostream> #include <iostream>
#include <iterator>
using namespace std; #include "Logger.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
gLogInit("NOTICE");
Timeval then(10000); Log(LOG_EMERG).get() << " testing the logger.";
cout << then.elapsed() << endl; Log(LOG_ALERT).get() << " testing the logger.";
Log(LOG_CRIT).get() << " testing the logger.";
while (!then.passed()) { Log(LOG_ERR).get() << " testing the logger.";
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl; Log(LOG_WARNING).get() << " testing the logger.";
usleep(500000); Log(LOG_NOTICE).get() << " testing the logger.";
} Log(LOG_INFO).get() << " testing the logger.";
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl; 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

File diff suppressed because one or more lines are too long

View File

@@ -30,21 +30,27 @@
#include "Threads.h" #include "Threads.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <signal.h>
static const int gNumToSend = 10; static const int gNumToSend = 10;
static void sigalarm_handler(int foo)
void *testReaderIP(void *)
{ {
UDPSocket readSocket(5934, "localhost", 5061); printf("FAIL: test did not run successfully\n");
readSocket.nonblocking(); exit(EXIT_FAILURE);
}
void *testReaderIP(void *param)
{
UDPSocket *readSocket = (UDPSocket *)param;
readSocket->nonblocking();
int rc = 0; int rc = 0;
while (rc<gNumToSend) { while (rc<gNumToSend) {
char buf[MAX_UDP_LENGTH]; char buf[MAX_UDP_LENGTH] = { 0 };
int count = readSocket.read(buf, MAX_UDP_LENGTH); int count = readSocket->read(buf, MAX_UDP_LENGTH);
if (count>0) { if (count>0) {
COUT("read: " << buf); CERR("read: " << buf);
rc++; rc++;
} else { } else {
sleep(2); sleep(2);
@@ -53,51 +59,42 @@ void *testReaderIP(void *)
return NULL; 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 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; Thread readerThreadIP;
readerThreadIP.start(testReaderIP,NULL); readerThreadIP.start(testReaderIP, &readSocket);
Thread readerThreadUnix;
readerThreadUnix.start(testReaderUnix,NULL);
UDPSocket socket1(5061, "127.0.0.1",5934);
UDDSocket socket1U("testSource","testDestination");
COUT("socket1: " << socket1.port());
// give the readers time to open // give the readers time to open
sleep(1); sleep(1);
for (int i=0; i<gNumToSend; i++) { for (int i=0; i<gNumToSend; i++) {
socket1.write("Hello IP land"); CERR("write");
socket1U.write("Hello Unix domain"); count = socket1.write("Hello IP land");
sleep(1); if (count < 0) {
COUT("FAIL: write");
exit(EXIT_FAILURE);
}
sleep(1);
} }
readerThreadIP.join(); readerThreadIP.join();
readerThreadUnix.join();
printf("Done\n");
} }
// vim: ts=4 sw=4 // 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 "Vector.h"
#include <iostream> #include <iostream>
// We must have a gConfig now to include Vector.
#include "Configuration.h"
ConfigurationTable gConfig;
using namespace std; using namespace std;
typedef Vector<int> TestVector; 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 <stdio.h>
#include <string.h> #include <string.h>
#include <osmocom/core/utils.h> #include <stdlib.h>
#include "../../Transceiver52M/common/convolve.h" #include "../../Transceiver52M/common/convolve.h"
#define TESTVEC_LEN 1000 #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