Skip to content

Commit

Permalink
Adding timestamps to Recorded Signals and ProtocolAnalyzer messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Jose Velazquez authored and PepsConti committed Oct 14, 2022
1 parent a4f8db4 commit 7be0da6
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 22 deletions.
12 changes: 6 additions & 6 deletions src/urh/controller/MainController.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def add_simulator_profile(self, filename):
self.ui.tabWidget.setCurrentIndex(3)
self.simulator_tab_controller.load_simulator_file(filename)

def add_signalfile(self, filename: str, group_id=0, enforce_sample_rate=None):
def add_signalfile(self, filename: str, group_id=0, enforce_sample_rate=None, signal_timestamp=0):
if not os.path.exists(filename):
QMessageBox.critical(self, self.tr("File not Found"),
self.tr("The file {0} could not be found. Was it moved or renamed?").format(
Expand All @@ -301,7 +301,7 @@ def add_signalfile(self, filename: str, group_id=0, enforce_sample_rate=None):
else:
sample_rate = self.project_manager.device_conf["sample_rate"]

signal = Signal(filename, sig_name, sample_rate=sample_rate)
signal = Signal(filename, sig_name, sample_rate=sample_rate, timestamp=signal_timestamp)

self.file_proxy_model.open_files.add(filename)
self.add_signal(signal, group_id)
Expand Down Expand Up @@ -738,11 +738,11 @@ def on_show_spectrum_dialog_action_triggered(self):
r.device_parameters_changed.connect(pm.set_device_parameters)
r.show()

@pyqtSlot(list, float)
def on_signals_recorded(self, file_names: list, sample_rate: float):
@pyqtSlot(list)
def on_signals_recorded(self, recorded_files: list):
QApplication.instance().setOverrideCursor(Qt.WaitCursor)
for filename in file_names:
self.add_signalfile(filename, enforce_sample_rate=sample_rate)
for recorded_file in recorded_files:
self.add_signalfile(recorded_file.filename, enforce_sample_rate=recorded_file.sample_rate, signal_timestamp=recorded_file.timestamp)
QApplication.instance().restoreOverrideCursor()

@pyqtSlot()
Expand Down
18 changes: 7 additions & 11 deletions src/urh/controller/dialogs/ReceiveDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
from urh.util import FileOperator
from urh.util.Formatter import Formatter
from datetime import datetime
from urh.signalprocessing.RecordedFile import RecordedFile

class ReceiveDialog(SendRecvDialog):
files_recorded = pyqtSignal(list, float)
files_recorded = pyqtSignal(list)

def __init__(self, project_manager, parent=None, testing_mode=False):
try:
Expand Down Expand Up @@ -47,12 +48,7 @@ def save_before_close(self):
elif reply == QMessageBox.Abort:
return False

try:
sample_rate = self.device.sample_rate
except:
sample_rate = 1e6

self.files_recorded.emit(self.recorded_files, sample_rate)
self.files_recorded.emit(self.recorded_files)
return True

def update_view(self):
Expand Down Expand Up @@ -94,8 +90,8 @@ def on_save_clicked(self):

dev = self.device
big_val = Formatter.big_value_with_suffix
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp,
timestamp_str = datetime.fromtimestamp(dev.data_timestamp).strftime("%Y%m%d_%H%M%S")
initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp_str,
big_val(dev.frequency), big_val(dev.sample_rate))

if dev.bandwidth_is_adjustable:
Expand All @@ -106,5 +102,5 @@ def on_save_clicked(self):
filename = FileOperator.ask_signal_file_name_and_save(initial_name, data,
sample_rate=dev.sample_rate, parent=self)
self.already_saved = True
if filename is not None and filename not in self.recorded_files:
self.recorded_files.append(filename)
if filename is not None and filename not in (x.filename for x in self.recorded_files):
self.recorded_files.append(RecordedFile(filename, dev.sample_rate, dev.data_timestamp))
16 changes: 15 additions & 1 deletion src/urh/dev/VirtualDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat
self.name = name
self.mode = mode
self.backend_handler = backend_handler
self.__data_timestamp = 0

freq = config.DEFAULT_FREQUENCY if freq is None else freq
sample_rate = config.DEFAULT_SAMPLE_RATE if sample_rate is None else sample_rate
Expand Down Expand Up @@ -354,7 +355,10 @@ def baseband_gain(self, value):

@property
def sample_rate(self):
return self.__dev.sample_rate
try:
return self.__dev.sample_rate
except:
return 1e6

@sample_rate.setter
def sample_rate(self, value):
Expand Down Expand Up @@ -490,6 +494,15 @@ def data(self, value):
else:
logger.warning("{}:{} has no data".format(self.__class__.__name__, self.backend.name))

@property
def data_timestamp(self):
if self.backend == Backends.native:
try:
self.__data_timestamp = self.__dev.first_data_timestamp # more accurate timestamp
except:
pass
return self.__data_timestamp

def free_data(self):
if self.backend == Backends.grc:
self.__dev.data = None
Expand Down Expand Up @@ -599,6 +612,7 @@ def spectrum(self):
raise ValueError("Spectrum x only available in spectrum mode")

def start(self):
self.__data_timestamp = time.time()
if self.backend == Backends.grc:
self.__dev.setTerminationEnabled(True)
self.__dev.terminate()
Expand Down
18 changes: 18 additions & 0 deletions src/urh/dev/native/Device.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban
self.error_codes = {}
self.device_messages = []

self.__first_data_timestamp = 0
self.receive_process_function = self.device_receive
self.send_process_function = self.device_send

Expand Down Expand Up @@ -573,8 +574,13 @@ def set_device_direct_sampling_mode(self, value):
self.parent_ctrl_conn.send((self.Command.SET_DIRECT_SAMPLING_MODE.name, int(value)))
except (BrokenPipeError, OSError):
pass

@property
def first_data_timestamp(self):
return self.__first_data_timestamp

def start_rx_mode(self):
self.__first_data_timestamp = 0
self.init_recv_buffer()
self.parent_data_conn, self.child_data_conn = Pipe(duplex=False)
self.parent_ctrl_conn, self.child_ctrl_conn = Pipe()
Expand Down Expand Up @@ -684,8 +690,20 @@ def read_receiving_queue(self):
while self.is_receiving:
try:
byte_buffer = self.parent_data_conn.recv_bytes()

if (self.__first_data_timestamp == 0):
self.__first_data_timestamp = time.time()
calculating_timestamp = True
else:
calculating_timestamp = False

samples = self.bytes_to_iq(byte_buffer)
n_samples = len(samples)

if (calculating_timestamp):
# Timestamp accurate correction
self.__first_data_timestamp -= n_samples / self.sample_rate

if n_samples == 0:
continue

Expand Down
4 changes: 2 additions & 2 deletions src/urh/signalprocessing/Message.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Message(object):
"alignment_offset", "bits_per_symbol"]

def __init__(self, plain_bits, pause: int, message_type: MessageType, rssi=0, modulator_index=0, decoder=None,
fuzz_created=False, bit_sample_pos=None, samples_per_symbol=100, participant=None, bits_per_symbol=1):
fuzz_created=False, bit_sample_pos=None, samples_per_symbol=100, participant=None, bits_per_symbol=1, timestamp=0):
"""
:param pause: pause AFTER the message in samples
Expand All @@ -44,7 +44,7 @@ def __init__(self, plain_bits, pause: int, message_type: MessageType, rssi=0, mo
self.participant = participant # type: Participant
self.message_type = message_type # type: MessageType

self.timestamp = time.time()
self.timestamp = timestamp
self.absolute_time = 0 # set in Compare Frame
self.relative_time = 0 # set in Compare Frame

Expand Down
3 changes: 2 additions & 1 deletion src/urh/signalprocessing/ProtocolAnalyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,10 @@ def get_protocol_from_signal(self):
middle_bit_pos = bit_sample_pos[i][int(len(bits) / 2)]
start, end = middle_bit_pos, middle_bit_pos + samples_per_symbol
rssi = np.mean(signal.iq_array.subarray(start, end).magnitudes_normalized)
message_timestamp = signal.timestamp + (bit_sample_pos[i][0] / signal.sample_rate)
message = Message(bits, pause, message_type=self.default_message_type,
samples_per_symbol=samples_per_symbol, rssi=rssi, decoder=self.decoder,
bit_sample_pos=bit_sample_pos[i], bits_per_symbol=signal.bits_per_symbol)
bit_sample_pos=bit_sample_pos[i], bits_per_symbol=signal.bits_per_symbol, timestamp=message_timestamp)
self.messages.append(message)
i += 1

Expand Down
6 changes: 6 additions & 0 deletions src/urh/signalprocessing/RecordedFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

class RecordedFile:
def __init__(self, filename, sample_rate, timestamp):
self.filename = filename
self.sample_rate = sample_rate
self.timestamp = timestamp
7 changes: 6 additions & 1 deletion src/urh/signalprocessing/Signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Signal(QObject):
protocol_needs_update = pyqtSignal()
data_edited = pyqtSignal() # On Crop/Mute/Delete etc.

def __init__(self, filename: str, name="Signal", modulation: str = None, sample_rate: float = 1e6, parent=None):
def __init__(self, filename: str, name="Signal", modulation: str = None, sample_rate: float = 1e6, timestamp: float = 0, parent=None):
super().__init__(parent)
self.__name = name
self.__tolerance = 5
Expand All @@ -51,6 +51,7 @@ def __init__(self, filename: str, name="Signal", modulation: str = None, sample_
self.__center = 0
self._noise_threshold = 0
self.__sample_rate = sample_rate
self.__timestamp = timestamp
self.noise_min_plot = 0
self.noise_max_plot = 0
self.block_protocol_update = False
Expand Down Expand Up @@ -178,6 +179,10 @@ def sample_rate(self, val):
self.__sample_rate = val
self.sample_rate_changed.emit(val)

@property
def timestamp(self):
return self.__timestamp

@property
def parameter_cache(self) -> dict:
"""
Expand Down

0 comments on commit 7be0da6

Please sign in to comment.