Where our callback is called with a status other than COMPLETED,
something abnormal has happened and we no longer want to either
submit further transfers or await a flush. So clear the streaming
and flush flags, and proceed to transfer_finished.
Do the same in the case where libusb_submit_transfer fails when
called to submit the flush transfer.
Firmware now detects the hardware it is running on at startup and
refuses to run if it is compiled for the wrong platform. The board ID
returned by firmware to the host is now derived from run-time detection
rather than a compile-time value. A separate method to retrieve
compile-time supported platform is added.
On HackRF One, pin straps are checked to determine hardware revision.
This is informational to aid troubleshooting and does not affect any
function.
Applications may need to learn the size of the USB transfer buffer
queue, for example to determine how many bytes will be preloaded with
calls to the TX callback.
I believe this was safe before, because this code is only called from
the transfer thread, and the condition being protected is just whether
the count is zero, not the actual value of the count.
However, this isn't performance critical and it's a lot easier to
reason about the code if we just hold the lock for this whole section.
This simplifies the code required to wait for cancellations to complete.
The condition variable now reflects whether `active_transfers == 0`, and
the associated lock must be held to decrement that count to zero.
These were added in #805, as a workaround to prevent their parent
functions from returning before transfer cancellations had completed.
This has since been fixed properly in #1029.
There are now only two possible outcomes to this function: either we
successfully resubmitted a transfer, or the transfer is finished and we
end up calling transfer_finished().
So we can go ahead and simplify it accordingly.
If a transfer was cancelled, we are on our way to shutdown.
If hackrf_stop_tx() or hackrf_stop_rx() were called, they will already
have cleared this flag, but it is not cleared in hackrf_close(), and
for consistency with other paths it makes sense to clear it here.
If result < 0 here, libusb_submit_transfer returned an error, so we
need to shut down.
If !resubmit, then cancel_transfers() was already called by one of the
stop or close functions, so streaming is already false.
In the case of a libusb error, we still need the transfer thread
running, in order to handle outstanding cancellations and to signal the
condition variable when that is done.
transfer_threadproc has a timeout of half a second, so
when kill_transfer_thread tries to pthread_join, it often
has to wait until the timeout kicks in.
With this fix, we ensure that a final request is made after
request_exit has been called, so that transfer_threadproc can exit its
loop in a fast and clean manner.
This change avoids various possible races in which an autonomous mode
change by the M0 might clobber a mode change made from the M4, as well
as related races on other state fields that can be written by the M4.
The previous mode field is replaced by two separate ones:
- active_mode, which is written only by the M0, and indicates the
current operating mode.
- requested_mode, which is written by the M4 to request a change.
This field includes both the requested mode, and a flag bit. The M4
writes the field with the flag bit set, and must then wait for the
M0 to signal completion of the request by clearing the flag bit.
Whilst the M4 is blocked waiting for the flag bit to be cleared, the
M0 can safely make all the required changes to the state that are
needed for the transition to the requested mode. Once the transition
is complete, the M0 clears the flag bit and the M4 continues execution.
Request handling is implemented in the idle loop. To handle requests,
mode-specific loops simply need to check the request flag and branch to
idle if it is set.
A request from the M4 to change modes will always require passing
through the idle loop, and is not subject to timing guarantees. Only
transitions made autonomously by the M0 have guaranteed timing
constraints.
The work previously done in reset_counts is now implemented as part of
the request handling, so the tx_start, rx_start and wait_start labels
are no longer required.
An extra two cycles are required in the TX shortfall path because we
must now load the active mode to check whether we are in TX_START.
Two cycles are saved in the normal TX path because updating the active
mode to TX_RUN can now be done without checking the previous value.