Skip to content

Commit 88fa644

Browse files
authored
make HackRF bias tee configurable (#794)
1 parent ddff707 commit 88fa644

10 files changed

+568
-483
lines changed

data/azure-pipelines.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,12 @@ jobs:
252252
displayName: "Install build dependencies"
253253
254254
- script: |
255-
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8d748e26ccc9afc8ea0d0201ae234fda35de721e/Formula/boost.rb
255+
echo "Reinstall icu4c"
256256
brew reinstall https://raw.githubusercontent.com/Homebrew/homebrew-core/a806a621ed3722fb580a58000fb274a2f2d86a6d/Formula/icu4c.rb
257+
echo "Link icu4c"
257258
brew link icu4c --force
259+
echo "Install boost"
260+
brew install --force --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/8d748e26ccc9afc8ea0d0201ae234fda35de721e/Formula/boost.rb
258261
cd /tmp
259262
wget https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2
260263
tar xf libusb-1.0.22.tar.bz2

data/ui/send_recv_device_settings.ui

+287-267
Large diffs are not rendered by default.

src/urh/controller/widgets/DeviceSettingsWidget.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ def set_val(ui_widget, key: str, default):
106106
checked = True if checked == "True" else False
107107
self.ui.checkBoxDCCorrection.setChecked(checked)
108108

109+
checked = conf_dict.get("bias_tee_enabled", False)
110+
if isinstance(checked, str):
111+
checked = True if checked == "True" else False
112+
self.ui.checkBoxBiasTee.setChecked(checked)
113+
109114
self.emit_editing_finished_signals()
110115

111116
@property
@@ -164,6 +169,7 @@ def create_connects(self):
164169

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

172+
self.ui.checkBoxBiasTee.clicked.connect(self.on_check_box_bias_tee_clicked)
167173
self.ui.checkBoxDCCorrection.clicked.connect(self.on_check_box_dc_correction_clicked)
168174

169175
def set_gain_defaults(self):
@@ -307,6 +313,10 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr
307313
self.ui.checkBoxDCCorrection.setVisible(show_dc_correction)
308314
self.ui.labelDCCorrection.setVisible(show_dc_correction)
309315

316+
show_bias_tee = "bias_tee_enabled" in conf and self.device is not None and self.device.bias_tee_enabled is not None
317+
self.ui.labelBiasTee.setVisible(show_bias_tee)
318+
self.ui.checkBoxBiasTee.setVisible(show_bias_tee)
319+
310320
def get_devices_for_combobox(self, continuous_send_mode):
311321
items = []
312322
for device_name in self.backend_handler.DEVICE_NAMES:
@@ -357,7 +367,7 @@ def emit_editing_finished_signals(self):
357367
def emit_device_parameters_changed(self):
358368
settings = {"name": str(self.device.name)}
359369
for attrib in ("frequency", "sample_rate", "bandwidth", "gain", "if_gain", "baseband_gain", "freq_correction",
360-
"antenna_index", "num_sending_repeats", "apply_dc_correction", "subdevice"):
370+
"antenna_index", "num_sending_repeats", "apply_dc_correction", "subdevice", "bias_tee_enabled"):
361371
try:
362372
value = getattr(self.device, attrib, None)
363373
if value is not None:
@@ -510,6 +520,11 @@ def on_btn_refresh_device_identifier_clicked(self):
510520
self.ui.comboBoxDeviceIdentifier.clear()
511521
self.ui.comboBoxDeviceIdentifier.addItems(self.device.get_device_list())
512522

523+
@pyqtSlot(bool)
524+
def on_check_box_bias_tee_clicked(self, checked: bool):
525+
if self.device is not None:
526+
self.device.bias_tee_enabled = bool(checked)
527+
513528
@pyqtSlot(bool)
514529
def on_check_box_dc_correction_clicked(self, checked: bool):
515530
self.device.apply_dc_correction = bool(checked)

src/urh/dev/VirtualDevice.py

+16
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat
158158
if mode == Mode.spectrum:
159159
self.__dev.is_in_spectrum_mode = True
160160

161+
@property
162+
def backend_is_native(self) -> bool:
163+
return self.backend == Backends.native
164+
161165
@property
162166
def data_type(self):
163167
if self.backend == Backends.native:
@@ -213,6 +217,18 @@ def apply_dc_correction(self, value: bool):
213217
if self.backend == Backends.native:
214218
self.__dev.apply_dc_correction = bool(value)
215219

220+
@property
221+
def bias_tee_enabled(self):
222+
if self.backend_is_native:
223+
return self.__dev.bias_tee_enabled
224+
else:
225+
return None
226+
227+
@bias_tee_enabled.setter
228+
def bias_tee_enabled(self, value: bool):
229+
if self.backend_is_native:
230+
self.__dev.bias_tee_enabled = value
231+
216232
@property
217233
def bandwidth_is_adjustable(self):
218234
if self.backend == Backends.grc:

src/urh/dev/config.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
"rx_rf_gain": [0, 14],
4949
"rx_if_gain": [0, 8, 16, 24, 32, 40],
5050
"tx_if_gain": list(range(0, 48)),
51-
"rx_baseband_gain": list(range(0, 63, 2)) # only available in RX
51+
"rx_baseband_gain": list(range(0, 63, 2)), # only available in RX
52+
"bias_tee_enabled": [False, True]
5253
}
5354

5455
# https://kb.ettus.com/About_USRP_Bandwidths_and_Sampling_Rates

src/urh/dev/native/Device.py

+19
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Command(Enum):
3939
SET_FREQUENCY_CORRECTION = 8
4040
SET_CHANNEL_INDEX = 9
4141
SET_ANTENNA_INDEX = 10
42+
SET_BIAS_TEE_ENABLED = 11
4243

4344
ASYNCHRONOUS = False
4445

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

252253
self.__freq_correction = 0
254+
self.__bias_tee_enabled = False
253255
self.__direct_sampling_mode = 0
254256
self.bandwidth_is_adjustable = True
255257

@@ -523,6 +525,23 @@ def set_device_antenna_index(self, value):
523525
except (BrokenPipeError, OSError):
524526
pass
525527

528+
@property
529+
def bias_tee_enabled(self):
530+
return self.__bias_tee_enabled
531+
532+
@bias_tee_enabled.setter
533+
def bias_tee_enabled(self, value: bool):
534+
value = bool(value)
535+
if value != self.__bias_tee_enabled:
536+
self.__bias_tee_enabled = value
537+
self.set_device_bias_tee_enabled(value)
538+
539+
def set_device_bias_tee_enabled(self, value):
540+
try:
541+
self.parent_ctrl_conn.send((self.Command.SET_BIAS_TEE_ENABLED.name, int(value)))
542+
except (BrokenPipeError, OSError):
543+
pass
544+
526545
@property
527546
def freq_correction(self):
528547
return self.__freq_correction

src/urh/dev/native/HackRF.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import OrderedDict
12
from multiprocessing import Array
23
from multiprocessing.connection import Connection
34

@@ -13,7 +14,8 @@ class HackRF(Device):
1314
DEVICE_METHODS = Device.DEVICE_METHODS.copy()
1415
DEVICE_METHODS.update({
1516
Device.Command.SET_FREQUENCY.name: "set_freq",
16-
Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth"
17+
Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth",
18+
Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee"
1719
})
1820

1921
DATA_TYPE = np.int8
@@ -31,7 +33,7 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier):
3133
msg = "SETUP"
3234
if device_identifier:
3335
msg += " ({})".format(device_identifier)
34-
msg += ": "+str(ret)
36+
msg += ": " + str(ret)
3537
ctrl_connection.send(msg)
3638

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

92+
@property
93+
def device_parameters(self) -> OrderedDict:
94+
return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency),
95+
(self.Command.SET_SAMPLE_RATE.name, self.sample_rate),
96+
(self.Command.SET_BANDWIDTH.name, self.bandwidth),
97+
(self.Command.SET_RF_GAIN.name, self.gain),
98+
(self.Command.SET_IF_GAIN.name, self.if_gain),
99+
(self.Command.SET_BB_GAIN.name, self.baseband_gain),
100+
(self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled),
101+
("identifier", self.device_serial)])
102+
90103
@property
91104
def has_multi_device_support(self):
92105
return hackrf.has_multi_device_support()

src/urh/dev/native/lib/chackrf.pxd

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
2+
13
cdef extern from "libhackrf/hackrf.h":
24
enum hackrf_error:
35
HACKRF_SUCCESS = 0
@@ -40,11 +42,6 @@ cdef extern from "libhackrf/hackrf.h":
4042
ctypedef struct hackrf_device:
4143
pass
4244

43-
ctypedef unsigned char uint8_t
44-
ctypedef unsigned short uint16_t
45-
ctypedef unsigned int uint32_t
46-
ctypedef unsigned long long uint64_t
47-
4845
ctypedef struct hackrf_transfer:
4946
hackrf_device* device
5047
uint8_t* buffer
@@ -81,7 +78,7 @@ cdef extern from "libhackrf/hackrf.h":
8178
int hackrf_open(hackrf_device** device);
8279

8380
IF HACKRF_MULTI_DEVICE_SUPPORT == 1:
84-
int hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device)
81+
int hackrf_open_by_serial(const char* desired_serial_number, hackrf_device** device)
8582
hackrf_device_list_t* hackrf_device_list()
8683

8784

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

110107
int hackrf_spiflash_erase(hackrf_device* device)
111-
int hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data)
108+
int hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, const unsigned char* data)
112109
int hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data)
113110

114111
# device will need to be reset after hackrf_cpld_write
115-
int hackrf_cpld_write(hackrf_device* device,
116-
unsigned char* const data, const unsigned int total_length)
112+
int hackrf_cpld_write(hackrf_device* device, const unsigned char* data, const unsigned int total_length)
117113

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

131127
# external amp, bool on/off
132128
int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value)
133-
129+
130+
# Bias Tee, bool on/off
131+
int hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value)
132+
134133
int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)
135134

136135
# range 0-40 step 8d, IF gain in osmosdr

src/urh/dev/native/lib/hackrf.pyx

+23-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
cimport urh.dev.native.lib.chackrf as chackrf
2+
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
23
from libc.stdlib cimport malloc
34
import time
45

@@ -70,21 +71,21 @@ ELSE:
7071
cpdef get_device_list():
7172
return None
7273

73-
cpdef setup(str serial):
74+
cpdef int setup(str serial):
7475
"""
7576
Convenience method for init + open. This one is used by HackRF class.
7677
:return:
7778
"""
7879
init()
7980
return open(serial)
8081

81-
cpdef init():
82+
cpdef int init():
8283
return chackrf.hackrf_init()
8384

84-
cpdef exit():
85+
cpdef int exit():
8586
return chackrf.hackrf_exit()
8687

87-
cpdef close():
88+
cpdef int close():
8889
return chackrf.hackrf_close(_c_device)
8990

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

96-
cpdef stop_rx_mode():
97+
cpdef int stop_rx_mode():
9798
global RUNNING
9899
RUNNING = -1
99100
time.sleep(TIMEOUT)
100101
return chackrf.hackrf_stop_rx(_c_device)
101102

102-
cpdef start_tx_mode(callback):
103+
cpdef int start_tx_mode(callback):
103104
global f, RUNNING
104105
RUNNING = 0
105106
f = callback
106107
return chackrf.hackrf_start_tx(_c_device, _c_callback_send, NULL)
107108

108-
cpdef stop_tx_mode():
109+
cpdef int stop_tx_mode():
109110
global RUNNING
110111
RUNNING = -1
111112
time.sleep(TIMEOUT)
112113
return chackrf.hackrf_stop_tx(_c_device)
113114

114-
cpdef board_id_read():
115-
cdef unsigned char value
116-
ret = chackrf.hackrf_board_id_read(_c_device, &value)
117-
if ret == hackrf_success:
118-
return value
119-
else:
120-
return ""
121-
122-
cpdef version_string_read():
123-
cdef char*version = <char *> malloc(20 * sizeof(char))
124-
cdef unsigned char length = 20
125-
ret = chackrf.hackrf_version_string_read(_c_device, version, length)
126-
if ret == hackrf_success:
127-
return version.decode('UTF-8')
128-
else:
129-
return ""
130-
131-
cpdef set_freq(freq_hz):
115+
cpdef int set_freq(freq_hz):
132116
time.sleep(TIMEOUT)
133117
return chackrf.hackrf_set_freq(_c_device, freq_hz)
134118

@@ -140,35 +124,39 @@ cpdef is_streaming():
140124
else:
141125
return False
142126

143-
cpdef set_rf_gain(value):
144-
""" Enable or disable RF amplifier """
127+
cpdef int set_amp_enable(value):
145128
time.sleep(TIMEOUT)
129+
cdef uint8_t val = 1 if value else 0
130+
return chackrf.hackrf_set_amp_enable(_c_device, val)
131+
132+
cpdef int set_rf_gain(value):
133+
""" Enable or disable RF amplifier """
146134
return set_amp_enable(value)
147135

148-
cpdef set_if_rx_gain(value):
136+
cpdef int set_if_rx_gain(value):
149137
""" Sets the LNA gain, in 8Db steps, maximum value of 40 """
150138
time.sleep(TIMEOUT)
151139
return chackrf.hackrf_set_lna_gain(_c_device, value)
152140

153-
cpdef set_if_tx_gain(value):
141+
cpdef int set_if_tx_gain(value):
154142
""" Sets the txvga gain, in 1db steps, maximum value of 47 """
155143
time.sleep(TIMEOUT)
156144
return chackrf.hackrf_set_txvga_gain(_c_device, value)
157145

158-
cpdef set_baseband_gain(value):
146+
cpdef int set_baseband_gain(value):
159147
""" Sets the vga gain, in 2db steps, maximum value of 62 """
160148
time.sleep(TIMEOUT)
161149
return chackrf.hackrf_set_vga_gain(_c_device, value)
162150

163-
cpdef set_sample_rate(sample_rate):
151+
cpdef int set_sample_rate(sample_rate):
164152
time.sleep(TIMEOUT)
165153
return chackrf.hackrf_set_sample_rate(_c_device, sample_rate)
166154

167-
cpdef set_amp_enable(value):
155+
cpdef int set_bias_tee(on_or_off):
168156
time.sleep(TIMEOUT)
169-
cdef bint val = 1 if value else 0
170-
return chackrf.hackrf_set_amp_enable(_c_device, val)
157+
cdef uint8_t bias_tee = 1 if on_or_off else 0
158+
return chackrf.hackrf_set_antenna_enable(_c_device, bias_tee)
171159

172-
cpdef set_baseband_filter_bandwidth(bandwidth_hz):
160+
cpdef int set_baseband_filter_bandwidth(bandwidth_hz):
173161
time.sleep(TIMEOUT)
174162
return chackrf.hackrf_set_baseband_filter_bandwidth(_c_device, bandwidth_hz)

0 commit comments

Comments
 (0)