libhackrf
HackRF SDR platform library
|
RX and TX, callbacks. More...
Data Structures | |
struct | hackrf_transfer |
USB transfer information passed to RX or TX callback. More... | |
Macros | |
#define | SAMPLES_PER_BLOCK 8192 |
Number of samples per tuning when sweeping. More... | |
#define | BYTES_PER_BLOCK 16384 |
Number of bytes per tuning for sweeping. More... | |
#define | MAX_SWEEP_RANGES 10 |
Maximum number of sweep ranges to be specified for hackrf_init_sweep. More... | |
Typedefs | |
typedef int(* | hackrf_sample_block_cb_fn) (hackrf_transfer *transfer) |
Sample block callback, used in RX and TX (set via hackrf_start_rx, hackrf_start_rx_sweep and hackrf_start_tx). More... | |
typedef void(* | hackrf_tx_block_complete_cb_fn) (hackrf_transfer *transfer, int) |
Block complete callback. More... | |
typedef void(* | hackrf_flush_cb_fn) (void *flush_ctx, int) |
Flush (end of transmission) callback. More... | |
Enumerations | |
enum | sweep_style { LINEAR = 0 , INTERLEAVED = 1 } |
sweep mode enum More... | |
Functions | |
int | hackrf_start_rx (hackrf_device *device, hackrf_sample_block_cb_fn callback, void *rx_ctx) |
Start receiving. More... | |
int | hackrf_stop_rx (hackrf_device *device) |
Stop receiving. More... | |
int | hackrf_start_tx (hackrf_device *device, hackrf_sample_block_cb_fn callback, void *tx_ctx) |
Start transmitting. More... | |
int | hackrf_set_tx_block_complete_callback (hackrf_device *device, hackrf_tx_block_complete_cb_fn callback) |
Setup callback to be called when an USB transfer is completed. More... | |
int | hackrf_enable_tx_flush (hackrf_device *device, hackrf_flush_cb_fn callback, void *flush_ctx) |
Setup flush (end-of-transmission) callback. More... | |
int | hackrf_stop_tx (hackrf_device *device) |
Stop transmission. More... | |
int | hackrf_set_tx_underrun_limit (hackrf_device *device, uint32_t value) |
Set transmit underrun limit. More... | |
int | hackrf_set_rx_overrun_limit (hackrf_device *device, uint32_t value) |
Set receive overrun limit. More... | |
int | hackrf_is_streaming (hackrf_device *device) |
Query device streaming status. More... | |
int | hackrf_set_hw_sync_mode (hackrf_device *device, const uint8_t value) |
Set hardware sync mode (hardware triggering) More... | |
int | hackrf_init_sweep (hackrf_device *device, const uint16_t *frequency_list, const int num_ranges, const uint32_t num_bytes, const uint32_t step_width, const uint32_t offset, const enum sweep_style style) |
Initialize sweep mode. More... | |
int | hackrf_start_rx_sweep (hackrf_device *device, hackrf_sample_block_cb_fn callback, void *rx_ctx) |
Start RX sweep. More... | |
There are 3 different streaming modes supported by HackRF:
Each mode needs to be initialized before use, then the mode needs to be entered with the hackrf_start_*
function. Data transfer happens through callbacks.
There are 3 types of callbacks in the library:
Steps for starting an RX or TX operation:
hackrf_start_*
)hackrf_stop_*
Data is transfered through the USB connection via setting up multiple async libusb transfers (hackrf_get_transfer_queue_depth). In TX mode, the transfers needs to be filled before submitting, and in RX mode, they need to be read out when they are done. This is done using the transfer callback - it receives a hackrf_transfer object and needs to transfer the data to/from it. As it's needed for all operations, this gets called whenever we need to move data, so every time a transfer is finished (and before the first transfer in TX mode). There's a "transfer complete callback" that only gets called when a transfer is completed. It does not need to do anything special tho, and is optional.
Streaming can be stopped via returning a non-zero value from the transfer callback, but that does NOT reset the device to IDLE mode, it only stops data transfers. In TX mode, when this happens, and the transmitter runs out of data to transmit, it will start transmitting all 0 values (but in older firmware versions, it started repeating the last buffer). To actually stop the operation, a call to hackrf_stop_*
is needed. Since the callback operate in an async libusb context, such a call can't be made from there, only from the main thread, so it must be signaled through some means (for example, a global variable, or better, a pthread_cond
) to stop. In RX mode, this signaling can be done from the transfer callback, but in TX mode, we must make sure that we only stop the operation when the last transfer is completed and the device transmitted it, or we might lose it. For this reason, the third flush callback exists, that gets called when this happens. It is adivsed to only signal the main thread to stop from this callback.
The function hackrf_is_streaming can be used to check if the device is streaming or not.
Set when starting an operation with hackrf_start_tx, hackrf_start_rx or hackrf_start_rx_sweep. This callback supplies / receives data. This function takes a hackrf_transfer struct as a parameter, and fill/read data to/from its buffer. This function runs in an async libusb context, meaning it should not iteract with the libhackrf library in other ways. The callback can return a boolean value, if its return value is non-zero then it won't be called again, meaning that no future transfers will take place, and (in TX case) the flush callback will be called shortly.
This callback is optional, and only applicable in TX mode. It gets called whenever a data transfer is finished, and can read the data. It needs to do nothing at all. This callback can be set using hackrf_set_tx_block_complete_callback
This callback is optional, and only applicable in TX mode. It get called when the last transfer is completed, and it's advisable to only stop streaming via this callback. This callback can be set using hackrf_enable_tx_flush
This code can be compiled using gcc -o triangle triangle.c -lm -lhackrf
. It generates and transmits a 440Hz triangle wave using FM modulation on the 2m HAM band (check your local laws and regulations on transmitting and only transmit on bands you have license to!).
For a more complete example, including error handling and more settings, see hackrf_transfer.c
Underrun/overrun detection can be enabled using hackrf_set_tx_underrun_limit or hackrf_set_rx_overrun_limit limit. This causes the HackRF to stop operation if more than the specified amount of samples get lost, for example in case of your program crashing, USB connection faliure, etc.
Sweeping mode is kind of special. In this mode, the device can be programmed to a list of frequencies to tune on, record set amount of samples and then tune to the next frequency and repeat. It can be setup via hackrf_init_sweep and started with hackrf_start_rx_sweep. In this mode, the callback does not receive raw samples, but blocks of samples prefixed with a frequency header specifying the tuned frequency.
See hackrf_sweep.c for a full example, and especialy the start of the RX callback for parsing the frequency header.
hackrf_set_hw_sync_mode can be used to setup HW sync mode (see the documentation on this mode). This mode allows multiple HackRF Ones to synchronize operations, or one HackRF One to synchrnonize on an external trigger source.
#define BYTES_PER_BLOCK 16384 |
#define MAX_SWEEP_RANGES 10 |
#define SAMPLES_PER_BLOCK 8192 |
typedef void(* hackrf_flush_cb_fn) (void *flush_ctx, int) |
Will be called when the last samples are transmitted and stopping transmission will result in no samples getting lost. Should signal the main thread that it should stop transmission via hackrf_stop_tx
typedef int(* hackrf_sample_block_cb_fn) (hackrf_transfer *transfer) |
In each mode, it is called when data needs to be handled, meaning filling samples in TX mode or reading them in RX modes.
In TX mode, it should refill the transfer buffer with new raw IQ data, and set hackrf_transfer::valid_length.
In RX mode, it should copy/process the contents of the transfer buffer's valid part.
In RX SWEEP mode, it receives multiple "blocks" of data, each with a 10-byte header containing the tuned frequency followed by the samples. See hackrf_init_sweep for more info.
The callback should return 0 if it wants to be called again, and any other value otherwise. Stopping the RX/TX/SWEEP is still done with hackrf_stop_rx and hackrf_stop_tx, and those should be called from the main thread, so this callback should signal the main thread that it should stop. Signaling the main thread to stop TX should be done from the flush callback in order to guarantee that no samples are discarded, see hackrf_flush_cb_fn
typedef void(* hackrf_tx_block_complete_cb_fn) (hackrf_transfer *transfer, int) |
Set via hackrf_set_tx_block_complete_callback, called when a transfer is finished to the device's buffer, regardless if the transfer was successful or not. It can signal the main thread to stop on failure, can catch USB transfer errors and can also gather statistics about the transfered data.
enum sweep_style |
Used by hackrf_init_sweep, to set sweep parameters.
Linear mode is no longer used by the hackrf_sweep command line tool and in general the interleaved method is always preferable, but the linear mode remains available for backward compatibility and might be useful in some special circumstances.
int hackrf_enable_tx_flush | ( | hackrf_device * | device, |
hackrf_flush_cb_fn | callback, | ||
void * | flush_ctx | ||
) |
This callback will be called when all the data was transmitted and all data transfers were completed. First parameter is supplied context, second parameter is success flag.
device | device to configure |
callback | callback to call when all transfers were completed |
flush_ctx | context (1st parameter of callback) |
int hackrf_init_sweep | ( | hackrf_device * | device, |
const uint16_t * | frequency_list, | ||
const int | num_ranges, | ||
const uint32_t | num_bytes, | ||
const uint32_t | step_width, | ||
const uint32_t | offset, | ||
const enum sweep_style | style | ||
) |
In this mode, in a single data transfer (single call to the RX transfer callback), multiple blocks of size num_bytes
bytes are received with different center frequencies. At the beginning of each block, a 10-byte frequency header is present in 0x7F - 0x7F - uint64_t frequency (LSBFIRST, in Hz)
format, followed by the actual samples.
Requires USB API version 0x0102 or above!
device | device to configure |
frequency_list | list of start-stop frequency pairs in MHz |
num_ranges | length of array frequency_list (in pairs, so total array length / 2!). Must be less than MAX_SWEEP_RANGES |
num_bytes | number of bytes to capture per tuning, must be a multiple of BYTES_PER_BLOCK |
step_width | width of each tuning step in Hz |
offset | frequency offset added to tuned frequencies. sample_rate / 2 is a good value |
style | sweep style |
int hackrf_is_streaming | ( | hackrf_device * | device | ) |
device | device to query |
int hackrf_set_hw_sync_mode | ( | hackrf_device * | device, |
const uint8_t | value | ||
) |
See the documentation on hardware triggering for details
Requires USB API version 0x0102 or above!
device | device to configure |
value | enable (1) or disable (0) hardware triggering |
int hackrf_set_rx_overrun_limit | ( | hackrf_device * | device, |
uint32_t | value | ||
) |
When this limit is set, after the specified number of samples (bytes, not whole IQ pairs) missing the device will automatically return to IDLE mode, thus stopping operation. Useful for handling cases like program/computer crashes or other problems. The default value 0 means no limit.
Requires USB API version 0x0106 or above!
device | device to configure |
value | number of samples to wait before auto-stopping |
int hackrf_set_tx_block_complete_callback | ( | hackrf_device * | device, |
hackrf_tx_block_complete_cb_fn | callback | ||
) |
This callback will be called whenever an USB transfer to the device is completed, regardless if it was successful or not (indicated by the second parameter).
device | device to configure |
callback | callback to call when a transfer is completed |
int hackrf_set_tx_underrun_limit | ( | hackrf_device * | device, |
uint32_t | value | ||
) |
When this limit is set, after the specified number of samples (bytes, not whole IQ pairs) missing the device will automatically return to IDLE mode, thus stopping operation. Useful for handling cases like program/computer crashes or other problems. The default value 0 means no limit.
Requires USB API version 0x0106 or above!
device | device to configure |
value | number of samples to wait before auto-stopping |
int hackrf_start_rx | ( | hackrf_device * | device, |
hackrf_sample_block_cb_fn | callback, | ||
void * | rx_ctx | ||
) |
Should be called after setting gains, frequency and sampling rate, as these values won't get reset but instead keep their last value, thus their state is unknown.
The callback is called with a hackrf_transfer object whenever the buffer is full. The callback is called in an async context so no libhackrf functions should be called from it. The callback should treat its argument as read-only.
device | device to configure |
callback | rx_callback |
rx_ctx | User provided RX context. Not used by the library, but available to callback as hackrf_transfer::rx_ctx. |
int hackrf_start_rx_sweep | ( | hackrf_device * | device, |
hackrf_sample_block_cb_fn | callback, | ||
void * | rx_ctx | ||
) |
See hackrf_init_sweep for more info
Requires USB API version 0x0104 or above!
device | device to start sweeping |
callback | rx callback processing the received data |
rx_ctx | User provided RX context. Not used by the library, but available to callback as hackrf_transfer::rx_ctx. |
int hackrf_start_tx | ( | hackrf_device * | device, |
hackrf_sample_block_cb_fn | callback, | ||
void * | tx_ctx | ||
) |
Should be called after setting gains, frequency and sampling rate, as these values won't get reset but instead keep their last value, thus their state is unknown. Setting flush function (using hackrf_enable_tx_flush) and/or setting block complete callback (using hackrf_set_tx_block_complete_callback) (if these features are used) should also be done before this.
The callback is called with a hackrf_transfer object whenever a transfer buffer is needed to be filled with samples. The callback is called in an async context so no libhackrf functions should be called from it. The callback should treat its argument as read-only, except the hackrf_transfer::buffer and hackrf_transfer::valid_length.
device | device to configure |
callback | tx_callback |
tx_ctx | User provided TX context. Not used by the library, but available to callback as hackrf_transfer::tx_ctx. |
int hackrf_stop_rx | ( | hackrf_device * | device | ) |
device | device to stop RX on |
int hackrf_stop_tx | ( | hackrf_device * | device | ) |
device | device to stop TX on |