diff --git a/data/decodings/homematic_complete b/data/decodings/homematic_complete index 1db3436896..822eef0026 100755 Binary files a/data/decodings/homematic_complete and b/data/decodings/homematic_complete differ diff --git a/data/decodings/homematic_complete.c b/data/decodings/homematic_complete.c index 233f0b8c4e..8b57ad89c9 100644 --- a/data/decodings/homematic_complete.c +++ b/data/decodings/homematic_complete.c @@ -1,6 +1,8 @@ #include #include +#define SHORTEN_PREAMBLE_TO_32 0 + typedef unsigned char byte; typedef unsigned short uint16; @@ -39,12 +41,19 @@ void print_binary(byte inpt) else putchar('0'); } +void print_preamble_nibbles(int count) +{ + int i; + for (i = 0; i < count; i++) + printf("1010"); +} + int find_preamble_start_in_bit(char *string, int len) { - char homematic_sync[]="11101001110010101110100111001010"; + char homematic_sync[] = "11101001110010101110100111001010"; for(int i = 0, j = 0; i < len; i++) { - if(string[i]==homematic_sync[j]) + if(string[i] == homematic_sync[j]) { j++; if(j == 32 && i>= 63) return i-63; @@ -103,18 +112,19 @@ void xor_lfsr(char *string) int main(int argc, char **argv) { - int i, j, max, offset, len; - byte dec[256]={0}, enc[256]={0}, crc_ok; - char string[2048]={0}; + int i, j, max, offset, len, preamble_additional_length; + byte dec[1024]={0}, enc[1024]={0}, crc_ok; + char string[65536]={0}; uint16 crcvalue; offset = 8; // Preamble + Sync // Copy data (argv[2]) to string if length is ok, shorten to multiple of 8 bit - if (strlen(argv[2]) > 256*8 || strlen(argv[2]) < 4) return -1; + if (strlen(argv[2]) > 8192*8 || strlen(argv[2]) < 4) return -1; len = strlen(argv[2]); i = find_preamble_start_in_bit(argv[2], len); if(i < 0) return 0; // preamble+sync not found or wrong length + preamble_additional_length = i; len = (len-i)-(len-i)%8; memcpy(string, argv[2]+i, len); @@ -130,7 +140,7 @@ int main(int argc, char **argv) for (i = 0; i < strlen(string)-3; i+=8) enc[i/8] = str2byte(&string[i]); max = i/8; - memcpy(&dec, &enc, 256); + memcpy(&dec, &enc, 1024); // Check CRC crcvalue = crc(&dec[8], max-2-8); @@ -167,6 +177,10 @@ int main(int argc, char **argv) dec[max-2] = 0xD0; } + // Prepend preamble longer than 32 bits + if(0 == SHORTEN_PREAMBLE_TO_32 && preamble_additional_length > 0) + print_preamble_nibbles(preamble_additional_length/4); + for(i = 0; i < max; i++) print_binary(dec[i]); } @@ -176,7 +190,7 @@ int main(int argc, char **argv) for (i = 0; i < strlen(string)-3; i+=8) dec[i/8] = str2byte(&string[i]); max = i/8; - memcpy(&enc, &dec, 256); + memcpy(&enc, &dec, 1024); /* * byte[] Dec = new byte[Enc.Length]; @@ -201,7 +215,7 @@ int main(int argc, char **argv) enc[max-2] = (crcvalue >> 8) & 0xFF; // Convert to string - memset(string, 0, 2048); + memset(string, 0, 65536); for(i = 0; i < max; i++) { for(j = 0; j < 8; j++) @@ -211,6 +225,10 @@ int main(int argc, char **argv) // Apply datawhitening xor_lfsr(string+64); + // Prepend preamble longer than 32 bits + if(0 == SHORTEN_PREAMBLE_TO_32 && preamble_additional_length > 0) // Add preamble longer than 32 bits + print_preamble_nibbles(preamble_additional_length/4); + // Print bits and duplicate last bit printf("%s%c\n", string, string[strlen(string)-1]); } diff --git a/data/ui/simulator_dialog.ui b/data/ui/simulator_dialog.ui index 5b29b25819..b21604f7e9 100644 --- a/data/ui/simulator_dialog.ui +++ b/data/ui/simulator_dialog.ui @@ -112,8 +112,8 @@ 0 0 - 178 - 62 + 1066 + 767 @@ -180,8 +180,8 @@ 0 0 - 100 - 30 + 1066 + 767 @@ -237,7 +237,7 @@ - Messages + Status @@ -445,7 +445,7 @@ QGroupBox::indicator:checked { - Transcript + Messages @@ -454,7 +454,7 @@ QGroupBox::indicator:checked { true - You will find the transcript of the simulation here. + Here you will find all messages that were sent and received during simulation. @@ -514,7 +514,7 @@ QGroupBox::indicator:checked { - SDR Status + Devices diff --git a/src/urh/controller/dialogs/SimulatorDialog.py b/src/urh/controller/dialogs/SimulatorDialog.py index cd25b8ffe8..5772062f80 100644 --- a/src/urh/controller/dialogs/SimulatorDialog.py +++ b/src/urh/controller/dialogs/SimulatorDialog.py @@ -173,6 +173,10 @@ def update_buttons(self): self.ui.btnLogAll.setEnabled(not all_items_selected) self.ui.btnLogNone.setEnabled(any_item_selected) + def __get_full_transcript(self) -> list: + return self.simulator.transcript.get_for_all_participants(all_rounds=True, + use_bit=self.ui.radioButtonTranscriptBit.isChecked()) + def update_view(self): for device_message in filter(None, map(str.rstrip, self.simulator.device_messages())): self.ui.textEditDevices.append(device_message) @@ -180,11 +184,11 @@ def update_view(self): for log_msg in filter(None, map(str.rstrip, self.simulator.read_log_messages())): self.ui.textEditSimulation.append(log_msg) - for line in self.simulator.get_full_transcript(start=self.current_transcript_index, - use_bit=self.ui.radioButtonTranscriptBit.isChecked()): + transcript = self.__get_full_transcript() + for line in transcript[self.current_transcript_index:]: self.ui.textEditTranscript.append(line) - self.current_transcript_index = len(self.simulator.transcript) + self.current_transcript_index = len(transcript) current_repeat = str(self.simulator.current_repeat + 1) if self.simulator.is_simulating else "-" self.ui.lblCurrentRepeatValue.setText(current_repeat) @@ -219,8 +223,7 @@ def emit_editing_finished_signals(self): self.sniff_settings_widget.emit_editing_finished_signals() def update_transcript_view(self): - transcript = self.simulator.get_full_transcript(start=0, use_bit=self.ui.radioButtonTranscriptBit.isChecked()) - self.ui.textEditTranscript.setText("\n".join(transcript)) + self.ui.textEditTranscript.setText("\n".join(self.__get_full_transcript())) def closeEvent(self, event: QCloseEvent): self.timer.stop() diff --git a/src/urh/simulator/Simulator.py b/src/urh/simulator/Simulator.py index c2b6a70334..8e1105fbbb 100644 --- a/src/urh/simulator/Simulator.py +++ b/src/urh/simulator/Simulator.py @@ -24,14 +24,13 @@ from urh.simulator.SimulatorRule import SimulatorRule, SimulatorRuleCondition, ConditionType from urh.simulator.SimulatorSleepAction import SimulatorSleepAction from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction +from urh.simulator.Transcript import Transcript from urh.util import util, HTMLFormatter from urh.util.Logger import logger from urh.util.ProjectManager import ProjectManager class Simulator(QObject): - TRANSCRIPT_FORMAT = "{0} ({1}->{2}): {3}" - simulation_started = pyqtSignal() simulation_stopped = pyqtSignal() @@ -45,7 +44,7 @@ def __init__(self, simulator_config: SimulatorConfiguration, modulators, self.modulators = modulators # type: list[Modulator] self.backend_handler = BackendHandler() - self.transcript = [] # type: list[tuple[Participant, Participant, Message, int]] + self.transcript = Transcript() self.current_item = None self.last_sent_message = None @@ -68,10 +67,6 @@ def __initialize_counters(self): if isinstance(item, SimulatorCounterAction): item.reset_value() - def __add_newline_to_transcript(self): - if len(self.transcript) > 0 and self.transcript[-1] != ("", "", "", ""): - self.transcript.append(("", "", "", "")) - def start(self): self.reset() @@ -134,7 +129,7 @@ def stop(self, msg=""): self.simulation_stopped.emit() def restart(self): - self.__add_newline_to_transcript() + self.transcript.start_new_round() self.reset() self.log_message("Restarting simulation") @@ -255,7 +250,7 @@ def simulate(self): command = self.__fill_counter_values(self.current_item.command) self.log_message("Calling {}".format(command)) if self.current_item.pass_transcript: - transcript = "\n".join(self.get_full_transcript()) + transcript = "\n".join(self.transcript.get_for_all_participants(all_rounds=False)) result, rc = util.run_command(command, transcript, use_stdin=True, return_rc=True) else: result, rc = util.run_command(command, param=None, detailed_output=True, return_rc=True) @@ -292,7 +287,7 @@ def simulate(self): elif self.current_item is None: self.current_repeat += 1 next_item = self.simulator_config.rootItem - self.__add_newline_to_transcript() + self.transcript.start_new_round() else: raise ValueError("Unknown action {}".format(type(self.current_item))) @@ -328,7 +323,7 @@ def process_message(self): new_message.plain_bits[start:end] = checksum + array.array("B", [0] * ( (end - start) - len(checksum))) - self.transcript.append((msg.source, msg.destination, new_message, msg.index())) + self.transcript.append(msg.source, msg.destination, new_message, msg.index()) self.send_message(new_message, msg.repeat, sender, msg.modulator_index) self.log_message("Sending message " + msg.index()) self.log_message_labels(new_message) @@ -373,7 +368,7 @@ def process_message(self): decoded_msg = Message(received_msg.decoded_bits, 0, received_msg.message_type, decoder=received_msg.decoder) msg.send_recv_messages.append(decoded_msg) - self.transcript.append((msg.source, msg.destination, decoded_msg, msg.index())) + self.transcript.append(msg.source, msg.destination, decoded_msg, msg.index()) self.log_message("Received message " + msg.index() + ": ") self.log_message_labels(decoded_msg) return @@ -483,16 +478,6 @@ def receive_message(self, sniffer): self.log_message("Receive timeout") return None - def get_transcript(self, participant: Participant): - result = [] - for source, destination, msg, _ in self.transcript: - if participant == destination: - result.append("->" + msg.plain_bits_str) - elif participant == source: - result.append("<-" + msg.plain_bits_str) - - return "\n".join(result) - def get_full_transcript(self, start=0, use_bit=True): result = [] for source, destination, msg, msg_index in self.transcript[start:]: @@ -514,9 +499,9 @@ def generate_message_from_template(self, template_msg: SimulatorMessage): assert valid result = self.expression_parser.evaluate_node(node) elif lbl.value_type_index == 3: - transcript = self.get_transcript(template_msg.source - if template_msg.source.simulate - else template_msg.destination) + transcript = self.transcript.get_for_participant(template_msg.source + if template_msg.source.simulate + else template_msg.destination) if template_msg.destination.simulate: direction = "->" if template_msg.source.simulate else "<-" diff --git a/src/urh/simulator/Transcript.py b/src/urh/simulator/Transcript.py new file mode 100644 index 0000000000..4353d33f29 --- /dev/null +++ b/src/urh/simulator/Transcript.py @@ -0,0 +1,52 @@ +from urh.signalprocessing.Message import Message +from urh.signalprocessing.Participant import Participant + + +class Transcript(object): + FORMAT = "{0} ({1}->{2}): {3}" + + def __init__(self): + self.__data = [] + + def append(self, source: Participant, destination: Participant, msg: Message, index: int): + if len(self.__data) == 0: + self.__data.append([]) + + self.__data[-1].append((source, destination, msg, index)) + + def start_new_round(self): + if len(self.__data) == 0 or len(self.__data[-1]) > 0: + self.__data.append([]) + + def clear(self): + self.__data.clear() + + def get_for_all_participants(self, all_rounds: bool, use_bit=True) -> list: + result = [] + if len(self.__data) == 0: + return result + + rng = range(0, len(self.__data)) if all_rounds else range(len(self.__data)-1, len(self.__data)) + + for i in rng: + for source, destination, msg, msg_index in self.__data[i]: + data = msg.plain_bits_str if use_bit else msg.plain_hex_str + result.append(self.FORMAT.format(msg_index, source.shortname, destination.shortname, data)) + + if i != len(self.__data) - 1: + result.append("") + + return result + + def get_for_participant(self, participant: Participant) -> str: + if len(self.__data) == 0: + return "" + + result = [] + for source, destination, msg, _ in self.__data[-1]: + if participant == destination: + result.append("->" + msg.plain_bits_str) + elif participant == source: + result.append("<-" + msg.plain_bits_str) + + return "\n".join(result) diff --git a/src/urh/ui/ui_simulator_dialog.py b/src/urh/ui/ui_simulator_dialog.py index f1466fc376..f1ed408ff1 100644 --- a/src/urh/ui/ui_simulator_dialog.py +++ b/src/urh/ui/ui_simulator_dialog.py @@ -50,7 +50,7 @@ def setupUi(self, DialogSimulator): self.scrollAreaRX.setWidgetResizable(True) self.scrollAreaRX.setObjectName("scrollAreaRX") self.scrollAreaWidgetContentsRX = QtWidgets.QWidget() - self.scrollAreaWidgetContentsRX.setGeometry(QtCore.QRect(0, 0, 178, 62)) + self.scrollAreaWidgetContentsRX.setGeometry(QtCore.QRect(0, 0, 1066, 767)) self.scrollAreaWidgetContentsRX.setObjectName("scrollAreaWidgetContentsRX") self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContentsRX) self.verticalLayout_6.setObjectName("verticalLayout_6") @@ -76,7 +76,7 @@ def setupUi(self, DialogSimulator): self.scrollAreaTX.setWidgetResizable(True) self.scrollAreaTX.setObjectName("scrollAreaTX") self.scrollAreaWidgetContentsTX = QtWidgets.QWidget() - self.scrollAreaWidgetContentsTX.setGeometry(QtCore.QRect(0, 0, 100, 30)) + self.scrollAreaWidgetContentsTX.setGeometry(QtCore.QRect(0, 0, 1066, 767)) self.scrollAreaWidgetContentsTX.setObjectName("scrollAreaWidgetContentsTX") self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContentsTX) self.verticalLayout_8.setObjectName("verticalLayout_8") @@ -283,15 +283,15 @@ def retranslateUi(self, DialogSimulator): self.checkBoxCaptureFullRX.setText(_translate("DialogSimulator", "Capture complete RX")) self.btnSaveRX.setToolTip(_translate("DialogSimulator", "Save current capture")) self.btnSaveRX.setText(_translate("DialogSimulator", "Save")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulation), _translate("DialogSimulator", "Messages")) - self.textEditTranscript.setPlaceholderText(_translate("DialogSimulator", "You will find the transcript of the simulation here.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulation), _translate("DialogSimulator", "Status")) + self.textEditTranscript.setPlaceholderText(_translate("DialogSimulator", "Here you will find all messages that were sent and received during simulation.")) self.radioButtonTranscriptBit.setText(_translate("DialogSimulator", "Bit &view")) self.radioButtonTranscriptHex.setText(_translate("DialogSimulator", "Hex view")) self.btnOpenInAnalysis.setText(_translate("DialogSimulator", "Open in Analysis")) self.btnSaveTranscript.setText(_translate("DialogSimulator", "...")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("DialogSimulator", "Transcript")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("DialogSimulator", "Messages")) self.textEditDevices.setPlaceholderText(_translate("DialogSimulator", "After starting the simulation you will the log messages of your configured SDRs here.")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_device), _translate("DialogSimulator", "SDR Status")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_device), _translate("DialogSimulator", "Devices")) self.btnStartStop.setText(_translate("DialogSimulator", "Start")) self.tabWidgetSimulatorSettings.setTabText(self.tabWidgetSimulatorSettings.indexOf(self.tabSimulation), _translate("DialogSimulator", "Simulation"))