This limit allows implementing a timeout: if a TX underrun or RX overrun
continues for the specified number of bytes, the M0 will revert to idle.
A setting of zero disables the limit.
This change adds 5 cycles to the TX & RX shortfall paths, to check if a
limit is set and to check the shortfall length against the limit.
To enable this, we keep a count of the current shortfall length. Each
time an SGPIO read/write cannot be completed due to a shortfall, we
increase this length. Each time an SGPIO read/write is completed
successfully, we reset the shortfall length to zero.
When a shortfall occurs and the existing shortfall length is zero, this
indicates a new shortfall, and the shortfall count is incremented.
This change adds one cycle to the normal RX & TX paths, to zero the
shortfall count. To enable this to be done in a single cycle, we keep a
zero handy in a high register.
The extra accounting adds 10 cycles to the TX and RX shortfall paths,
plus an additional 3 cycles to the RX shortfall path since there are
now two branches involved: one to the shortfall handler, and another
back to the main loop.
With both counters in place, the number of bytes in the buffer is now
indicated by the difference between the M0 and M4 counts.
The M4 count needs to be increased whenever the M4 produces or consumes
data in the USB bulk buffer, so that the two counts remain correctly
synchronised.
There are three places where this is done:
1. When a USB bulk transfer in or out of the buffer completes, the count
is increased by the number of bytes transferred. This is the most
common case.
2. At TX startup, the M4 effectively sends the M0 16K of zeroes to
transmit, before the first host-provided data.
This is done by zeroing the whole 32K buffer area, and then setting
up the first bulk transfer to write to the second 16K, whilst the M0
begins transmission of the first 16K.
The count is therefore increased by 16K during TX startup, to account
for the initial 16K of zeros.
3. In sweep mode, some data is discarded. When this is done, the count
is incremented by the size of the discarded data.
The USB IRQ is masked whilst doing this, since a read-modify-write is
required, and the bulk transfer completion callback may be called at
any point, which also increases the count.
Instead of this count wrapping at the buffer size, it now increments
continuously. The offset within the buffer is now obtained from the
lower bits of the count.
This makes it possible to keep track of the total number of bytes
transferred by the M0 core.
The count will wrap at 2^32 bytes, which at 20Msps will occur every
107 seconds.
This adds a `hackrf_debug [-S|--state]` option, and the necessary
plumbing to libhackrf and the M4 firmware to support it.
The USB API and libhackrf versions are bumped to reflect the changes.
Calling libusb_cancel_transfer only starts the cancellation of a
transfer. The process is not complete until the transfer callback
has been called with status LIBUSB_TRANSFER_CANCELLED.
If hackrf_start_rx() is called soon after hackrf_stop_rx(),
prepare_transfers() may be called before the previous cancellations
are completed, resulting in a LIBUSB_ERROR_BUSY when a transfer is
reused with libusb_submit_transfer().
To prevent this happening, we keep track of which transfers have
finished (either by completion, or cancellation), and make
cancel_transfers() wait until all transfers are finished.
This is implemented using a pthread condition variable which is
signalled from the transfer thread.
Fixes bug #916.
Previously, there was a race which could lead to a transfer being left
active after cancel_transfers() completed. This would then cause the
next prepare_transfers() call to fail, because libusb_submit_transfer()
would return an error due to the transfer already being in use.
The sequence of events that could cause this was:
1. Main thread calls hackrf_stop_rx(), which calls cancel_transfers(),
which iterates through the 4 transfers in use and cancels them one
by one with libusb_cancel_transfer().
2. During this time, a transfer is completed. The transfer thread calls
hackrf_libusb_transfer_callback(), which handles the data and then
calls libusb_submit_transfer() to resubmit that transfer.
3. Now, cancel_transfers() and hackrf_stop_rx() are completed but one
transfer is still active.
4. The next hackrf_start_rx() call fails, because prepare_transfers()
tries to submit a transfer which is already in use.
To fix this, we add a lock which must be held to either cancel transfers
or restart them. This ensures that only one of these actions can happen
for a given transfer; it's no longer possible for a transfer to be
cancelled and then immediately restarted.
* Clean up the CMake build system and improve the FindFFTW3 module.
* Fixes for Linux build
* Include winsock.h to get struct timeval
* Couple more fixes for MSVC, also add new FindMath module
* Update host build README for new CMake changes (esp. Windows)
* Try to fix Travis OS X build error
* Add docs about pthread-win32
* Whoops, AppVeyor caught a bug in FindFFTW where the includes not being found weren't generating a fatal error.
* Travis rebuild bump
* One more fix: replace hardcoded include paths with a PATH_SUFFIX to standard include paths
* Invert Windows preprocessor flag so it's only needed when using a static build. This preserves compatibility with the previous system.
* Fix copy-paste error
* Update cmake modules from amber-cmake upstream, incorporate TryLinkLibrary into FindUSB1
* Fix missing include
My previous commits didn't handle the specific case of hackrf_close()
being called without the transfers being active.
In this instance the transfers haven't been setup, so calling
cancel_transfers() returned an error.
Instead:
* refactor out the tx/rx stop command from canceling transfers
* send the tx/rx stop command without canceling transfers, since ..
* ... we can then destroy the transfer thread.
I may also need to put an explicit cancel_transfers() before the
call to send the tx/rx stop commands; I'll look at doing that
in a subsequent commit.
This seems to stop consumers that are doing quick back to back stop/start
(eg gqrx changing decode mode / filter bandwidth) from hanging the
device.
I now don't have any weird hangs on hackrf with gqrx/freebsd/libusb!
When things hang it isn't erroring out in any way; it just doesn't
start receive. It doesn't look like a libusb issue; I'd have to get
some USB bus sniffing to see what's going on behind the scenes.
* Update device->streaming to reflect whether we're streaming data,
rather than just whether the streaming thread is active.
The streaming thread is now always active!
On at least freebsd-13 trying to cancel a transfer whilst the libusb thread
is not running results in the transfers not completing cancellation.
The next time they're attempted to be re-added the libusb code thinks
they're still active, and returns BUSY on the buffers.
This causes gqrx to error out when one makes DSP changes or stops/starts it.
You have to restart gqrx to fix it.
After digging into it a bit, the libusb code expects that you're actively
running the main loop in order to have some deferred actions run in the
context of said main loop thread. This includes processing cancelled
transfers - the callbacks have to be run (if they exist) before the
buffers are properly cancelled and have their tracking metadata (a couple of
private pointers and state) removed from inside of libusb.
This patch does the following:
* separate out adding and cancelling transfers from the libusb worker thread
create/destroy path
* create the libusb worker thread when opening the device
* destroy the libusb worker thread when closing the device
* only add and cancel transfers when starting and stopping tx/rx
* handle cancelled transfers gracefully in the USB callback
Whilst here, also make the libusb device memory zeroed by using
calloc instead of malloc.
This fixes all of the weird libusb related buffer management problems
on FreeBSD.
HackRF One supports arbitrary sample rates from 2 Msps to 20 Msps. In
early development we had ideas about preferred sample rates that we no
longer consider valid.
The checksum calculation process was causing the CPLD configuration to reload from flash. With the new SRAM loading mechanism, flash contents may not be up to date, so the CPLD bitstream may regress to the point of not working or not working correctly. This commit is a short-term fix for mossmann/hackrf issue #609.
fixes#435, osmosdr calls hackrf_exit for the last sink and the last
source. If both are in one flow graph the desctructor of the source
fails as the sink already closed the usb context.
This prevents hackrf_exit to close the context if not all devices are closed