Skip to content

Commit

Permalink
make HackRF bias tee configurable (#794)
Browse files Browse the repository at this point in the history
  • Loading branch information
jopohl authored Jul 29, 2020
1 parent ddff707 commit 88fa644
Show file tree
Hide file tree
Showing 10 changed files with 568 additions and 483 deletions.
5 changes: 4 additions & 1 deletion data/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,12 @@ jobs:
displayName: "Install build dependencies"
- script: |
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8d748e26ccc9afc8ea0d0201ae234fda35de721e/Formula/boost.rb
echo "Reinstall icu4c"
brew reinstall https://raw.githubusercontent.com/Homebrew/homebrew-core/a806a621ed3722fb580a58000fb274a2f2d86a6d/Formula/icu4c.rb
echo "Link icu4c"
brew link icu4c --force
echo "Install boost"
brew install --force --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/8d748e26ccc9afc8ea0d0201ae234fda35de721e/Formula/boost.rb
cd /tmp
wget https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2
tar xf libusb-1.0.22.tar.bz2
Expand Down
554 changes: 287 additions & 267 deletions data/ui/send_recv_device_settings.ui

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion src/urh/controller/widgets/DeviceSettingsWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ def set_val(ui_widget, key: str, default):
checked = True if checked == "True" else False
self.ui.checkBoxDCCorrection.setChecked(checked)

checked = conf_dict.get("bias_tee_enabled", False)
if isinstance(checked, str):
checked = True if checked == "True" else False
self.ui.checkBoxBiasTee.setChecked(checked)

self.emit_editing_finished_signals()

@property
Expand Down Expand Up @@ -164,6 +169,7 @@ def create_connects(self):

self.ui.comboBoxDeviceIdentifier.editTextChanged.connect(self.on_combo_box_device_identifier_edit_text_changed)

self.ui.checkBoxBiasTee.clicked.connect(self.on_check_box_bias_tee_clicked)
self.ui.checkBoxDCCorrection.clicked.connect(self.on_check_box_dc_correction_clicked)

def set_gain_defaults(self):
Expand Down Expand Up @@ -307,6 +313,10 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr
self.ui.checkBoxDCCorrection.setVisible(show_dc_correction)
self.ui.labelDCCorrection.setVisible(show_dc_correction)

show_bias_tee = "bias_tee_enabled" in conf and self.device is not None and self.device.bias_tee_enabled is not None
self.ui.labelBiasTee.setVisible(show_bias_tee)
self.ui.checkBoxBiasTee.setVisible(show_bias_tee)

def get_devices_for_combobox(self, continuous_send_mode):
items = []
for device_name in self.backend_handler.DEVICE_NAMES:
Expand Down Expand Up @@ -357,7 +367,7 @@ def emit_editing_finished_signals(self):
def emit_device_parameters_changed(self):
settings = {"name": str(self.device.name)}
for attrib in ("frequency", "sample_rate", "bandwidth", "gain", "if_gain", "baseband_gain", "freq_correction",
"antenna_index", "num_sending_repeats", "apply_dc_correction", "subdevice"):
"antenna_index", "num_sending_repeats", "apply_dc_correction", "subdevice", "bias_tee_enabled"):
try:
value = getattr(self.device, attrib, None)
if value is not None:
Expand Down Expand Up @@ -510,6 +520,11 @@ def on_btn_refresh_device_identifier_clicked(self):
self.ui.comboBoxDeviceIdentifier.clear()
self.ui.comboBoxDeviceIdentifier.addItems(self.device.get_device_list())

@pyqtSlot(bool)
def on_check_box_bias_tee_clicked(self, checked: bool):
if self.device is not None:
self.device.bias_tee_enabled = bool(checked)

@pyqtSlot(bool)
def on_check_box_dc_correction_clicked(self, checked: bool):
self.device.apply_dc_correction = bool(checked)
Expand Down
16 changes: 16 additions & 0 deletions src/urh/dev/VirtualDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat
if mode == Mode.spectrum:
self.__dev.is_in_spectrum_mode = True

@property
def backend_is_native(self) -> bool:
return self.backend == Backends.native

@property
def data_type(self):
if self.backend == Backends.native:
Expand Down Expand Up @@ -213,6 +217,18 @@ def apply_dc_correction(self, value: bool):
if self.backend == Backends.native:
self.__dev.apply_dc_correction = bool(value)

@property
def bias_tee_enabled(self):
if self.backend_is_native:
return self.__dev.bias_tee_enabled
else:
return None

@bias_tee_enabled.setter
def bias_tee_enabled(self, value: bool):
if self.backend_is_native:
self.__dev.bias_tee_enabled = value

@property
def bandwidth_is_adjustable(self):
if self.backend == Backends.grc:
Expand Down
3 changes: 2 additions & 1 deletion src/urh/dev/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"rx_rf_gain": [0, 14],
"rx_if_gain": [0, 8, 16, 24, 32, 40],
"tx_if_gain": list(range(0, 48)),
"rx_baseband_gain": list(range(0, 63, 2)) # only available in RX
"rx_baseband_gain": list(range(0, 63, 2)), # only available in RX
"bias_tee_enabled": [False, True]
}

# https://kb.ettus.com/About_USRP_Bandwidths_and_Sampling_Rates
Expand Down
19 changes: 19 additions & 0 deletions src/urh/dev/native/Device.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Command(Enum):
SET_FREQUENCY_CORRECTION = 8
SET_CHANNEL_INDEX = 9
SET_ANTENNA_INDEX = 10
SET_BIAS_TEE_ENABLED = 11

ASYNCHRONOUS = False

Expand Down Expand Up @@ -250,6 +251,7 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban
self.__antenna_index = 0

self.__freq_correction = 0
self.__bias_tee_enabled = False
self.__direct_sampling_mode = 0
self.bandwidth_is_adjustable = True

Expand Down Expand Up @@ -523,6 +525,23 @@ def set_device_antenna_index(self, value):
except (BrokenPipeError, OSError):
pass

@property
def bias_tee_enabled(self):
return self.__bias_tee_enabled

@bias_tee_enabled.setter
def bias_tee_enabled(self, value: bool):
value = bool(value)
if value != self.__bias_tee_enabled:
self.__bias_tee_enabled = value
self.set_device_bias_tee_enabled(value)

def set_device_bias_tee_enabled(self, value):
try:
self.parent_ctrl_conn.send((self.Command.SET_BIAS_TEE_ENABLED.name, int(value)))
except (BrokenPipeError, OSError):
pass

@property
def freq_correction(self):
return self.__freq_correction
Expand Down
17 changes: 15 additions & 2 deletions src/urh/dev/native/HackRF.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import OrderedDict
from multiprocessing import Array
from multiprocessing.connection import Connection

Expand All @@ -13,7 +14,8 @@ class HackRF(Device):
DEVICE_METHODS = Device.DEVICE_METHODS.copy()
DEVICE_METHODS.update({
Device.Command.SET_FREQUENCY.name: "set_freq",
Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth"
Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth",
Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee"
})

DATA_TYPE = np.int8
Expand All @@ -31,7 +33,7 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier):
msg = "SETUP"
if device_identifier:
msg += " ({})".format(device_identifier)
msg += ": "+str(ret)
msg += ": " + str(ret)
ctrl_connection.send(msg)

return ret == 0
Expand Down Expand Up @@ -87,6 +89,17 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban
-9999: "HACKRF_ERROR_OTHER"
}

@property
def device_parameters(self) -> OrderedDict:
return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency),
(self.Command.SET_SAMPLE_RATE.name, self.sample_rate),
(self.Command.SET_BANDWIDTH.name, self.bandwidth),
(self.Command.SET_RF_GAIN.name, self.gain),
(self.Command.SET_IF_GAIN.name, self.if_gain),
(self.Command.SET_BB_GAIN.name, self.baseband_gain),
(self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled),
("identifier", self.device_serial)])

@property
def has_multi_device_support(self):
return hackrf.has_multi_device_support()
Expand Down
19 changes: 9 additions & 10 deletions src/urh/dev/native/lib/chackrf.pxd
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t

cdef extern from "libhackrf/hackrf.h":
enum hackrf_error:
HACKRF_SUCCESS = 0
Expand Down Expand Up @@ -40,11 +42,6 @@ cdef extern from "libhackrf/hackrf.h":
ctypedef struct hackrf_device:
pass

ctypedef unsigned char uint8_t
ctypedef unsigned short uint16_t
ctypedef unsigned int uint32_t
ctypedef unsigned long long uint64_t

ctypedef struct hackrf_transfer:
hackrf_device* device
uint8_t* buffer
Expand Down Expand Up @@ -81,7 +78,7 @@ cdef extern from "libhackrf/hackrf.h":
int hackrf_open(hackrf_device** device);

IF HACKRF_MULTI_DEVICE_SUPPORT == 1:
int hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device)
int hackrf_open_by_serial(const char* desired_serial_number, hackrf_device** device)
hackrf_device_list_t* hackrf_device_list()


Expand All @@ -108,12 +105,11 @@ cdef extern from "libhackrf/hackrf.h":
int hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value)

int hackrf_spiflash_erase(hackrf_device* device)
int hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data)
int hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, const unsigned char* data)
int hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data)

# device will need to be reset after hackrf_cpld_write
int hackrf_cpld_write(hackrf_device* device,
unsigned char* const data, const unsigned int total_length)
int hackrf_cpld_write(hackrf_device* device, const unsigned char* data, const unsigned int total_length)

int hackrf_board_id_read(hackrf_device* device, uint8_t* value)
int hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length)
Expand All @@ -130,7 +126,10 @@ cdef extern from "libhackrf/hackrf.h":

# external amp, bool on/off
int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value)


# Bias Tee, bool on/off
int hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value)

int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)

# range 0-40 step 8d, IF gain in osmosdr
Expand Down
58 changes: 23 additions & 35 deletions src/urh/dev/native/lib/hackrf.pyx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cimport urh.dev.native.lib.chackrf as chackrf
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
from libc.stdlib cimport malloc
import time

Expand Down Expand Up @@ -70,21 +71,21 @@ ELSE:
cpdef get_device_list():
return None

cpdef setup(str serial):
cpdef int setup(str serial):
"""
Convenience method for init + open. This one is used by HackRF class.
:return:
"""
init()
return open(serial)

cpdef init():
cpdef int init():
return chackrf.hackrf_init()

cpdef exit():
cpdef int exit():
return chackrf.hackrf_exit()

cpdef close():
cpdef int close():
return chackrf.hackrf_close(_c_device)

cpdef int start_rx_mode(callback):
Expand All @@ -93,42 +94,25 @@ cpdef int start_rx_mode(callback):
f = callback
return chackrf.hackrf_start_rx(_c_device, _c_callback_recv, NULL)

cpdef stop_rx_mode():
cpdef int stop_rx_mode():
global RUNNING
RUNNING = -1
time.sleep(TIMEOUT)
return chackrf.hackrf_stop_rx(_c_device)

cpdef start_tx_mode(callback):
cpdef int start_tx_mode(callback):
global f, RUNNING
RUNNING = 0
f = callback
return chackrf.hackrf_start_tx(_c_device, _c_callback_send, NULL)

cpdef stop_tx_mode():
cpdef int stop_tx_mode():
global RUNNING
RUNNING = -1
time.sleep(TIMEOUT)
return chackrf.hackrf_stop_tx(_c_device)

cpdef board_id_read():
cdef unsigned char value
ret = chackrf.hackrf_board_id_read(_c_device, &value)
if ret == hackrf_success:
return value
else:
return ""

cpdef version_string_read():
cdef char*version = <char *> malloc(20 * sizeof(char))
cdef unsigned char length = 20
ret = chackrf.hackrf_version_string_read(_c_device, version, length)
if ret == hackrf_success:
return version.decode('UTF-8')
else:
return ""

cpdef set_freq(freq_hz):
cpdef int set_freq(freq_hz):
time.sleep(TIMEOUT)
return chackrf.hackrf_set_freq(_c_device, freq_hz)

Expand All @@ -140,35 +124,39 @@ cpdef is_streaming():
else:
return False

cpdef set_rf_gain(value):
""" Enable or disable RF amplifier """
cpdef int set_amp_enable(value):
time.sleep(TIMEOUT)
cdef uint8_t val = 1 if value else 0
return chackrf.hackrf_set_amp_enable(_c_device, val)

cpdef int set_rf_gain(value):
""" Enable or disable RF amplifier """
return set_amp_enable(value)

cpdef set_if_rx_gain(value):
cpdef int set_if_rx_gain(value):
""" Sets the LNA gain, in 8Db steps, maximum value of 40 """
time.sleep(TIMEOUT)
return chackrf.hackrf_set_lna_gain(_c_device, value)

cpdef set_if_tx_gain(value):
cpdef int set_if_tx_gain(value):
""" Sets the txvga gain, in 1db steps, maximum value of 47 """
time.sleep(TIMEOUT)
return chackrf.hackrf_set_txvga_gain(_c_device, value)

cpdef set_baseband_gain(value):
cpdef int set_baseband_gain(value):
""" Sets the vga gain, in 2db steps, maximum value of 62 """
time.sleep(TIMEOUT)
return chackrf.hackrf_set_vga_gain(_c_device, value)

cpdef set_sample_rate(sample_rate):
cpdef int set_sample_rate(sample_rate):
time.sleep(TIMEOUT)
return chackrf.hackrf_set_sample_rate(_c_device, sample_rate)

cpdef set_amp_enable(value):
cpdef int set_bias_tee(on_or_off):
time.sleep(TIMEOUT)
cdef bint val = 1 if value else 0
return chackrf.hackrf_set_amp_enable(_c_device, val)
cdef uint8_t bias_tee = 1 if on_or_off else 0
return chackrf.hackrf_set_antenna_enable(_c_device, bias_tee)

cpdef set_baseband_filter_bandwidth(bandwidth_hz):
cpdef int set_baseband_filter_bandwidth(bandwidth_hz):
time.sleep(TIMEOUT)
return chackrf.hackrf_set_baseband_filter_bandwidth(_c_device, bandwidth_hz)
Loading

0 comments on commit 88fa644

Please sign in to comment.