updates_and_fixes #12
|
|
@ -1,4 +1,4 @@
|
||||||
import time
|
import gc
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ import numpy as np
|
||||||
from bladerf import _bladerf
|
from bladerf import _bladerf
|
||||||
|
|
||||||
from ria_toolkit_oss.datatypes import Recording
|
from ria_toolkit_oss.datatypes import Recording
|
||||||
from ria_toolkit_oss.sdr import SDR
|
from ria_toolkit_oss.sdr import SDR, SDRError, SDRParameterError
|
||||||
|
|
||||||
|
|
||||||
class Blade(SDR):
|
class Blade(SDR):
|
||||||
|
|
@ -22,7 +22,7 @@ class Blade(SDR):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if identifier != "":
|
if identifier != "":
|
||||||
print(f"Warning, radio identifier {identifier} provided for Blade but will not be used.")
|
warnings.warn(f"Blade: Identifier '{identifier}' will be ignored", UserWarning)
|
||||||
|
|
||||||
uut = self._probe_bladerf()
|
uut = self._probe_bladerf()
|
||||||
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Blade(SDR):
|
||||||
|
|
||||||
self.device = _bladerf.BladeRF(uut)
|
self.device = _bladerf.BladeRF(uut)
|
||||||
self._print_versions(device=self.device)
|
self._print_versions(device=self.device)
|
||||||
|
self.bytes_per_sample = 4
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
|
@ -42,8 +43,10 @@ class Blade(SDR):
|
||||||
if board is not None:
|
if board is not None:
|
||||||
board.close()
|
board.close()
|
||||||
|
|
||||||
# TODO why does this create an error under any conditions?
|
if error != 0:
|
||||||
raise OSError("Shutdown initiated with error code: {}".format(error))
|
raise OSError(f"BladeRF shutdown with error code: {error}")
|
||||||
|
else:
|
||||||
|
print("BladeRF shutdown successfully")
|
||||||
|
|
||||||
def _probe_bladerf(self):
|
def _probe_bladerf(self):
|
||||||
device = None
|
device = None
|
||||||
|
|
@ -85,24 +88,25 @@ class Blade(SDR):
|
||||||
:type sample_rate: int or float
|
:type sample_rate: int or float
|
||||||
:param center_frequency: The center frequency of the recording.
|
:param center_frequency: The center frequency of the recording.
|
||||||
:type center_frequency: int or float
|
:type center_frequency: int or float
|
||||||
:param gain: The gain set for receiving on the BladeRF
|
:param gain: The gain set for receiving on the BladeRF.
|
||||||
:type gain: int
|
:type gain: int
|
||||||
:param channel: The channel the BladeRF is set to.
|
:param channel: The channel the BladeRF is set to.
|
||||||
:type channel: int
|
:type channel: int
|
||||||
:param buffer_size: The buffer size during receive. Defaults to 8192.
|
:param buffer_size: The buffer size during receive. Defaults to 8192.
|
||||||
:type buffer_size: int
|
:type buffer_size: int
|
||||||
:param gain_mode: 'absolute' passes gain directly to the sdr,
|
:param gain_mode: 'absolute' passes gain directly to the SDR;
|
||||||
'relative' means that gain should be a negative value, and it will be subtracted from the max gain (60).
|
'relative' means that gain should be a negative value, and it will be subtracted from the max gain (60).
|
||||||
:type gain_mode: str
|
:type gain_mode: str
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print("Initializing RX")
|
print("Initializing RX")
|
||||||
|
|
||||||
# Configure BladeRF
|
# Configure BladeRF
|
||||||
self._set_rx_channel(channel)
|
self.set_rx_channel(channel)
|
||||||
self._set_rx_sample_rate(sample_rate)
|
self.set_rx_sample_rate(sample_rate)
|
||||||
self._set_rx_center_frequency(center_frequency)
|
self.set_rx_center_frequency(center_frequency)
|
||||||
self._set_rx_gain(channel, gain, gain_mode)
|
self.set_rx_gain(channel, gain, gain_mode)
|
||||||
self._set_rx_buffer_size(buffer_size)
|
self.set_rx_buffer_size(buffer_size)
|
||||||
|
|
||||||
bw = self.rx_sample_rate
|
bw = self.rx_sample_rate
|
||||||
if bw < 200000:
|
if bw < 200000:
|
||||||
|
|
@ -128,10 +132,8 @@ class Blade(SDR):
|
||||||
stream_timeout=3500000000,
|
stream_timeout=3500000000,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rx_ch.enable = True
|
|
||||||
self.bytes_per_sample = 4
|
|
||||||
|
|
||||||
print("Blade Starting RX...")
|
print("Blade Starting RX...")
|
||||||
|
self.rx_ch.enable = True
|
||||||
self._enable_rx = True
|
self._enable_rx = True
|
||||||
|
|
||||||
while self._enable_rx:
|
while self._enable_rx:
|
||||||
|
|
@ -148,18 +150,34 @@ class Blade(SDR):
|
||||||
print("Blade RX Completed.")
|
print("Blade RX Completed.")
|
||||||
self.rx_ch.enable = False
|
self.rx_ch.enable = False
|
||||||
|
|
||||||
def record(self, num_samples: Optional[int] = None, rx_time: Optional[int | float] = None):
|
def record(
|
||||||
|
self,
|
||||||
|
num_samples: Optional[int] = None,
|
||||||
|
rx_time: Optional[int | float] = None,
|
||||||
|
) -> Recording:
|
||||||
|
"""
|
||||||
|
Create a radio recording (iq samples and metadata) of a given length from the Blade.
|
||||||
|
Either num_samples or rx_time must be provided.
|
||||||
|
init_rx() must be called before record()
|
||||||
|
|
||||||
|
:param num_samples: The number of samples to record.
|
||||||
|
:type num_samples: int, optional
|
||||||
|
:param rx_time: The time to record.
|
||||||
|
:type rx_time: int or float, optional
|
||||||
|
|
||||||
|
returns: Recording object (iq samples and metadata)
|
||||||
|
"""
|
||||||
if not self._rx_initialized:
|
if not self._rx_initialized:
|
||||||
raise RuntimeError("RX was not initialized. init_rx() must be called before _stream_rx() or record()")
|
raise RuntimeError("RX was not initialized. init_rx() must be called before _stream_rx() or record()")
|
||||||
|
|
||||||
if num_samples is not None and rx_time is not None:
|
if num_samples is not None and rx_time is not None:
|
||||||
raise ValueError("Only input one of num_samples or rx_time")
|
raise SDRParameterError("Only input one of num_samples or rx_time")
|
||||||
elif num_samples is not None:
|
elif num_samples is not None:
|
||||||
self._num_samples_to_record = num_samples
|
self._num_samples_to_record = num_samples
|
||||||
elif rx_time is not None:
|
elif rx_time is not None:
|
||||||
self._num_samples_to_record = int(rx_time * self.rx_sample_rate)
|
self._num_samples_to_record = int(rx_time * self.rx_sample_rate)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Must provide input of one of num_samples or rx_time")
|
raise SDRParameterError("Must provide input of one of num_samples or rx_time")
|
||||||
|
|
||||||
# Setup synchronous stream
|
# Setup synchronous stream
|
||||||
self.device.sync_config(
|
self.device.sync_config(
|
||||||
|
|
@ -171,11 +189,10 @@ class Blade(SDR):
|
||||||
stream_timeout=3500000000,
|
stream_timeout=3500000000,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rx_ch.enable = True
|
|
||||||
self.bytes_per_sample = 4
|
|
||||||
|
|
||||||
print("Blade Starting RX...")
|
print("Blade Starting RX...")
|
||||||
|
with self._param_lock:
|
||||||
self._enable_rx = True
|
self._enable_rx = True
|
||||||
|
self.rx_ch.enable = True
|
||||||
|
|
||||||
store_array = np.zeros(
|
store_array = np.zeros(
|
||||||
(1, (self._num_samples_to_record // self.rx_buffer_size + 1) * self.rx_buffer_size), dtype=np.complex64
|
(1, (self._num_samples_to_record // self.rx_buffer_size + 1) * self.rx_buffer_size), dtype=np.complex64
|
||||||
|
|
@ -191,6 +208,7 @@ class Blade(SDR):
|
||||||
|
|
||||||
# Disable module
|
# Disable module
|
||||||
print("Blade RX Completed.")
|
print("Blade RX Completed.")
|
||||||
|
with self._param_lock:
|
||||||
self.rx_ch.enable = False
|
self.rx_ch.enable = False
|
||||||
metadata = {
|
metadata = {
|
||||||
"source": self.__class__.__name__,
|
"source": self.__class__.__name__,
|
||||||
|
|
@ -207,7 +225,7 @@ class Blade(SDR):
|
||||||
center_frequency: int | float,
|
center_frequency: int | float,
|
||||||
gain: int,
|
gain: int,
|
||||||
channel: int,
|
channel: int,
|
||||||
buffer_size: Optional[int] = 8192,
|
buffer_size: Optional[int] = 32768,
|
||||||
gain_mode: Optional[str] = "absolute",
|
gain_mode: Optional[str] = "absolute",
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
|
@ -226,14 +244,22 @@ class Blade(SDR):
|
||||||
:param gain_mode: 'absolute' passes gain directly to the sdr,
|
:param gain_mode: 'absolute' passes gain directly to the sdr,
|
||||||
'relative' means that gain should be a negative value, and it will be subtracted from the max gain (60).
|
'relative' means that gain should be a negative value, and it will be subtracted from the max gain (60).
|
||||||
:type gain_mode: str
|
:type gain_mode: str
|
||||||
|
|
||||||
|
:return: 0 if successful, -1 if there's an error.
|
||||||
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Configure BladeRF
|
# Configure BladeRF
|
||||||
self._set_tx_channel(channel)
|
self.set_tx_channel(channel)
|
||||||
self._set_tx_sample_rate(sample_rate)
|
self.set_tx_sample_rate(sample_rate)
|
||||||
self._set_tx_center_frequency(center_frequency)
|
self.set_tx_center_frequency(center_frequency)
|
||||||
self._set_tx_gain(channel=channel, gain=gain, gain_mode=gain_mode)
|
self.set_tx_gain(channel=channel, gain=gain, gain_mode=gain_mode)
|
||||||
self._set_tx_buffer_size(buffer_size)
|
self.set_tx_buffer_size(buffer_size)
|
||||||
|
|
||||||
|
if self.tx_sample_rate >= 7.5e6 and self.tx_buffer_size < 65536:
|
||||||
|
warnings.warn(
|
||||||
|
"Blade: For high sample rates, a buffer size of 65536, 131072, or 262144 is recommended", UserWarning
|
||||||
|
)
|
||||||
|
|
||||||
bw = self.tx_sample_rate
|
bw = self.tx_sample_rate
|
||||||
if bw < 200000:
|
if bw < 200000:
|
||||||
|
|
@ -302,13 +328,13 @@ class Blade(SDR):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if num_samples is not None and tx_time is not None:
|
if num_samples is not None and tx_time is not None:
|
||||||
raise ValueError("Only input one of num_samples or tx_time")
|
raise SDRParameterError("Only input one of num_samples or tx_time")
|
||||||
elif num_samples is not None:
|
elif num_samples is not None:
|
||||||
tx_time = num_samples / self.tx_sample_rate
|
|
||||||
elif tx_time is not None:
|
|
||||||
pass
|
pass
|
||||||
|
elif tx_time is not None:
|
||||||
|
num_samples = int(tx_time * self.tx_sample_rate)
|
||||||
else:
|
else:
|
||||||
tx_time = len(recording) / self.tx_sample_rate
|
num_samples = len(recording)
|
||||||
|
|
||||||
if isinstance(recording, np.ndarray):
|
if isinstance(recording, np.ndarray):
|
||||||
samples = recording
|
samples = recording
|
||||||
|
|
@ -317,9 +343,15 @@ class Blade(SDR):
|
||||||
warnings.warn("Recording object is multichannel, only channel 0 data was used for transmission")
|
warnings.warn("Recording object is multichannel, only channel 0 data was used for transmission")
|
||||||
samples = recording.data[0]
|
samples = recording.data[0]
|
||||||
else:
|
else:
|
||||||
raise TypeError("recording must be np.ndarray or Recording")
|
raise SDRParameterError("recording must be np.ndarray or Recording")
|
||||||
|
|
||||||
samples = samples.astype(np.complex64, copy=False)
|
samples = samples.astype(np.complex64, copy=False)
|
||||||
|
tx_bytes = self._convert_tx_samples(samples)
|
||||||
|
|
||||||
|
# Transmit in chunks
|
||||||
|
samples_sent = 0
|
||||||
|
len_samples = len(samples)
|
||||||
|
chunk_size = self.tx_buffer_size
|
||||||
|
|
||||||
# Setup stream
|
# Setup stream
|
||||||
self.device.sync_config(
|
self.device.sync_config(
|
||||||
|
|
@ -335,26 +367,21 @@ class Blade(SDR):
|
||||||
self.tx_ch.enable = True
|
self.tx_ch.enable = True
|
||||||
|
|
||||||
print("Blade Starting TX...")
|
print("Blade Starting TX...")
|
||||||
|
|
||||||
# Transmit samples - repeat as needed for the duration
|
|
||||||
start_time = time.time()
|
|
||||||
sample_index = 0
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while time.time() - start_time < tx_time:
|
while samples_sent < num_samples:
|
||||||
# Get next chunk
|
this_chunk_size = min(chunk_size, num_samples - samples_sent)
|
||||||
chunk_size = min(self.tx_buffer_size, len(samples) - sample_index)
|
|
||||||
if chunk_size == 0:
|
|
||||||
# Reached end, loop back
|
|
||||||
sample_index = 0
|
|
||||||
chunk_size = min(self.tx_buffer_size, len(samples))
|
|
||||||
|
|
||||||
chunk = samples[sample_index : sample_index + chunk_size]
|
start_idx = (samples_sent % len_samples) * self.bytes_per_sample
|
||||||
sample_index += chunk_size
|
end_idx = start_idx + this_chunk_size * self.bytes_per_sample
|
||||||
|
end_idx %= len_samples * self.bytes_per_sample
|
||||||
|
|
||||||
# Convert and transmit
|
if end_idx > start_idx:
|
||||||
byte_array = self._convert_tx_samples(chunk)
|
chunk_bytes_arr = tx_bytes[start_idx:end_idx]
|
||||||
self.device.sync_tx(byte_array, len(chunk))
|
else:
|
||||||
|
chunk_bytes_arr = tx_bytes[start_idx:] + tx_bytes[:end_idx]
|
||||||
|
|
||||||
|
self.device.sync_tx(chunk_bytes_arr, this_chunk_size)
|
||||||
|
samples_sent += this_chunk_size
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nTransmission interrupted by user")
|
print("\nTransmission interrupted by user")
|
||||||
|
|
@ -384,29 +411,70 @@ class Blade(SDR):
|
||||||
byte_array = tx_samples.tobytes()
|
byte_array = tx_samples.tobytes()
|
||||||
return byte_array
|
return byte_array
|
||||||
|
|
||||||
def _set_rx_channel(self, channel):
|
def set_rx_channel(self, channel):
|
||||||
|
if channel != 0 and channel != 1:
|
||||||
|
raise SDRParameterError("Channel must be either 0 or 1.")
|
||||||
|
|
||||||
self.rx_channel = channel
|
self.rx_channel = channel
|
||||||
self.rx_ch = self.device.Channel(_bladerf.CHANNEL_RX(channel))
|
self.rx_ch = self.device.Channel(_bladerf.CHANNEL_RX(channel))
|
||||||
print(f"\nBlade channel = {self.rx_ch}")
|
print(f"\nBlade channel = {self.rx_ch}")
|
||||||
|
|
||||||
def _set_rx_sample_rate(self, sample_rate):
|
def set_rx_sample_rate(self, sample_rate):
|
||||||
|
"""
|
||||||
|
Set the sample rate of the receiver.
|
||||||
|
Not callable during recording; Blade requires stream stop/restart to change sample rate.
|
||||||
|
"""
|
||||||
|
with self._param_lock:
|
||||||
|
if hasattr(self, "rx_channel"):
|
||||||
|
range_list = self.device.get_sample_rate_range(self.rx_channel)
|
||||||
|
min_rate, max_rate = range_list[0], range_list[1]
|
||||||
|
else:
|
||||||
|
raise SDRError("Must set channel before setting center frequency")
|
||||||
|
|
||||||
|
if sample_rate < min_rate or sample_rate > max_rate:
|
||||||
|
raise SDRParameterError(
|
||||||
|
f"{self.__class__.__name__}: Sample rate {sample_rate/1e6:.3f} Msps "
|
||||||
|
f"out of range: [{min_rate/1e6:.3f} - {max_rate/1e6:.3f} Msps]"
|
||||||
|
)
|
||||||
|
|
||||||
self.rx_sample_rate = sample_rate
|
self.rx_sample_rate = sample_rate
|
||||||
self.rx_ch.sample_rate = self.rx_sample_rate
|
self.rx_ch.sample_rate = self.rx_sample_rate
|
||||||
print(f"Blade sample rate = {self.rx_ch.sample_rate}")
|
print(f"Blade sample rate = {self.rx_ch.sample_rate}")
|
||||||
|
|
||||||
def _set_rx_center_frequency(self, center_frequency):
|
def set_rx_center_frequency(self, center_frequency):
|
||||||
|
"""
|
||||||
|
Set the center frequency of the receiver.
|
||||||
|
Not callable during recording; Blade requires stream stop/restart to change center frequency.
|
||||||
|
"""
|
||||||
|
with self._param_lock:
|
||||||
|
if hasattr(self, "rx_channel"):
|
||||||
|
range_list = self.device.get_frequency_range(self.rx_channel)
|
||||||
|
min_rate, max_rate = range_list[0], range_list[1]
|
||||||
|
else:
|
||||||
|
raise SDRError("Must set channel before setting center frequency")
|
||||||
|
|
||||||
|
if center_frequency < min_rate or center_frequency > max_rate:
|
||||||
|
raise SDRParameterError(
|
||||||
|
f"{self.__class__.__name__}: Center frequency {center_frequency/1e9:.3f} GHz "
|
||||||
|
f"out of range: [{min_rate/1e9:.3f} - {max_rate/1e9:.3f} GHz]"
|
||||||
|
)
|
||||||
|
|
||||||
self.rx_center_frequency = center_frequency
|
self.rx_center_frequency = center_frequency
|
||||||
self.rx_ch.frequency = center_frequency
|
self.rx_ch.frequency = center_frequency
|
||||||
print(f"Blade center frequency = {self.rx_ch.frequency}")
|
print(f"Blade center frequency = {self.rx_ch.frequency}")
|
||||||
|
|
||||||
def _set_rx_gain(self, channel, gain, gain_mode):
|
def set_rx_gain(self, channel, gain, gain_mode):
|
||||||
|
"""
|
||||||
|
Set the gain of the receiver.
|
||||||
|
Not callable during recording; Blade requires stream stop/restart to change gain.
|
||||||
|
"""
|
||||||
|
with self._param_lock:
|
||||||
rx_gain_min = self.device.get_gain_range(channel)[0]
|
rx_gain_min = self.device.get_gain_range(channel)[0]
|
||||||
rx_gain_max = self.device.get_gain_range(channel)[1]
|
rx_gain_max = self.device.get_gain_range(channel)[1]
|
||||||
|
|
||||||
if gain_mode == "relative":
|
if gain_mode == "relative":
|
||||||
if gain > 0:
|
if gain > 0:
|
||||||
raise ValueError(
|
raise SDRParameterError(
|
||||||
"When gain_mode = 'relative', gain must be < 0. This sets \
|
"When gain_mode = 'relative', gain must be < 0. This sets \
|
||||||
the gain relative to the maximum possible gain."
|
the gain relative to the maximum possible gain."
|
||||||
)
|
)
|
||||||
|
|
@ -425,32 +493,64 @@ class Blade(SDR):
|
||||||
|
|
||||||
print(f"Blade gain = {self.rx_ch.gain}")
|
print(f"Blade gain = {self.rx_ch.gain}")
|
||||||
|
|
||||||
def _set_rx_buffer_size(self, buffer_size):
|
def set_rx_buffer_size(self, buffer_size):
|
||||||
self.rx_buffer_size = buffer_size
|
self.rx_buffer_size = buffer_size
|
||||||
|
|
||||||
def _set_tx_channel(self, channel):
|
def set_tx_channel(self, channel):
|
||||||
|
if channel != 0 and channel != 1:
|
||||||
|
raise SDRParameterError("Channel must be either 0 or 1.")
|
||||||
|
|
||||||
self.tx_channel = channel
|
self.tx_channel = channel
|
||||||
self.tx_ch = self.device.Channel(_bladerf.CHANNEL_TX(self.tx_channel))
|
self.tx_ch = self.device.Channel(_bladerf.CHANNEL_TX(self.tx_channel))
|
||||||
print(f"\nBlade channel = {self.tx_ch}")
|
print(f"\nBlade channel = {self.tx_ch}")
|
||||||
|
|
||||||
def _set_tx_sample_rate(self, sample_rate):
|
def set_tx_sample_rate(self, sample_rate):
|
||||||
|
if hasattr(self, "tx_channel"):
|
||||||
|
range_list = self.device.get_sample_rate_range(self.tx_channel)
|
||||||
|
min_rate, max_rate = range_list[0], range_list[1]
|
||||||
|
else:
|
||||||
|
raise SDRError("Must set channel before setting center frequency")
|
||||||
|
|
||||||
|
if sample_rate < min_rate or sample_rate > max_rate:
|
||||||
|
raise SDRParameterError(
|
||||||
|
f"{self.__class__.__name__}: Sample rate {sample_rate/1e6:.3f} Msps "
|
||||||
|
f"out of range: [{min_rate/1e6:.3f} - {max_rate/1e6:.3f} Msps]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if sample_rate < min_rate or sample_rate > max_rate:
|
||||||
|
raise SDRParameterError(
|
||||||
|
f"{self.__class__.__name__}: Sample rate {sample_rate/1e6:.3f} Msps "
|
||||||
|
f"out of range: [{min_rate/1e6:.3f} - {max_rate/1e6:.3f} Msps]"
|
||||||
|
)
|
||||||
|
|
||||||
self.tx_sample_rate = sample_rate
|
self.tx_sample_rate = sample_rate
|
||||||
self.tx_ch.sample_rate = self.tx_sample_rate
|
self.tx_ch.sample_rate = self.tx_sample_rate
|
||||||
print(f"Blade sample rate = {self.tx_ch.sample_rate}")
|
print(f"Blade sample rate = {self.tx_ch.sample_rate}")
|
||||||
|
|
||||||
def _set_tx_center_frequency(self, center_frequency):
|
def set_tx_center_frequency(self, center_frequency):
|
||||||
|
if hasattr(self, "tx_channel"):
|
||||||
|
range_list = self.device.get_frequency_range(self.tx_channel)
|
||||||
|
min_rate, max_rate = range_list[0], range_list[1]
|
||||||
|
else:
|
||||||
|
raise SDRError("Must set channel before setting center frequency")
|
||||||
|
|
||||||
|
if center_frequency < min_rate or center_frequency > max_rate:
|
||||||
|
raise SDRParameterError(
|
||||||
|
f"{self.__class__.__name__}: Center frequency {center_frequency/1e9:.3f} GHz "
|
||||||
|
f"out of range: [{min_rate/1e9:.3f} - {max_rate/1e9:.3f} GHz]"
|
||||||
|
)
|
||||||
|
|
||||||
self.tx_center_frequency = center_frequency
|
self.tx_center_frequency = center_frequency
|
||||||
self.tx_ch.frequency = center_frequency
|
self.tx_ch.frequency = center_frequency
|
||||||
print(f"Blade center frequency = {self.tx_ch.frequency}")
|
print(f"Blade center frequency = {self.tx_ch.frequency}")
|
||||||
|
|
||||||
def _set_tx_gain(self, channel, gain, gain_mode):
|
def set_tx_gain(self, channel, gain, gain_mode):
|
||||||
|
|
||||||
tx_gain_min = self.device.get_gain_range(channel)[0]
|
tx_gain_min = self.device.get_gain_range(channel)[0]
|
||||||
tx_gain_max = self.device.get_gain_range(channel)[1]
|
tx_gain_max = self.device.get_gain_range(channel)[1]
|
||||||
|
|
||||||
if gain_mode == "relative":
|
if gain_mode == "relative":
|
||||||
if gain > 0:
|
if gain > 0:
|
||||||
raise ValueError(
|
raise SDRParameterError(
|
||||||
"When gain_mode = 'relative', gain must be < 0. This sets\
|
"When gain_mode = 'relative', gain must be < 0. This sets\
|
||||||
the gain relative to the maximum possible gain."
|
the gain relative to the maximum possible gain."
|
||||||
)
|
)
|
||||||
|
|
@ -469,7 +569,7 @@ class Blade(SDR):
|
||||||
|
|
||||||
print(f"Blade gain = {self.tx_ch.gain}")
|
print(f"Blade gain = {self.tx_ch.gain}")
|
||||||
|
|
||||||
def _set_tx_buffer_size(self, buffer_size):
|
def set_tx_buffer_size(self, buffer_size):
|
||||||
self.tx_buffer_size = buffer_size
|
self.tx_buffer_size = buffer_size
|
||||||
|
|
||||||
def set_clock_source(self, source):
|
def set_clock_source(self, source):
|
||||||
|
|
@ -499,4 +599,20 @@ class Blade(SDR):
|
||||||
print(f"BladeRF bias tee {state} on channel {channel}.")
|
print(f"BladeRF bias tee {state} on channel {channel}.")
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
if hasattr(self, "device") and self.device is not None:
|
||||||
|
try:
|
||||||
|
if hasattr(self, "tx_ch"):
|
||||||
|
self.tx_ch.enable = False
|
||||||
|
if hasattr(self, "rx_ch"):
|
||||||
|
self.rx_ch.enable = False
|
||||||
|
|
||||||
self.device.close()
|
self.device.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: error closing bladeRF: {e}")
|
||||||
|
finally:
|
||||||
|
del self.device
|
||||||
|
self.device = None
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
def supports_dynamic_updates(self) -> dict:
|
||||||
|
return {"center_frequency": False, "sample_rate": False, "gain": False}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user