Age | Commit message (Collapse) | Author | Files | Lines |
|
This hack allows OsmoBTS to correctly restart itself with different parameters.
We assume that transceiver is run as a service and will be restarted on exit.
|
|
This change reveals some issue with the UHD start/stop code. Specifically,
we get a failed assert in RadioInterface::pullBuffer() (num_rd == OUTCHUNK
with num_rd=0) with the POWERON/POWEROFF/POWERON sequence.
|
|
The reason is to allow them to be started from any TRX. I.e. they are started
when the first TRX starts and stopped when the last TRX stops.
|
|
delete operator.
|
|
It's very basic at this moment. We should add a stress-test for thread
start/stop at least.
|
|
|
|
should shut down cleanly.
|
|
Also note that we introduced shutdown() method for Transceiver threads which
implement proper shutdown of threads when they are in blocking read state.
This involves using shutdown() on sockets and pushing NULL to queues.
With this change we should be able to start/stop transceiver channels at
arbitrary moments.
|
|
Current implementation strictly synchronize thread startup and shutdown
to make sure a thread is actually started on startThread() exit and
that it's stopped on stopThread() exit (or an error is returned).
I also changed the Thread class to be used as a parent class for
an actual thread. This way we could provide much better logical
separation between variables used by different threads. Which will
(hopefully) reduce number of issues with inter-thread communications.
|
|
pthread_cond_timedwait() returns.
|
|
This method is useful to abort a blocking operations on a socket during shutdown.
|
|
We need a way to stop InterthreadQueue blocking read to be able to shutdown
a thread. The easiest way to do that is to push NULL to the queue, but the
original implementation will just ignore that and continue blocking. After
the change the blocking read() will exit with NULL result which is perfectly
fine with us.
Ideally we should change all methods of InterthreadQueue to return a status
value to indicate normal exits, timeouts, etc. Right now the only way to
indicate an error is returning NULL, which could be a valid operation.
|
|
|
|
|
|
|
|
statically allocated memory.
|
|
|
|
|
|
|
|
|
|
|
|
Inside the drive loop addRadioVector() is duplicate call that was
not removed from the previous separation of the main loop and
transceiver instances.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
This patch aligns the multicarrier (MC) USRP code with
released GSM core changes that accommodate the MC RAD1.
Primary changes are:
1. Runtime setting of number of channelizer paths
2. Matching channelizer path to ARFCN mapping of GSM core
3. Use a single clock update socket on the drive loop
4. Match transceiver data and control socket ports
Setting of channelizer paths (or width) was previously fixed
at compile time. In either case, channelizer width is limited
by the sample rate of the device and channel spacing of the
maximally decimated filterbank. Available settings are 1, 5,
and 10 channels, which accommodate any number of ARFCN's in
between. Also add the frequency offsets to handle the effective
shift in setting RF frequency.
Previous assumption was to place C0 at the center frequency,
but RAD1 assumes C0 at the leftmost carrier, so adjust
accordingly.
The rest is general consolidation to mostly match the RAD1
interaction with GSM core. There is some loss of flexibility to
run, say, multiple independent instances of OpenBTS through a
single bank of channelized transceivers. But, the better
compatibility and reduction in code is the appropriate tradeoff.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
This patches fixes the hypothetical bug in the read out of the
intermediate sample buffer after a local overflow condition.
Local overflows - occurring in the intermediate storage buffer
and not the UHD transport - should never occur; the existence
of a local overflow indicates a significant error elsewhere in
the system. For example, if timestamps or timing offsets are
ridiculously off, such errors may occur.
Nonetheless, handle errors anyways by taking the modulo value
of the calculated read index to stay within the buffer and avoid
seg faulting.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Move from the hard coded case of 3 transceiver instances to a
command line determined value. 'M' potential channels will be
compiled into the build depending on preprocessor selections
in radioParams.h. The command line argument must be less M.
Channels are selected starting from 0, which is centered on the
RF tuning frequency. Subsequent channels are selected by shifting
outward from 0 (center) in a left before right pattern. Default
channel spacing is 400 kHz. The ordering for supported cases of
1, 5, and 10 path channelizers is as follows.
CHAN_M = 1
{ 0 }
CHAN_M = 5
{ 0, 1, 4, 2, 3 }
CHAN_M = 10
{ 0, 1, 9, 2, 8, 3, 7, 4, 6, 5}
Note: Channel 5 for the 10 channel case sits on the Nyquist
frequency and is therefor unusable.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Similar to the previous commit titled,
"multi-arfcn, trx: allocate threads on heap and fix thread release"
there is the potential for a segfault on exit if the event thread
is never started. As before, address the issue by initializing
the Thread pointer with NULL and later allocating the object
immediately prior to use.
On stop or exit, allow the thread to exit by checking a condition
variable. If device is stopped or never started, the same variable
can be checked for state, which avoids attempts to deallocate an
empty pointer.
If there is a better method to shutdown / deallocate using the
OpenBTS thread library, please let me know.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
The original split-transceiver abstraction did not maintain
internal instances of the radio interface or drive loop.
The FIFO's were attached through external calls. The control
loop, however, made such an approach overly difficult, so
the transceiver now maintains pointers to the aforementioned
objects. In doing so, we no longer need external attachment
calls to setup the FIFO's.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
This fixes a bug where the energy threshold may reach infinity.
The transceiver energy detection threshold increase is
dependent on elapsed frames and the previous false detection
time. If we assume a (0,0) start time with the actual start
time - randomly determined - it's possible to get very
large elapsed frame counts at start. Once the threshold hits
'inf' further calculations are impossible and transceiver
is locked out from use.
Use the actual start time for initializing variables so
we avoid this scenario.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Previous approach was to allow stack unwinding to take care
shutdown and thread ending, which was unpredictable and
occasionally segfault. Attempt to shutdown more gracefully.
There are thread cancellation points in the transceiver code
using pthread_testcancel(), but the thread abstraction library
does not allow direct access to the pthread variables. This
prevents thread shutdown through pthread_cancel(). To get
around this, use boolean status values in the receive socket
service loops and main drive loop.
The socket read calls will block indefinitly, so shutdown
may cause the socket implementation to throw a SocketError
exception. Use of timeout values with reads does not seem to
work correctly or reliably, so catch the exception and ignore
if it occurs on shutdown.
The following error may appear as the socket is shutdown while
the Transceiver is blocking on read().
DatagramSocket::read() failed: Bad file descriptor
So be it; the API doesn't allow us to do any more.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
The underlying pthread of the Thread object isn't created until
Thread::start(). If the Thread object is contructed, but not
started, then the destructor will fail with a variety of
unpredictable errors such as the following or double free() in
certain cases.
Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0x3811abed3e946178) at malloc.c:2972
2972 if (chunk_is_mmapped(p))
If the Thread object is stack allocated, but start() isn't called,
destructor is guaranteed to run and will fail. The previous
approach was to dynamically allocate threads, but not free them,
thus avoiding memory errors, but creating memory leaks.
To get around this limitation, dynamically allocate Thread objects
and initialize with NULL. Then allocate immediately prior to start
such that pthread allocation is tied to the Thread object
constructor. Deallocation can check that the Thread pointer is
valid through NULL or other tracking methods.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
This call is a remnant of the Transceiver / DriveLoop split. The
empty call is never used.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
At one point an attach() call was used to connect
multiple transceivers to the radio interface. The
current approach is to pass the radio interface to
the transceiver instances through the constructor.
Remove the unused and deprecated call.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Certain notable variables - sample buffers - are not
allocated until start(), which causes a segfault if the
transceiver is shutdown without the radio starting. Check
that the radio is 'started' before releasing in the
destructor.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Lack of an explicitly defined virtual destructor was
causing the empty default interface destructor to be
called, which created a memory leak at shutdown.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Add a transceiver main() for multi-arfcn use and modify single
channel transceiver for use with updated interfaces.
Setup multiTRX with 3 channels for default case.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
This patch separates the 'Transceiver' into a multi-channel
I/O component and single channel component. The latter may
may have multiple instances. The receive FIFO is converted to
a thread-safe queue.
The 'TransceiverIO' continuously drives the receive and transmit
loops. In this process, bursts are driven into thread-safe FIFO's
and read from the priority queues. Filler bursts are inserted if
no transmit data is available.
Each 'Transceiver' instance attaches to the I/O object and creates
its own threads and sockets, which include blocking on the receive
FIFO for the attached channel. Each instance also handles its own
control loop and clock indications.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
The radio interface needs to feed the device I/O buffers
synchronously in order to drive the channelizer. Asynchronous
channel access occurs opposite the radio interface through
a bank of thread-safe FIFO's or priority queue's on receive
and transmit sides respectively.
Setup 'M' channels and allow only a subset to be active at a
given time. When a channel is unused, there is no need to
feed the particular receive FIFO or pull data from the
channel priority queue.
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
Signed-off-by: Thomas Tsou <ttsou@vt.edu>
|
|
|
|
Before, we assumed that non-B100 device was implicitly a USRP2
(inclusive of N200/N210). Make the check explicit so that any
unknown device will causes an error and exit.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
UHD will throw if something goes awry in these sensitive sections,
so we should catch and shutdown gracefully. There is no recovery
if we can't set rates.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
We're performance floating point comparisons so allow a
10 Hz offset when UHD does not return an exact sample rate;
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
Remove the built time resampling selection and link both options.
Move the normal push/pullBuffer() calls back to the base class and
overload them in the inherited resampling class.
USRP2/N2xx devices are the only devices that require resampling so
return that resampling is necessary on the device open(), which is
the point at which the device type will be known.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
The GSM transceiver only operates at a whole number multiple of
the GSM rate and doesn't care about the actual device rate and
if resampling is used. Therefore GSM specific portion of the
transceiver should only need to submit the samples-per-symbol
value to the device interface.
Then, the device should be able to determine the appropriate
sample rate (400 ksps or 270.833 ksps) and if resampling is
appropriate.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
The transceiver only uses a single integer oversampling value,
which is more simply referred to as samples-per-symbol.
mRadioOversampling --> mSPS
mTransceiverOversampling (removed)
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
Periodic timing alignment should never be required for UHD devices,
though the mechanism was used as a fallback mechanism should UHD
not properly recover after an underrun - as may occur in old
003.003.000 based revisions. This issue is not a concern in more
recent UHD releases and deprecates this code for legacy USRP1
use only.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
Previously, two timing correction values were used for UHD devices
depending on the sample rate of 270.833e3 or 400e3 for native GSM or
resampled device rate respectively. The correction values compensate
for residual timing effects due to analog component delays, filters
lag times, and general fudge factors. These values are device
specific and over-generalized by the two value configuration.
This patch adds the following struct to store these correction
values by device type and sample rate - through samples-per-symbol.
struct uhd_dev_offset {
enum uhd_dev_type type;
int sps;
double offset;
};
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
UHD device type was previously detected, but only categorized in
terms of bus type, USB or Ethernet, and sample rate capability.
With the number of supported device increasing, we can no longer
easily group devices since we need to handle more and more
device-specific peculiarities. Some of these factors are managed
internally by the UHD driver, but other factors (e.g. timing
offsets) are specific to a single device.
Start by maintaining an enumerated list of relevant device types
that we can use for applying device specific operations. Also
rename the USB/Ethernet grouping to transmit window type because
that's what it is.
enum uhd_dev_type {
USRP1,
USRP2,
B100,
NUM_USRP_TYPES,
};
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
Feed the second channel with the same data buffer as channel one.
The two channel send maintains the same UHD interface, so we use
the same metadata for both channels. Hard code the second channel
RF frequency as an offset relative to first channel for now.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|
|
This patch is long overdue and can now be merged after better understanding
of timestamp stability issues. UHD tick / timespec conversions were
generally used with the streamer interface, though these calls are actually
independent change sets. The combination would lead to internal rounding
errors and a timing drift most notably on B100 running at GSM symbol
rate multiples. There are no known issues, however, with the streamer code
itself.
The aforementioned issue was discovered in test code only, which was never
merged to mainline.
Signed-off-by: Thomas Tsou <tom@tsou.cc>
|