cfclient 2017.4__py3-none-any.whl → 2025.12.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cfclient/__init__.py +16 -11
- cfclient/configs/config.json +4 -3
- cfclient/configs/input/Generic_OS_X.json +1 -0
- cfclient/configs/input/Joystick.json +1 -0
- cfclient/configs/input/PS3_Mode_1.json +1 -0
- cfclient/configs/input/PS3_Mode_2.json +1 -0
- cfclient/configs/input/PS3_Mode_3.json +1 -0
- cfclient/configs/input/PS4_Mode_1.json +1 -0
- cfclient/configs/input/PS4_Mode_2.json +1 -0
- cfclient/configs/input/PS4_shoulder_btns_yaw.json +1 -0
- cfclient/configs/input/xbox360_mode1.json +1 -0
- cfclient/configs/log/PID_tuning/Attitude.json +46 -0
- cfclient/configs/log/PID_tuning/Attitude_rate.json +46 -0
- cfclient/configs/log/PID_tuning/Position.json +46 -0
- cfclient/configs/log/PID_tuning/Velocity.json +46 -0
- cfclient/configs/log/PID_tuning_components/Pitch.json +22 -0
- cfclient/configs/log/PID_tuning_components/Pitch_rate.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_x.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_y.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_z.json +22 -0
- cfclient/configs/log/PID_tuning_components/Roll.json +22 -0
- cfclient/configs/log/PID_tuning_components/Roll_rate.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_x.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_y.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_z.json +22 -0
- cfclient/configs/log/PID_tuning_components/Yaw.json +22 -0
- cfclient/configs/log/PID_tuning_components/Yaw_rate.json +22 -0
- cfclient/gui.py +44 -9
- cfclient/headless.py +3 -12
- cfclient/resources/log_param_doc.json +1 -0
- cfclient/ui/connectivity_manager.py +198 -0
- cfclient/ui/dialogs/about.py +53 -36
- cfclient/ui/dialogs/about.ui +23 -3
- cfclient/ui/dialogs/anchor_position_dialog.py +252 -0
- cfclient/ui/dialogs/anchor_position_dialog.ui +138 -0
- cfclient/ui/dialogs/basestation_mode_dialog.py +185 -0
- cfclient/ui/dialogs/basestation_mode_dialog.ui +186 -0
- cfclient/ui/dialogs/bootloader.py +448 -85
- cfclient/ui/dialogs/bootloader.ui +387 -134
- cfclient/ui/dialogs/cf2config.py +4 -4
- cfclient/ui/dialogs/cf2config.ui +3 -4
- cfclient/ui/dialogs/inputconfigdialogue.py +24 -19
- cfclient/ui/dialogs/inputconfigdialogue.ui +53 -30
- cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.py +220 -0
- cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.ui +110 -0
- cfclient/ui/dialogs/lighthouse_system_type_dialog.py +93 -0
- cfclient/ui/dialogs/lighthouse_system_type_dialog.ui +121 -0
- cfclient/ui/dialogs/logconfigdialogue.py +401 -101
- cfclient/ui/dialogs/logconfigdialogue.ui +117 -72
- cfclient/ui/icons/bl.webp +0 -0
- cfclient/ui/icons/bolt.webp +0 -0
- cfclient/ui/icons/cf21.webp +0 -0
- cfclient/ui/icons/checkmark_black.png +0 -0
- cfclient/ui/icons/checkmark_white.png +0 -0
- cfclient/ui/icons/create.png +0 -0
- cfclient/ui/icons/delete.png +0 -0
- cfclient/ui/icons/flapper.webp +0 -0
- cfclient/ui/icons/tag.webp +0 -0
- cfclient/ui/main.py +328 -258
- cfclient/ui/main.ui +184 -80
- cfclient/ui/pluginhelper.py +7 -1
- cfclient/ui/pose_logger.py +116 -0
- cfclient/ui/tab_toolbox.py +208 -0
- cfclient/ui/tabs/ColorLEDTab.py +752 -0
- cfclient/ui/tabs/ConsoleTab.py +48 -13
- cfclient/ui/{toolboxes → tabs}/CrtpSharkToolbox.py +19 -34
- cfclient/ui/tabs/ExampleTab.py +9 -16
- cfclient/ui/tabs/FlightTab.py +437 -325
- cfclient/ui/tabs/GpsTab.py +14 -20
- cfclient/ui/tabs/LEDRingTab.py +277 -0
- cfclient/ui/tabs/LogBlockDebugTab.py +20 -27
- cfclient/ui/tabs/LogBlockTab.py +35 -35
- cfclient/ui/tabs/LogClientTab.py +85 -0
- cfclient/ui/tabs/LogTab.py +50 -27
- cfclient/ui/tabs/ParamTab.py +443 -57
- cfclient/ui/tabs/PlotTab.py +23 -25
- cfclient/ui/tabs/TuningTab.py +292 -0
- cfclient/ui/tabs/__init__.py +12 -2
- cfclient/ui/tabs/colorLEDTab.ui +624 -0
- cfclient/ui/tabs/consoleTab.ui +46 -0
- cfclient/ui/tabs/flightActionContainer.ui +103 -0
- cfclient/ui/tabs/flightTab.ui +724 -237
- cfclient/ui/tabs/{ledTab.ui → ledRingTab.ui} +63 -46
- cfclient/ui/tabs/lighthouse_tab.py +714 -0
- cfclient/ui/tabs/lighthouse_tab.ui +430 -0
- cfclient/ui/tabs/locopositioning_tab.py +606 -389
- cfclient/ui/tabs/locopositioning_tab.ui +370 -253
- cfclient/ui/tabs/logClientTab.ui +52 -0
- cfclient/ui/tabs/logTab.ui +1 -1
- cfclient/ui/tabs/paramTab.ui +204 -3
- cfclient/ui/tabs/tuningTab.ui +773 -0
- cfclient/ui/widgets/ai.py +37 -39
- cfclient/ui/widgets/hexspinbox.py +16 -10
- cfclient/ui/widgets/plotter.ui +39 -47
- cfclient/ui/widgets/plotwidget.py +57 -22
- cfclient/ui/widgets/super_slider.py +112 -0
- cfclient/ui/wizards/__init__.py +0 -0
- cfclient/ui/wizards/bslh_1.png +0 -0
- cfclient/ui/wizards/bslh_2.png +0 -0
- cfclient/ui/wizards/bslh_3.png +0 -0
- cfclient/ui/wizards/bslh_4.png +0 -0
- cfclient/ui/wizards/bslh_5.png +0 -0
- cfclient/ui/wizards/lighthouse_geo_bs_estimation_wizard.py +465 -0
- cfclient/utils/config_manager.py +5 -4
- cfclient/utils/input/__init__.py +77 -19
- cfclient/utils/input/inputinterfaces/wiimote.py +2 -2
- cfclient/utils/input/inputreaderinterface.py +17 -7
- cfclient/utils/input/inputreaders/__init__.py +17 -0
- cfclient/utils/logconfigreader.py +245 -25
- cfclient/utils/logdatawriter.py +3 -1
- cfclient/utils/periodictimer.py +1 -1
- cfclient/utils/ui.py +336 -0
- cfclient/utils/zmq_led_driver.py +5 -0
- cfclient/utils/zmq_param.py +6 -0
- cfclient/version.py +34 -1
- cfclient-2025.12.1.dist-info/METADATA +70 -0
- cfclient-2025.12.1.dist-info/RECORD +152 -0
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/WHEEL +1 -1
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/entry_points.txt +0 -1
- cfclient-2025.12.1.dist-info/licenses/LICENSE.txt +350 -0
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/top_level.txt +1 -0
- cfconfig/Makefile +51 -0
- cfconfig/configblock.py +111 -0
- cfloader/__init__.py +41 -55
- cfzmq/__init__.py +22 -14
- cfclient/ui/dialogs/cf1config.py +0 -265
- cfclient/ui/dialogs/cf1config.ui +0 -260
- cfclient/ui/tab.py +0 -96
- cfclient/ui/tabs/LEDTab.py +0 -169
- cfclient/ui/toolboxes/ConsoleToolbox.py +0 -69
- cfclient/ui/toolboxes/DebugDriverToolbox.py +0 -107
- cfclient/ui/toolboxes/__init__.py +0 -45
- cfclient/ui/toolboxes/consoleToolbox.ui +0 -62
- cfclient/ui/toolboxes/debugDriverToolbox.ui +0 -86
- cfclient-2017.4.dist-info/DESCRIPTION.rst +0 -3
- cfclient-2017.4.dist-info/METADATA +0 -22
- cfclient-2017.4.dist-info/RECORD +0 -104
- cfclient-2017.4.dist-info/metadata.json +0 -1
- /cfclient/{icon-256.png → ui/icons/icon-256.png} +0 -0
- /cfclient/ui/{toolboxes → tabs}/crtpSharkToolbox.ui +0 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
|
|
8
8
|
# || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
|
|
9
9
|
#
|
|
10
|
-
# Copyright (C) 2011-
|
|
10
|
+
# Copyright (C) 2011-2023 Bitcraze AB
|
|
11
11
|
#
|
|
12
12
|
# Crazyflie Nano Quadcopter Client
|
|
13
13
|
#
|
|
@@ -32,12 +32,13 @@ views in the UI.
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
import logging
|
|
35
|
+
import struct
|
|
35
36
|
|
|
36
37
|
import cfclient
|
|
37
|
-
from
|
|
38
|
-
from
|
|
39
|
-
from
|
|
40
|
-
from
|
|
38
|
+
from cfclient.utils.ui import UiUtils
|
|
39
|
+
from PyQt6 import QtWidgets, uic
|
|
40
|
+
from PyQt6.QtCore import Qt, QTimer
|
|
41
|
+
from PyQt6.QtGui import QShortcut, QKeySequence
|
|
41
42
|
|
|
42
43
|
from cflib.crazyflie.log import LogConfig
|
|
43
44
|
|
|
@@ -51,8 +52,9 @@ logger = logging.getLogger(__name__)
|
|
|
51
52
|
|
|
52
53
|
NAME_FIELD = 0
|
|
53
54
|
ID_FIELD = 1
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
TYPE_FIELD = 2
|
|
56
|
+
SIZE_FIELD = 3
|
|
57
|
+
MAX_LOG_SIZE = 26
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
@@ -62,47 +64,320 @@ class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
|
62
64
|
self.setupUi(self)
|
|
63
65
|
self.helper = helper
|
|
64
66
|
|
|
65
|
-
self.logTree.setHeaderLabels(['Name', 'ID', '
|
|
66
|
-
self.varTree.setHeaderLabels(['Name', 'ID', '
|
|
67
|
+
self.logTree.setHeaderLabels(['Name', 'ID', 'Type', 'Size'])
|
|
68
|
+
self.varTree.setHeaderLabels(['Name', 'ID', 'Type', 'Size'])
|
|
69
|
+
self.categoryTree.setHeaderLabels(['Categories'])
|
|
67
70
|
|
|
71
|
+
self.logTree.setSortingEnabled(True)
|
|
72
|
+
self.varTree.setSortingEnabled(True)
|
|
73
|
+
|
|
74
|
+
# Item-click callbacks.
|
|
68
75
|
self.addButton.clicked.connect(lambda: self.moveNode(self.logTree,
|
|
69
76
|
self.varTree))
|
|
70
77
|
self.removeButton.clicked.connect(lambda: self.moveNode(self.varTree,
|
|
71
78
|
self.logTree))
|
|
72
|
-
self.cancelButton.clicked.connect(self.close)
|
|
73
|
-
self.loadButton.clicked.connect(self.loadConfig)
|
|
74
79
|
self.saveButton.clicked.connect(self.saveConfig)
|
|
75
80
|
|
|
81
|
+
self.categoryTree.itemSelectionChanged.connect(self._item_selected)
|
|
82
|
+
self.categoryTree.itemPressed.connect(self._on_item_press)
|
|
83
|
+
self.categoryTree.itemChanged.connect(self._config_changed)
|
|
84
|
+
|
|
85
|
+
# Add/remove item on doubleclick.
|
|
86
|
+
self.logTree.itemDoubleClicked.connect(self.itemDoubleClicked)
|
|
87
|
+
self.varTree.itemDoubleClicked.connect(lambda: self.moveNode(
|
|
88
|
+
self.varTree, self.logTree))
|
|
76
89
|
self.loggingPeriod.textChanged.connect(self.periodChanged)
|
|
77
90
|
|
|
78
|
-
self.packetSize.setMaximum(26)
|
|
79
91
|
self.currentSize = 0
|
|
92
|
+
self.packetSize.setMaximum(100)
|
|
80
93
|
self.packetSize.setValue(0)
|
|
81
94
|
self.period = 0
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
# Used when renaming a config/category
|
|
97
|
+
self._last_pressed_item = None
|
|
98
|
+
|
|
99
|
+
# set icons
|
|
100
|
+
save_icon, delete_icon = self.helper.logConfigReader.get_icons()
|
|
101
|
+
self.createCategoryBtn.setIcon(save_icon)
|
|
102
|
+
self.createConfigBtn.setIcon(save_icon)
|
|
103
|
+
self.deleteBtn.setIcon(delete_icon)
|
|
104
|
+
|
|
105
|
+
# bind buttons
|
|
106
|
+
self.createCategoryBtn.clicked.connect(self._create_category)
|
|
107
|
+
self.createConfigBtn.clicked.connect(self._create_config)
|
|
108
|
+
self.deleteBtn.clicked.connect(self._delete_config)
|
|
109
|
+
|
|
110
|
+
# set tooltips
|
|
111
|
+
self.createCategoryBtn.setToolTip('Create a new category')
|
|
112
|
+
self.createConfigBtn.setToolTip('Create a new log-config')
|
|
113
|
+
self.deleteBtn.setToolTip('Delete category')
|
|
114
|
+
|
|
115
|
+
# enable right-click context-menu
|
|
116
|
+
self.categoryTree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
|
117
|
+
self.categoryTree.customContextMenuRequested.connect(
|
|
118
|
+
self.menuContextTree)
|
|
119
|
+
|
|
120
|
+
# keyboard shortcuts
|
|
121
|
+
shortcut_delete = QShortcut(QKeySequence("Delete"), self)
|
|
122
|
+
shortcut_delete.activated.connect(self._delete_config)
|
|
123
|
+
|
|
124
|
+
shortcut_f2 = QShortcut(QKeySequence("F2"), self)
|
|
125
|
+
shortcut_f2.activated.connect(self._edit_name)
|
|
126
|
+
|
|
127
|
+
self._config_saved_timer = QTimer()
|
|
128
|
+
self._config_saved_timer.timeout.connect(self._config_saved_status)
|
|
129
|
+
|
|
130
|
+
self.closeOnSave.setChecked(True)
|
|
131
|
+
|
|
132
|
+
def itemDoubleClicked(self):
|
|
133
|
+
if self.categoryTree.selectedItems():
|
|
134
|
+
self.moveNode(self.logTree, self.varTree)
|
|
135
|
+
|
|
136
|
+
def _config_saved_status(self):
|
|
137
|
+
self.statusText.setText('')
|
|
138
|
+
self._config_saved_timer.stop()
|
|
139
|
+
|
|
140
|
+
def _on_item_press(self, item):
|
|
141
|
+
self._last_pressed_item = item, item.text(0)
|
|
142
|
+
|
|
143
|
+
def _create_config(self):
|
|
144
|
+
""" Creates a new log-configuration in the chosen
|
|
145
|
+
category. If no category is selected, the
|
|
146
|
+
configuration is stored in the 'Default' category.
|
|
147
|
+
"""
|
|
148
|
+
items = self.categoryTree.selectedItems()
|
|
149
|
+
|
|
150
|
+
if items:
|
|
151
|
+
config = items[0]
|
|
152
|
+
parent = config.parent()
|
|
153
|
+
if parent:
|
|
154
|
+
category = parent.text(0)
|
|
155
|
+
else:
|
|
156
|
+
category = config.text(0)
|
|
157
|
+
|
|
158
|
+
conf_name = self.helper.logConfigReader.create_empty_log_conf(
|
|
159
|
+
category)
|
|
160
|
+
self._reload()
|
|
161
|
+
# Load the newly created log-config.
|
|
162
|
+
self._select_item(conf_name, category)
|
|
163
|
+
self._edit_name()
|
|
164
|
+
|
|
165
|
+
def _create_category(self):
|
|
166
|
+
""" Creates a new category and enables editing the name. """
|
|
167
|
+
category_name = self.helper.logConfigReader.create_category()
|
|
168
|
+
self._load_saved_configs()
|
|
169
|
+
self.sortTrees()
|
|
170
|
+
self._select_category(category_name)
|
|
171
|
+
self._edit_name()
|
|
172
|
+
|
|
173
|
+
def _delete_config(self):
|
|
174
|
+
|
|
175
|
+
""" Deletes a category or a configuration
|
|
176
|
+
depending on if the item has a parent or not.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
items = self.categoryTree.selectedItems()
|
|
180
|
+
if items:
|
|
181
|
+
config = items[0]
|
|
182
|
+
parent = config.parent()
|
|
183
|
+
|
|
184
|
+
if parent:
|
|
185
|
+
# Delete a configuration in the given category.
|
|
186
|
+
category = parent.text(0)
|
|
187
|
+
self.helper.logConfigReader.delete_config(config.text(0),
|
|
188
|
+
category)
|
|
189
|
+
self._reload()
|
|
190
|
+
else:
|
|
191
|
+
# Delete a category and all its log-configurations
|
|
192
|
+
category = config.text(0)
|
|
193
|
+
if category != 'Default':
|
|
194
|
+
self.helper.logConfigReader.delete_category(category)
|
|
195
|
+
self._reload()
|
|
196
|
+
|
|
197
|
+
def _config_changed(self, config):
|
|
198
|
+
""" Changes the name for a log-configuration or a category.
|
|
199
|
+
This is a callback function that gets called when an item
|
|
200
|
+
is changed.
|
|
201
|
+
"""
|
|
202
|
+
item, old_name = self._last_pressed_item
|
|
203
|
+
|
|
204
|
+
parent = config.parent()
|
|
205
|
+
if parent:
|
|
206
|
+
# Change name for a log-config, inside of the category.
|
|
207
|
+
new_conf_name = item.text(0)
|
|
208
|
+
category = parent.text(0)
|
|
209
|
+
self.helper.logConfigReader.change_name_config(old_name,
|
|
210
|
+
new_conf_name,
|
|
211
|
+
category)
|
|
212
|
+
else:
|
|
213
|
+
# Change name for the category.
|
|
214
|
+
category = config.text(0)
|
|
215
|
+
self.helper.logConfigReader.change_name_category(old_name,
|
|
216
|
+
category)
|
|
217
|
+
|
|
218
|
+
def _edit_name(self):
|
|
219
|
+
""" Enables editing the clicked item.
|
|
220
|
+
When the edit is saved, a callback is fired.
|
|
221
|
+
"""
|
|
222
|
+
items = self.categoryTree.selectedItems()
|
|
223
|
+
if items:
|
|
224
|
+
item_clicked = items[0]
|
|
225
|
+
self.categoryTree.editItem(item_clicked, 0)
|
|
226
|
+
|
|
227
|
+
def _reload(self):
|
|
228
|
+
self.resetTrees()
|
|
229
|
+
self._load_saved_configs()
|
|
230
|
+
self.sortTrees()
|
|
231
|
+
|
|
232
|
+
def menuContextTree(self, point):
|
|
233
|
+
|
|
234
|
+
menu = QtWidgets.QMenu()
|
|
235
|
+
|
|
236
|
+
createConfig = None
|
|
237
|
+
createCategory = None
|
|
238
|
+
delete = None
|
|
239
|
+
edit = None
|
|
240
|
+
|
|
241
|
+
item = self.categoryTree.itemAt(point)
|
|
242
|
+
if item:
|
|
243
|
+
createConfig = menu.addAction('Create new log configuration')
|
|
244
|
+
edit = menu.addAction('Edit name')
|
|
245
|
+
|
|
246
|
+
if item.parent():
|
|
247
|
+
delete = menu.addAction('Delete config')
|
|
248
|
+
else:
|
|
249
|
+
delete = menu.addAction('Delete category')
|
|
250
|
+
else:
|
|
251
|
+
createCategory = menu.addAction('Create new Category')
|
|
252
|
+
|
|
253
|
+
action = menu.exec_(self.categoryTree.mapToGlobal(point))
|
|
254
|
+
|
|
255
|
+
if action == createConfig:
|
|
256
|
+
self._create_config()
|
|
257
|
+
elif createCategory:
|
|
258
|
+
self._create_category()
|
|
259
|
+
elif action == delete:
|
|
260
|
+
self._delete_config()
|
|
261
|
+
elif action == edit:
|
|
262
|
+
self._edit_name()
|
|
263
|
+
|
|
264
|
+
def _select_category(self, category):
|
|
265
|
+
items = self.categoryTree.findItems(category, Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchRecursive)
|
|
266
|
+
if items:
|
|
267
|
+
category = items[0]
|
|
268
|
+
self.categoryTree.setCurrentItem(category)
|
|
269
|
+
self._last_pressed_item = category, category.text(0)
|
|
270
|
+
|
|
271
|
+
def _select_item(self, conf_name, category):
|
|
272
|
+
""" loads the given config in the correct category """
|
|
273
|
+
items = self.categoryTree.findItems(conf_name, Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchRecursive)
|
|
274
|
+
for item in items:
|
|
275
|
+
if item.parent().text(0) == category:
|
|
276
|
+
self._last_pressed_item = item, conf_name
|
|
277
|
+
self._loadConfig(category, conf_name)
|
|
278
|
+
self.categoryTree.setCurrentItem(item)
|
|
279
|
+
|
|
280
|
+
def _item_selected(self):
|
|
281
|
+
""" Opens the log configuration of the pressed
|
|
282
|
+
item in the category-tree. """
|
|
283
|
+
items = self.categoryTree.selectedItems()
|
|
284
|
+
|
|
285
|
+
if items:
|
|
286
|
+
config = items[0]
|
|
287
|
+
category = config.parent()
|
|
288
|
+
if category:
|
|
289
|
+
self._loadConfig(category.text(NAME_FIELD),
|
|
290
|
+
config.text(NAME_FIELD))
|
|
291
|
+
else:
|
|
292
|
+
# if category is None, it's the category that's clicked
|
|
293
|
+
self._clear_trees_and_progressbar()
|
|
294
|
+
|
|
295
|
+
def _clear_trees_and_progressbar(self):
|
|
296
|
+
self.varTree.clear()
|
|
297
|
+
self.logTree.clear()
|
|
298
|
+
self.currentSize = 0
|
|
299
|
+
self.loggingPeriod.setText('')
|
|
300
|
+
self.updatePacketSizeBar()
|
|
301
|
+
|
|
302
|
+
def _load_saved_configs(self):
|
|
303
|
+
""" Read saved log-configs and display them on
|
|
304
|
+
the left-side category-tree. """
|
|
305
|
+
|
|
306
|
+
config = None
|
|
307
|
+
config = self.helper.logConfigReader._getLogConfigs()
|
|
308
|
+
|
|
309
|
+
if (config is None):
|
|
310
|
+
logger.warning("Could not load config")
|
|
311
|
+
else:
|
|
312
|
+
self.categoryTree.clear()
|
|
313
|
+
# Create category-tree.
|
|
314
|
+
for conf_category in config:
|
|
315
|
+
category = QtWidgets.QTreeWidgetItem()
|
|
316
|
+
category.setData(NAME_FIELD, Qt.ItemDataRole.DisplayRole, conf_category)
|
|
317
|
+
category.setFlags(category.flags() | Qt.ItemFlag.ItemIsEditable)
|
|
318
|
+
|
|
319
|
+
# Copulate category-tree with log configurations.
|
|
320
|
+
for conf in config[conf_category]:
|
|
321
|
+
item = QtWidgets.QTreeWidgetItem()
|
|
322
|
+
|
|
323
|
+
# Check if name contains category/config-name.
|
|
324
|
+
# This is only true is a new config has been added
|
|
325
|
+
# during a session, and the window re-opened.
|
|
326
|
+
if '/' in conf.name:
|
|
327
|
+
conf_name = conf.name.split('/')[1]
|
|
328
|
+
else:
|
|
329
|
+
conf_name = conf.name
|
|
330
|
+
|
|
331
|
+
item.setData(NAME_FIELD, Qt.ItemDataRole.DisplayRole, conf_name)
|
|
332
|
+
category.addChild(item)
|
|
333
|
+
|
|
334
|
+
# Enable item-editing.
|
|
335
|
+
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsEditable)
|
|
336
|
+
|
|
337
|
+
self.categoryTree.addTopLevelItem(category)
|
|
338
|
+
self.categoryTree.expandItem(category)
|
|
339
|
+
|
|
340
|
+
self.sortTrees()
|
|
341
|
+
|
|
342
|
+
def _loadConfig(self, category, config_name):
|
|
343
|
+
configs = self.helper.logConfigReader._getLogConfigs()[category]
|
|
344
|
+
|
|
345
|
+
if (configs is None):
|
|
346
|
+
logger.warning("Could not load config")
|
|
347
|
+
|
|
348
|
+
else:
|
|
349
|
+
for config in configs:
|
|
350
|
+
name = self._parse_configname(config)
|
|
351
|
+
if name == config_name:
|
|
352
|
+
self.resetTrees()
|
|
353
|
+
self.loggingPeriod.setText("%d" % config.period_in_ms)
|
|
354
|
+
self.period = config.period_in_ms
|
|
355
|
+
for v in config.variables:
|
|
356
|
+
if (v.is_toc_variable()):
|
|
357
|
+
parts = v.name.split(".")
|
|
358
|
+
varParent = parts[0]
|
|
359
|
+
varName = parts[1]
|
|
360
|
+
if self.moveNodeByName(
|
|
361
|
+
self.logTree, self.varTree, varParent,
|
|
362
|
+
varName) is False:
|
|
363
|
+
logger.warning("Could not find node %s.%s!!",
|
|
364
|
+
varParent, varName)
|
|
365
|
+
else:
|
|
366
|
+
logger.warning("Error: Mem vars not supported!")
|
|
367
|
+
|
|
368
|
+
self.sortTrees()
|
|
369
|
+
|
|
370
|
+
def resetTrees(self):
|
|
371
|
+
self.varTree.clear()
|
|
372
|
+
self.logTree.clear()
|
|
373
|
+
self.updateToc()
|
|
96
374
|
|
|
97
375
|
def sortTrees(self):
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
node.
|
|
102
|
-
|
|
103
|
-
Qt.AscendingOrder)
|
|
104
|
-
for node in self.getNodeChildren(self.logTree.invisibleRootItem()):
|
|
105
|
-
node.sortChildren(NAME_FIELD, Qt.AscendingOrder)
|
|
376
|
+
""" Sorts all trees by their name. """
|
|
377
|
+
for tree in [self.logTree, self.varTree, self.categoryTree]:
|
|
378
|
+
tree.sortItems(NAME_FIELD, Qt.SortOrder.AscendingOrder)
|
|
379
|
+
for node in self.getNodeChildren(tree.invisibleRootItem()):
|
|
380
|
+
node.sortChildren(NAME_FIELD, Qt.SortOrder.AscendingOrder)
|
|
106
381
|
|
|
107
382
|
def getNodeChildren(self, treeNode):
|
|
108
383
|
children = []
|
|
@@ -115,25 +390,33 @@ class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
|
115
390
|
for node in self.getNodeChildren(self.varTree.invisibleRootItem()):
|
|
116
391
|
for leaf in self.getNodeChildren(node):
|
|
117
392
|
self.currentSize = (self.currentSize +
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
393
|
+
int(leaf.text(SIZE_FIELD)))
|
|
394
|
+
|
|
395
|
+
self.packetSizeText.setText('%s/%s bytes' % (self.currentSize,
|
|
396
|
+
MAX_LOG_SIZE))
|
|
397
|
+
|
|
398
|
+
if self.currentSize > MAX_LOG_SIZE:
|
|
399
|
+
self.packetSize.setMaximum(self.currentSize / MAX_LOG_SIZE * 100)
|
|
121
400
|
self.packetSize.setFormat("%v%")
|
|
122
|
-
self.packetSize.setValue(self.currentSize /
|
|
401
|
+
self.packetSize.setValue(int(self.currentSize / MAX_LOG_SIZE * 100))
|
|
402
|
+
self.packetSize.setStyleSheet(
|
|
403
|
+
UiUtils.progressbar_stylesheet('red'))
|
|
123
404
|
else:
|
|
124
|
-
self.packetSize.setMaximum(
|
|
405
|
+
self.packetSize.setMaximum(MAX_LOG_SIZE)
|
|
125
406
|
self.packetSize.setFormat("%p%")
|
|
126
|
-
self.packetSize.setValue(self.currentSize)
|
|
407
|
+
self.packetSize.setValue(int(self.currentSize))
|
|
408
|
+
self.packetSize.setStyleSheet(
|
|
409
|
+
UiUtils.progressbar_stylesheet(UiUtils.COLOR_GREEN))
|
|
127
410
|
|
|
128
411
|
def addNewVar(self, logTreeItem, target):
|
|
129
412
|
parentName = logTreeItem.parent().text(NAME_FIELD)
|
|
130
|
-
varParent = target.findItems(parentName, Qt.MatchExactly, NAME_FIELD)
|
|
413
|
+
varParent = target.findItems(parentName, Qt.MatchFlag.MatchExactly, NAME_FIELD)
|
|
131
414
|
|
|
132
415
|
item = logTreeItem.clone()
|
|
133
416
|
|
|
134
417
|
if (len(varParent) == 0):
|
|
135
418
|
newParent = QtWidgets.QTreeWidgetItem()
|
|
136
|
-
newParent.setData(0, Qt.DisplayRole, parentName)
|
|
419
|
+
newParent.setData(0, Qt.ItemDataRole.DisplayRole, parentName)
|
|
137
420
|
newParent.addChild(item)
|
|
138
421
|
target.addTopLevelItem(newParent)
|
|
139
422
|
target.expandItem(newParent)
|
|
@@ -168,7 +451,7 @@ class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
|
168
451
|
self.moveNodeItem(source, target, source.currentItem())
|
|
169
452
|
|
|
170
453
|
def moveNodeByName(self, source, target, parentName, itemName):
|
|
171
|
-
parents = source.findItems(parentName, Qt.MatchExactly, NAME_FIELD)
|
|
454
|
+
parents = source.findItems(parentName, Qt.MatchFlag.MatchExactly, NAME_FIELD)
|
|
172
455
|
node = None
|
|
173
456
|
if (len(parents) > 0):
|
|
174
457
|
parent = parents[0]
|
|
@@ -182,55 +465,43 @@ class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
|
182
465
|
return False
|
|
183
466
|
|
|
184
467
|
def showEvent(self, event):
|
|
185
|
-
self.
|
|
186
|
-
self.
|
|
187
|
-
toc = self.helper.cf.log.toc
|
|
188
|
-
if (len(list(toc.toc.keys())) > 0):
|
|
189
|
-
self.configNameCombo.setEnabled(True)
|
|
190
|
-
else:
|
|
191
|
-
self.configNameCombo.setEnabled(False)
|
|
192
|
-
|
|
193
|
-
def resetTrees(self):
|
|
194
|
-
self.varTree.clear()
|
|
195
|
-
self.updateToc()
|
|
468
|
+
self._clear_trees_and_progressbar()
|
|
469
|
+
self._load_saved_configs()
|
|
196
470
|
|
|
197
471
|
def periodChanged(self, value):
|
|
198
472
|
try:
|
|
199
473
|
self.period = int(value)
|
|
200
474
|
self.checkAndEnableSaveButton()
|
|
201
|
-
except:
|
|
475
|
+
except Exception:
|
|
202
476
|
self.period = 0
|
|
203
477
|
|
|
204
478
|
def showErrorPopup(self, caption, message):
|
|
205
|
-
self.box = QMessageBox() # noqa
|
|
479
|
+
self.box = QtWidgets.QMessageBox() # noqa
|
|
206
480
|
self.box.setWindowTitle(caption)
|
|
207
481
|
self.box.setText(message)
|
|
208
482
|
# self.box.setButtonText(1, "Ok")
|
|
209
|
-
self.box.setWindowFlags(Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)
|
|
483
|
+
self.box.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.MSWindowsFixedSizeDialogHint)
|
|
210
484
|
self.box.show()
|
|
211
485
|
|
|
212
486
|
def updateToc(self):
|
|
213
487
|
self.logTree.clear()
|
|
214
|
-
|
|
215
488
|
toc = self.helper.cf.log.toc
|
|
216
489
|
|
|
217
490
|
for group in list(toc.toc.keys()):
|
|
218
491
|
groupItem = QtWidgets.QTreeWidgetItem()
|
|
219
|
-
groupItem.setData(NAME_FIELD, Qt.DisplayRole, group)
|
|
492
|
+
groupItem.setData(NAME_FIELD, Qt.ItemDataRole.DisplayRole, group)
|
|
220
493
|
for param in list(toc.toc[group].keys()):
|
|
221
494
|
item = QtWidgets.QTreeWidgetItem()
|
|
222
|
-
item.setData(NAME_FIELD, Qt.DisplayRole, param)
|
|
223
|
-
item.setData(ID_FIELD, Qt.DisplayRole,
|
|
495
|
+
item.setData(NAME_FIELD, Qt.ItemDataRole.DisplayRole, param)
|
|
496
|
+
item.setData(ID_FIELD, Qt.ItemDataRole.DisplayRole,
|
|
224
497
|
toc.toc[group][param].ident)
|
|
225
|
-
item.setData(
|
|
226
|
-
toc.toc[group][param].pytype)
|
|
227
|
-
item.setData(CTYPE_FIELD, Qt.DisplayRole,
|
|
498
|
+
item.setData(TYPE_FIELD, Qt.ItemDataRole.DisplayRole,
|
|
228
499
|
toc.toc[group][param].ctype)
|
|
500
|
+
item.setData(SIZE_FIELD, Qt.ItemDataRole.DisplayRole,
|
|
501
|
+
struct.calcsize(toc.toc[group][param].pytype))
|
|
229
502
|
groupItem.addChild(item)
|
|
230
503
|
|
|
231
504
|
self.logTree.addTopLevelItem(groupItem)
|
|
232
|
-
self.logTree.expandItem(groupItem)
|
|
233
|
-
self.sortTrees()
|
|
234
505
|
|
|
235
506
|
def populateDropDown(self):
|
|
236
507
|
self.configNameCombo.clear()
|
|
@@ -240,48 +511,77 @@ class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
|
|
|
240
511
|
if (len(toc) > 0):
|
|
241
512
|
self.loadButton.setEnabled(True)
|
|
242
513
|
|
|
243
|
-
def loadConfig(self):
|
|
244
|
-
cText = self.configNameCombo.currentText()
|
|
245
|
-
config = None
|
|
246
|
-
for d in self.helper.logConfigReader.getLogConfigs():
|
|
247
|
-
if (d.name == cText):
|
|
248
|
-
config = d
|
|
249
|
-
if (config is None):
|
|
250
|
-
logger.warning("Could not load config")
|
|
251
|
-
else:
|
|
252
|
-
self.resetTrees()
|
|
253
|
-
self.loggingPeriod.setText("%d" % config.period_in_ms)
|
|
254
|
-
self.period = config.period_in_ms
|
|
255
|
-
for v in config.variables:
|
|
256
|
-
if (v.is_toc_variable()):
|
|
257
|
-
parts = v.name.split(".")
|
|
258
|
-
varParent = parts[0]
|
|
259
|
-
varName = parts[1]
|
|
260
|
-
if self.moveNodeByName(
|
|
261
|
-
self.logTree, self.varTree, varParent,
|
|
262
|
-
varName) is False:
|
|
263
|
-
logger.warning("Could not find node %s.%s!!",
|
|
264
|
-
varParent, varName)
|
|
265
|
-
else:
|
|
266
|
-
logger.warning("Error: Mem vars not supported!")
|
|
267
|
-
|
|
268
514
|
def saveConfig(self):
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
515
|
+
items = self.categoryTree.selectedItems()
|
|
516
|
+
|
|
517
|
+
if items:
|
|
518
|
+
config = items[0]
|
|
519
|
+
parent = config.parent()
|
|
520
|
+
|
|
521
|
+
if parent:
|
|
522
|
+
|
|
523
|
+
# If we're just editing an existing config, we'll delete
|
|
524
|
+
# the old one first.
|
|
525
|
+
self._delete_from_plottab(self._last_pressed_item[1])
|
|
526
|
+
|
|
527
|
+
category = parent.text(NAME_FIELD)
|
|
528
|
+
config_name = config.text(NAME_FIELD)
|
|
529
|
+
updatedConfig = self.createConfigFromSelection(config_name)
|
|
530
|
+
|
|
531
|
+
if category != 'Default':
|
|
532
|
+
plot_tab_name = '%s/%s' % (category, config_name)
|
|
533
|
+
else:
|
|
534
|
+
plot_tab_name = config_name
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
self.helper.logConfigReader.saveLogConfigFile(
|
|
538
|
+
category,
|
|
539
|
+
updatedConfig)
|
|
540
|
+
self.statusText.setText('Log config succesfully saved!')
|
|
541
|
+
self._config_saved_timer.start(4000)
|
|
542
|
+
if self.closeOnSave.isChecked():
|
|
543
|
+
self.close()
|
|
544
|
+
|
|
545
|
+
except Exception as e:
|
|
546
|
+
self.showErrorPopup("Error when saving file",
|
|
547
|
+
"Error: %s" % e)
|
|
548
|
+
|
|
549
|
+
# The name of the config is changed due to displaying
|
|
550
|
+
# it as category/config-name in the plotter-tab.
|
|
551
|
+
# The config is however saved with only the config-name.
|
|
552
|
+
updatedConfig.name = plot_tab_name
|
|
275
553
|
self.helper.cf.log.add_config(updatedConfig)
|
|
276
554
|
|
|
277
|
-
def
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
555
|
+
def _parse_configname(self, config):
|
|
556
|
+
""" If the configs are placed in a category,
|
|
557
|
+
they are named as Category/confname.
|
|
558
|
+
"""
|
|
559
|
+
parts = config.name.split('/')
|
|
560
|
+
return parts[1] if len(parts) > 1 else parts[0]
|
|
561
|
+
|
|
562
|
+
def _delete_from_plottab(self, conf_name):
|
|
563
|
+
""" Removes a config from the plot-tab. """
|
|
564
|
+
for logconfig in self.helper.cf.log.log_blocks:
|
|
565
|
+
config_to_delete = self._parse_configname(logconfig)
|
|
566
|
+
if config_to_delete == conf_name:
|
|
567
|
+
self.helper.plotTab.remove_config(logconfig)
|
|
568
|
+
self.helper.cf.log.log_blocks.remove(logconfig)
|
|
569
|
+
logconfig.delete()
|
|
570
|
+
|
|
571
|
+
def _get_node_children(self):
|
|
572
|
+
root_item = self.varTree.invisibleRootItem()
|
|
573
|
+
return [root_item.child(i) for i in range(root_item.childCount())]
|
|
574
|
+
|
|
575
|
+
def createConfigFromSelection(self, config):
|
|
576
|
+
logconfig = LogConfig(config, self.period)
|
|
577
|
+
|
|
578
|
+
for node in self._get_node_children():
|
|
281
579
|
parentName = node.text(NAME_FIELD)
|
|
580
|
+
|
|
282
581
|
for leaf in self.getNodeChildren(node):
|
|
283
582
|
varName = leaf.text(NAME_FIELD)
|
|
284
|
-
varType = str(leaf.text(
|
|
583
|
+
varType = str(leaf.text(TYPE_FIELD))
|
|
285
584
|
completeName = "%s.%s" % (parentName, varName)
|
|
286
585
|
logconfig.add_variable(completeName, varType)
|
|
586
|
+
|
|
287
587
|
return logconfig
|