136 changes: 136 additions & 0 deletions sw/supervision/python/log_widget.py
@@ -0,0 +1,136 @@
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QProcess
import utils
from generated.ui_log_widget import Ui_LogWidget
from conf import *
import re
import shutil

TMP_DIR = "/tmp/pprz"

ENVS = [
"PAPARAZZI_HOME",
"PAPARAZZI_SRC",
"HOME"
]

DATE_TAGS = ["YY", "MM", "DD", "hh", "mm", "ss"]
OTHER_TAGS = ["AIRCRAFT", "AC_ID"]


class LogWidget(QWidget, Ui_LogWidget):

def __init__(self, parent=None, *args, **kwargs):
QWidget.__init__(self, parent=parent, *args, **kwargs)
self.setupUi(self)
self.process = QProcess(self)
self.date = None
self.basename = None
self.conf: Conf = None
self.substitutions = {}
self.reset_output()
self.input_button.clicked.connect(self.select_input)
self.output_button.clicked.connect(self.select_output)
self.reset_output_button.clicked.connect(self.reset_output)
self.process_button.clicked.connect(self.start_processing)
self.help_button.clicked.connect(self.show_help)
self.process.finished.connect(self.handle_finished)
self.process.readyReadStandardOutput.connect(self.read_stdout)
self.process.readyReadStandardError.connect(self.read_stderr)

def set_conf(self, conf):
self.conf = conf

def select_input(self):
home = os.path.expandvars("$HOME")
(path, _) = QFileDialog().getOpenFileName(self, "Select log file", home, "Log (*.LOG);; All (*.*)")
self.input_edit.setText(path)

def select_output(self):
start_path = os.path.expandvars(self.output_edit.text())
path = QFileDialog().getExistingDirectory(self, "Select log file", start_path, QFileDialog.ShowDirsOnly)
for env in ENVS:
res = os.getenv(env)
if res in path:
path_sub = path.replace(res, f"${env}")
if os.path.expandvars(path_sub) == path:
# check that the substitution is valid
path = path_sub
self.output_edit.setText(path)

def reset_output(self):
settings = utils.get_settings()
output_path = settings.value("default_log_path", "$PAPARAZZI_HOME/var/logs/$YY-$MM/$DD/$AIRCRAFT", str)
self.output_edit.setText(output_path)

def start_processing(self):
if (self.process.state() == QProcess.ProcessState.NotRunning and
self.input_edit.text() != ""):
program = os.path.expandvars("$PAPARAZZI_SRC/sw/logalizer/sd2log")
input = self.input_edit.text()
output = os.path.expandvars(self.output_edit.text())
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
self.process.start(program, [input, TMP_DIR])
self.status_label.setText("processing...")

def handle_finished(self, exit_code: int, exit_status: QProcess.ExitStatus):
if exit_status != QProcess.ExitStatus.NormalExit or exit_code != 0:
self.status_label.setText(f"exited with code {exit_code}")
return

self.status_label.setText("Log processed, copying files...")
ac_id = self.get_ac_id(f"{TMP_DIR}/{self.basename}.data")
ac = self.conf[ac_id]
self.substitutions["AC_ID"] = str(ac_id)
self.substitutions["AIRCRAFT"] = ac.name
out = os.path.expandvars(self.output_edit.text())
for tag in DATE_TAGS + OTHER_TAGS:
try:
value = self.substitutions[tag]
out = out.replace(f"${tag}", value)
except KeyError:
print(f"no tag {tag}")
self.status_label.setText(f"Error: unknown tag {tag}!")
return
if not os.path.exists(out):
os.makedirs(out)
shutil.move(f"{TMP_DIR}/{self.basename}.data", f"{out}/{self.basename}.data")
shutil.move(f"{TMP_DIR}/{self.basename}.log", f"{out}/{self.basename}.log")
shutil.move(f"{TMP_DIR}/{self.basename}.tlm", f"{out}/{self.basename}.tlm")
self.status_label.setText(f"Files extracted in {out}")

def get_ac_id(self, filename) -> int:
with open(filename, 'r') as data:
ac_id = int(data.readline().split()[1])
return ac_id

def read_stdout(self):
out = self.process.readAllStandardOutput()
out = out.data().decode()

def read_stderr(self):
err = self.process.readAllStandardError()
err = err.data().decode()
for line in err.splitlines():
m = re.match(r'(.*)\.data', line)
if m is not None:
self.basename = m.group(1)
m = re.match(r'(\d{2})_(\d{2})_(\d{2})__(\d{2})_(\d{2})_(\d{2})', self.basename)
if len(m.groups()) == 6:
for tag, value in zip(DATE_TAGS, m.groups()):
self.substitutions[tag] = value

def show_help(self):
QMessageBox.information(self, "logs extractor help",
"<h1>Extract easily your log files!</h1><br/>"
"You can use substitution variables in the output directory:<br/>"
"<b>$AIRCRAFT</b>: aircraft name<br/>"
"<b>$AC_ID</b>: aircraft id<br/>"
"<b>$YY</b>: year<br/>"
"<b>$MM</b>: month<br/>"
"<b>$DD</b>: day<br/>"
"<b>$hh</b>: hour<br/>"
"<b>$mm</b>: minutes<br/>"
"<b>$ss</b>: seconds<br/>")
1 change: 1 addition & 0 deletions sw/supervision/python/paparazzicenter.py
Expand Up @@ -78,6 +78,7 @@ def handle_set_changed(self, conf_file):
self.conf = Conf(conf_file)
Conf.set_current_conf(conf_file)
self.configuration_panel.build_widget.set_conf(self.conf)
self.log_widget.set_conf(self.conf)
acs = [ac.name for ac in self.conf.aircrafts]
self.header.set_acs(acs)

Expand Down
Binary file added sw/supervision/python/ui/icons/help.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added sw/supervision/python/ui/icons/open.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added sw/supervision/python/ui/icons/undo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions sw/supervision/python/ui/resources.qrc
@@ -1,5 +1,8 @@
<RCC>
<qresource prefix="icons">
<file>icons/help.png</file>
<file>icons/undo.png</file>
<file>icons/open.png</file>
<file>icons/error.svg</file>
<file>icons/running.svg</file>
<file>icons/edit.png</file>
Expand Down
56 changes: 36 additions & 20 deletions sw/supervision/python/ui/ui_app_settings.ui
Expand Up @@ -6,32 +6,32 @@
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>131</height>
<width>364</width>
<height>212</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<item row="3" column="1">
<widget class="QCheckBox" name="keep_build_programs_checkbox">
<property name="text">
<string>Text editor</string>
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="text_editor_edit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Keep changes on exit</string>
<string>Terminal Emulator</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<item row="0" column="1">
<widget class="QLineEdit" name="text_editor_edit"/>
</item>
<item row="6" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
Expand All @@ -41,22 +41,29 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="terminal_emulator_edit"/>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="keep_changes_checkbox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Terminal Emulator</string>
<string>Keep changes on exit</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="terminal_emulator_edit"/>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Text editor</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
Expand All @@ -68,13 +75,22 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="keep_build_programs_checkbox">
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
<string>Default log path</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="log_path_edit"/>
</item>
</layout>
</widget>
<resources/>
Expand Down
117 changes: 117 additions & 0 deletions sw/supervision/python/ui/ui_log_widget.ui
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LogWidget</class>
<widget class="QWidget" name="LogWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>359</width>
<height>128</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>SD log file</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="input_button">
<property name="toolTip">
<string>Select SD LOG file</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/icons/open.png</normaloff>:/icons/icons/open.png</iconset>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QToolButton" name="output_button">
<property name="toolTip">
<string>Select output directory</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/icons/open.png</normaloff>:/icons/icons/open.png</iconset>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Output dir</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="output_edit"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="input_edit"/>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="reset_output_button">
<property name="toolTip">
<string>reset to default</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/icons/undo.png</normaloff>:/icons/icons/undo.png</iconset>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QToolButton" name="help_button">
<property name="toolTip">
<string>help</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/icons/help.png</normaloff>:/icons/icons/help.png</iconset>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="status_label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="process_button">
<property name="text">
<string>Process</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>
53 changes: 52 additions & 1 deletion sw/supervision/python/ui/ui_supervision_window.ui
Expand Up @@ -38,6 +38,51 @@
<string>Documentation</string>
</attribute>
</widget>
<widget class="QWidget" name="tools_panel">
<attribute name="title">
<string>Tools</string>
</attribute>
<layout class="QGridLayout" name="gridLayout" rowstretch="1,1" columnstretch="1,1">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Logs</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="LogWidget" name="log_widget" native="true"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
Expand All @@ -48,7 +93,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
<height>30</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
Expand Down Expand Up @@ -103,6 +148,12 @@
<header>doc_panel.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LogWidget</class>
<extends>QWidget</extends>
<header>log_widget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down