Commit 05db8768 authored by Karol Hennessy's avatar Karol Hennessy

Merge branch 'ui_dev' into test_UI_new_state_machines_merge

parents d7013674 fabb9426
Pipeline #1589 failed with stages
...@@ -7,12 +7,15 @@ Command-line arguments: ...@@ -7,12 +7,15 @@ Command-line arguments:
-d, --debug : set the level of debug output.Include once for INFO, twice for DEBUG -d, --debug : set the level of debug output.Include once for INFO, twice for DEBUG
-w, --windowed : run the user interface in windowed mode. -w, --windowed : run the user interface in windowed mode.
-r, --resolution : set the window size in pixels. E.g. -r 1920x1080 -r, --resolution : set the window size in pixels. E.g. -r 1920x1080
--no-startup : start the UI without going through the calibration startup sequence.
-l, --language : set the initial language for the UI (can later be set within the
interface). Defaults to English.
""" """
__author__ = ["Benjamin Mummery", "Dónal Murray", "Tiago Sarmento"] __author__ = ["Benjamin Mummery", "Dónal Murray", "Tiago Sarmento"]
__credits__ = ["Benjamin Mummery", "Dónal Murray", "Tim Powell", "Tiago Sarmento"] __credits__ = ["Benjamin Mummery", "Dónal Murray", "Tim Powell", "Tiago Sarmento"]
__license__ = "GPL" __license__ = "GPL"
__version__ = "0.1.1" __version__ = "0.1.2"
__maintainer__ = "Benjamin Mummery" __maintainer__ = "Benjamin Mummery"
__email__ = "benjamin.mummery@stfc.ac.uk" __email__ = "benjamin.mummery@stfc.ac.uk"
__status__ = "Prototype" __status__ = "Prototype"
...@@ -113,6 +116,9 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -113,6 +116,9 @@ class NativeUI(HEVClient, QMainWindow):
): ):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# store variable to change editability of screen - implemented in screen locking
self.enableState = True
# Set the resolution of the display window # Set the resolution of the display window
self.screen_width = resolution[0] self.screen_width = resolution[0]
self.screen_height = resolution[1] self.screen_height = resolution[1]
...@@ -148,8 +154,12 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -148,8 +154,12 @@ class NativeUI(HEVClient, QMainWindow):
# Set up fonts based on the screen resolution. text_font and value_font are 20 # Set up fonts based on the screen resolution. text_font and value_font are 20
# and 40px respectively for 1920*1080. # and 40px respectively for 1920*1080.
self.text_font = QFont("Sans Serif", resolution[0] / 96) self.text_font = QFont("Sans Serif", int(resolution[0] / 96))
self.value_font = QFont("Sans Serif", 2 * resolution[0] / 96) self.value_font = QFont("Sans Serif", int(2 * resolution[0] / 96))
# Set the popup size based on the screen resolution. alarm_popup_width is 400
# for 1920*1080
self.alarm_popup_width = int(resolution[0] / 4.8)
# Import icons # Import icons
self.icons = { self.icons = {
...@@ -157,6 +167,7 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -157,6 +167,7 @@ class NativeUI(HEVClient, QMainWindow):
"button_alarms_page": "exclamation-triangle-solid", "button_alarms_page": "exclamation-triangle-solid",
"button_modes_page": "fan-solid", "button_modes_page": "fan-solid",
"button_settings_page": "sliders-h-solid", "button_settings_page": "sliders-h-solid",
"lock_screen": "lock-solid",
} }
self.iconext = "png" self.iconext = "png"
self.iconpath = self.__find_icons(self.iconext) self.iconpath = self.__find_icons(self.iconext)
...@@ -169,6 +180,8 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -169,6 +180,8 @@ class NativeUI(HEVClient, QMainWindow):
palette = self.palette() palette = self.palette()
palette.setColor(QPalette.Window, self.colors["page_background"]) palette.setColor(QPalette.Window, self.colors["page_background"])
self.alt_palette = self.palette()
# Set up the handlers # Set up the handlers
self.battery_handler = BatteryHandler() self.battery_handler = BatteryHandler()
self.data_handler = DataHandler(plot_history_length=1000) self.data_handler = DataHandler(plot_history_length=1000)
...@@ -324,7 +337,8 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -324,7 +337,8 @@ class NativeUI(HEVClient, QMainWindow):
) )
) )
# TODO: command sending # Startup next and skip buttons should move from the startup widget to the main
# display
self.widgets.nextButton.pressed.connect( self.widgets.nextButton.pressed.connect(
lambda: self.display_stack.setCurrentWidget(self.main_display) lambda: self.display_stack.setCurrentWidget(self.main_display)
) )
...@@ -332,6 +346,12 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -332,6 +346,12 @@ class NativeUI(HEVClient, QMainWindow):
lambda: self.display_stack.setCurrentWidget(self.main_display) lambda: self.display_stack.setCurrentWidget(self.main_display)
) )
self.widgets.lock_button.PageButtonPressed.connect(self.toggle_editability)
# Startup next button should send the ventilator start command.
self.widgets.nextButton.pressed.connect(
lambda: self.q_send_cmd("GENERAL", "START")
)
# Battery Display should update when we get battery info # Battery Display should update when we get battery info
self.battery_handler.UpdateBatteryDisplay.connect( self.battery_handler.UpdateBatteryDisplay.connect(
self.widgets.battery_display.update_status self.widgets.battery_display.update_status
...@@ -372,6 +392,12 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -372,6 +392,12 @@ class NativeUI(HEVClient, QMainWindow):
lambda: self.display_stack.setCurrentWidget(self.startupWidget) lambda: self.display_stack.setCurrentWidget(self.startupWidget)
) )
self.typeValPopupNum.okButton.pressed.connect(
self.typeValPopupNum.handle_ok_press
)
self.typeValPopupAlpha.okButton.pressed.connect(
self.typeValPopupNum.handle_ok_press
)
##### Mode: ##### Mode:
# When mode is switched from mode page, various other locations must respond # When mode is switched from mode page, various other locations must respond
for widget in self.mode_handler.spinDict.values(): for widget in self.mode_handler.spinDict.values():
...@@ -433,18 +459,26 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -433,18 +459,26 @@ class NativeUI(HEVClient, QMainWindow):
button_widget.pressed.connect( button_widget.pressed.connect(
lambda i=key: self.mode_handler.handle_okbutton_click(i) lambda i=key: self.mode_handler.handle_okbutton_click(i)
) )
button_widget.pressed.connect(self.clinical_handler.commandSent)
elif isinstance(button_widget, CancelButtonWidget): elif isinstance(button_widget, CancelButtonWidget):
mode = self.mode_handler.get_mode(key) buttonMode = self.mode_handler.get_mode(key)
button_widget.pressed.connect(self.mode_handler.commandSent) button_widget.pressed.connect(
lambda i=buttonMode: self.mode_handler.handle_cancel_pressed(i)
)
button_widget.pressed.connect(
lambda i=buttonMode: self.clinical_handler.handle_cancel_pressed(i)
)
for key, button_widget in self.mode_handler.mainButtonDict.items(): for key, button_widget in self.mode_handler.mainButtonDict.items():
if isinstance(button_widget, (OkButtonWidget)): if isinstance(button_widget, (OkButtonWidget)):
button_widget.clicked.connect( button_widget.clicked.connect(
self.mode_handler.handle_mainokbutton_click self.mode_handler.handle_mainokbutton_click
) )
button_widget.pressed.connect(self.clinical_handler.commandSent)
elif isinstance(button_widget, CancelButtonWidget): elif isinstance(button_widget, CancelButtonWidget):
# mode = self.mode_handler.get_mode(key) # mode = self.mode_handler.get_mode(key)
button_widget.clicked.connect(self.mode_handler.commandSent) button_widget.clicked.connect(self.mode_handler.commandSent)
button_widget.pressed.connect(self.clinical_handler.commandSent)
for key, spin_widget in self.clinical_handler.limSpinDict.items(): for key, spin_widget in self.clinical_handler.limSpinDict.items():
spin_widget.simpleSpin.manualChanged.connect( spin_widget.simpleSpin.manualChanged.connect(
...@@ -472,8 +506,8 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -472,8 +506,8 @@ class NativeUI(HEVClient, QMainWindow):
self.clinical_handler.handle_cancelbutton_click self.clinical_handler.handle_cancelbutton_click
) )
# for widget in (self.clinical_handler.setSpinDict.values()): for widget in self.clinical_handler.setSpinDict.values():
# self.clinical_handler.UpdateClinical.connect(widget.update_value) self.clinical_handler.UpdateClinical.connect(widget.update_value)
self.mode_handler.OpenPopup.connect(self.messageCommandPopup.populatePopup) self.mode_handler.OpenPopup.connect(self.messageCommandPopup.populatePopup)
self.mode_handler.OpenPopup.connect( self.mode_handler.OpenPopup.connect(
...@@ -500,6 +534,13 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -500,6 +534,13 @@ class NativeUI(HEVClient, QMainWindow):
) )
##### Expert Settings: ##### Expert Settings:
self.widgets.expert_password_widget.okButton.pressed.connect(
self.widgets.expert_password_widget.submit_password
)
self.widgets.expert_password_widget.correctPassword.connect(
lambda: self.widgets.expert_passlock_stack.setCurrentIndex(1)
)
# Expert handler should respond to manual value changes # Expert handler should respond to manual value changes
for key, spin_widget in self.expert_handler.spinDict.items(): for key, spin_widget in self.expert_handler.spinDict.items():
spin_widget.simpleSpin.manualChanged.connect( spin_widget.simpleSpin.manualChanged.connect(
...@@ -640,12 +681,30 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -640,12 +681,30 @@ class NativeUI(HEVClient, QMainWindow):
return 0 return 0
def toggle_editability(self):
"""Set all widgets disabled to lock screen"""
self.enableState = not self.enableState
if self.enableState:
self.alt_palette.setColor(QPalette.Window, self.colors["page_background"])
else:
self.alt_palette.setColor(QPalette.Window, self.colors["page_foreground"])
self.setPalette(self.alt_palette)
for attribute in dir(self.widgets):
widg = self.widgets.get_widget(attribute)
if isinstance(widg, QWidget):
widg.setEnabled(self.enableState)
self.widgets.lock_button.setEnabled(True)
@Slot(str) @Slot(str)
def change_page(self, page_to_show: str) -> int: def change_page(self, page_to_show: str) -> int:
""" """
Change the page shown in page_stack. Change the page shown in page_stack.
""" """
self.widgets.page_stack.setCurrentWidget(getattr(self.widgets, page_to_show)) self.widgets.page_stack.setCurrentWidget(getattr(self.widgets, page_to_show))
self.widgets.expert_passlock_stack.setCurrentIndex(
0
) # reset password lock on expert settings
return 0 return 0
@Slot(str, str, float) @Slot(str, str, float)
...@@ -656,12 +715,9 @@ class NativeUI(HEVClient, QMainWindow): ...@@ -656,12 +715,9 @@ class NativeUI(HEVClient, QMainWindow):
logging.debug("to MCU: cmd: %s", cmd) logging.debug("to MCU: cmd: %s", cmd)
check = self.send_cmd(cmdtype=cmdtype, cmd=cmd, param=param) check = self.send_cmd(cmdtype=cmdtype, cmd=cmd, param=param)
if check: if check:
print("confirmed this command " + cmdtype + " " + cmd)
self.confirmPopup.addConfirmation(cmdtype + " " + cmd) self.confirmPopup.addConfirmation(cmdtype + " " + cmd)
print("added popup")
return 0 return 0
else: else:
print("failed this command " + cmdtype + " " + cmd)
return 1 return 1
@Slot(str) @Slot(str)
......
...@@ -24,6 +24,7 @@ class AlarmWidget(QtWidgets.QWidget): ...@@ -24,6 +24,7 @@ class AlarmWidget(QtWidgets.QWidget):
def __init__(self, NativeUI, abstractAlarm, alarmCarrier, *args, **kwargs): def __init__(self, NativeUI, abstractAlarm, alarmCarrier, *args, **kwargs):
super(AlarmWidget, self).__init__(*args, **kwargs) super(AlarmWidget, self).__init__(*args, **kwargs)
popup_height = int(NativeUI.alarm_popup_width / 10.0)
self.NativeUI = NativeUI self.NativeUI = NativeUI
self.alarmCarrier = alarmCarrier # Needs to refer to its containing object self.alarmCarrier = alarmCarrier # Needs to refer to its containing object
...@@ -37,27 +38,28 @@ class AlarmWidget(QtWidgets.QWidget): ...@@ -37,27 +38,28 @@ class AlarmWidget(QtWidgets.QWidget):
iconpath_check = os.path.join( iconpath_check = os.path.join(
self.NativeUI.iconpath, "exclamation-triangle-solid.png" self.NativeUI.iconpath, "exclamation-triangle-solid.png"
) )
pixmap = QtGui.QPixmap(iconpath_check).scaledToHeight(40) pixmap = QtGui.QPixmap(iconpath_check).scaledToHeight(popup_height)
iconLabel.setPixmap(pixmap) iconLabel.setPixmap(pixmap)
self.layout.addWidget(iconLabel) self.layout.addWidget(iconLabel)
self.textLabel = QtWidgets.QLabel() self.textLabel = QtWidgets.QLabel()
alarmLevel = self.alarmPayload["alarm_type"].replace('PRIORITY_', '') alarmLevel = self.alarmPayload["alarm_type"] # .replace('PRIORITY_', '')
self.textLabel.setText( self.textLabel.setText(
alarmLevel + " - " + self.alarmPayload["alarm_code"] self.alarmPayload["alarm_code"] + " - (" + alarmLevel + ")"
) )
self.textLabel.setFixedWidth(400) self.textLabel.setFixedWidth(NativeUI.alarm_popup_width)
self.textLabel.setAlignment(QtCore.Qt.AlignCenter) self.textLabel.setAlignment(QtCore.Qt.AlignCenter)
self.textLabel.setFont(NativeUI.text_font) self.textLabel.setFont(NativeUI.text_font)
#self.textLabel.setStyleSheet("font-size: " + NativeUI.text_size + ";") # self.textLabel.setStyleSheet("font-size: " + NativeUI.text_size + ";")
self.layout.addWidget(self.textLabel) self.layout.addWidget(self.textLabel)
self.setFixedHeight(40) self.setFixedHeight(popup_height)
self.setLayout(self.layout) self.setLayout(self.layout)
if self.alarmPayload["alarm_type"] == "PRIORITY_HIGH": if self.alarmPayload["alarm_type"] == "PRIORITY_HIGH":
self.setStyleSheet("background-color:red;") self.setStyleSheet("background-color:red;")
elif self.alarmPayload["alarm_type"] == "PRIORITY_MEDIUM": elif self.alarmPayload["alarm_type"] == "PRIORITY_MEDIUM":
self.setStyleSheet("background-color:orange;") self.setStyleSheet("background-color:orange;")
self.setFixedSize(NativeUI.alarm_popup_width + popup_height, popup_height)
# self.timer = QtCore.QTimer() # self.timer = QtCore.QTimer()
# self.timer.setInterval(500) # just faster than 60Hz # self.timer.setInterval(500) # just faster than 60Hz
...@@ -66,14 +68,13 @@ class AlarmWidget(QtWidgets.QWidget): ...@@ -66,14 +68,13 @@ class AlarmWidget(QtWidgets.QWidget):
self.installEventFilter(self) self.installEventFilter(self)
def eventFilter(self, source, event): def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.MouseButtonPress): if event.type() == QtCore.QEvent.MouseButtonPress:
self.NativeUI.widgets.page_buttons.alarms_button.click() self.NativeUI.widgets.page_buttons.alarms_button.click()
return False return False
def get_priority(self): def get_priority(self):
return self.alarmPayload["alarm_type"] return self.alarmPayload["alarm_type"]
def setFont(self, font) -> int: def setFont(self, font) -> int:
""" """
Set the font for textLabel. Set the font for textLabel.
...@@ -95,12 +96,13 @@ class AlarmWidget(QtWidgets.QWidget): ...@@ -95,12 +96,13 @@ class AlarmWidget(QtWidgets.QWidget):
class AlarmPopup(QtWidgets.QDialog): class AlarmPopup(QtWidgets.QDialog):
"""Container class for alarm widgets. Handles ordering and positioning of alarms. """Container class for alarm widgets. Handles ordering and positioning of alarms.
Needs to adjust its size whenever a widget is deleted""" Needs to adjust its size whenever a widget is deleted"""
def __init__(self, NativeUI, *args, **kwargs): def __init__(self, NativeUI, *args, **kwargs):
super(AlarmPopup, self).__init__(*args, **kwargs) super(AlarmPopup, self).__init__(*args, **kwargs)
self.setParent(NativeUI) # ensures popup closes when main UI does self.setParent(NativeUI) # ensures popup closes when main UI does
self.alarmDict = {} self.alarmDict = {}
self.NativeUI = NativeUI self.NativeUI = NativeUI
self.extraAlarms = AlarmExtrasWidget(NativeUI,self) self.extraAlarms = AlarmExtrasWidget(NativeUI, self)
self.layout = QtWidgets.QVBoxLayout() self.layout = QtWidgets.QVBoxLayout()
self.layout.setSpacing(0) self.layout.setSpacing(0)
...@@ -141,7 +143,7 @@ class AlarmPopup(QtWidgets.QDialog): ...@@ -141,7 +143,7 @@ class AlarmPopup(QtWidgets.QDialog):
self.NativeUI, abstractAlarm, self self.NativeUI, abstractAlarm, self
) )
self.refresh_alarm_ordering() self.refresh_alarm_ordering()
#self.layout.addWidget(self.alarmDict[abstractAlarm.alarmPayload["alarm_code"]]) # self.layout.addWidget(self.alarmDict[abstractAlarm.alarmPayload["alarm_code"]])
return 0 return 0
def removeAlarm(self, abstractAlarm): def removeAlarm(self, abstractAlarm):
...@@ -157,25 +159,26 @@ class AlarmPopup(QtWidgets.QDialog): ...@@ -157,25 +159,26 @@ class AlarmPopup(QtWidgets.QDialog):
self.layout.removeWidget(self.alarmDict[key]) self.layout.removeWidget(self.alarmDict[key])
for key in self.alarmDict: for key in self.alarmDict:
if self.alarmDict[key].get_priority() == 'PRIORITY_HIGH': if self.alarmDict[key].get_priority() == "PRIORITY_HIGH":
if self.layout.count() == 4: if self.layout.count() == 4:
self.extraAlarms.update_text(1 + len(self.alarmDict) - self.layout.count()) self.extraAlarms.update_text(
1 + len(self.alarmDict) - self.layout.count()
)
self.layout.addWidget(self.extraAlarms) self.layout.addWidget(self.extraAlarms)
break break
self.layout.addWidget(self.alarmDict[key]) self.layout.addWidget(self.alarmDict[key])
if self.layout.count() < 5: if self.layout.count() < 5:
for key in self.alarmDict: for key in self.alarmDict:
if self.layout.count() == 3: if self.layout.count() == 3:
self.extraAlarms.update_text(len(self.alarmDict) - self.layout.count()) self.extraAlarms.update_text(
len(self.alarmDict) - self.layout.count()
)
self.layout.addWidget(self.extraAlarms) self.layout.addWidget(self.extraAlarms)
break break
if self.alarmDict[key].get_priority() == 'PRIORITY_LOW': if self.alarmDict[key].get_priority() == "PRIORITY_LOW":
self.layout.addWidget(self.alarmDict[key]) self.layout.addWidget(self.alarmDict[key])
# def resetTimer(self, alarmPayload): # def resetTimer(self, alarmPayload):
# self.alarmDict[alarmPayload["alarm_code"]].timer.start() # self.alarmDict[alarmPayload["alarm_code"]].timer.start()
...@@ -188,49 +191,52 @@ class AlarmPopup(QtWidgets.QDialog): ...@@ -188,49 +191,52 @@ class AlarmPopup(QtWidgets.QDialog):
return 0 return 0
class AlarmExtrasWidget(QtWidgets.QWidget): class AlarmExtrasWidget(QtWidgets.QWidget):
"""Object containing information particular to one alarm. """Object containing information particular to one alarm.
Created when alarm received from microcontroller, timeout after alarm signal stops. Created when alarm received from microcontroller, timeout after alarm signal stops.
Is contained within alarmPopup""" Is contained within alarmPopup"""
def __init__(self, NativeUI, alarmCarrier, *args, **kwargs): def __init__(self, NativeUI, alarmCarrier, *args, **kwargs):
super(AlarmExtrasWidget, self).__init__(*args, **kwargs) super(AlarmExtrasWidget, self).__init__(*args, **kwargs)
popup_height = int(NativeUI.alarm_popup_width / 10.0)
self.NativeUI = NativeUI self.NativeUI = NativeUI
self.alarmCarrier = alarmCarrier # Needs to refer to its containing object self.alarmCarrier = alarmCarrier # Needs to refer to its containing object
self.layout = QtWidgets.QHBoxLayout() self.layout = QtWidgets.QHBoxLayout()
self.layout.setSpacing(0) self.layout.setSpacing(0)
self.layout.setMargin(0) self.layout.setMargin(0)
#self.alarmPayload = abstractAlarm.alarmPayload # self.alarmPayload = abstractAlarm.alarmPayload
iconLabel = QtWidgets.QLabel() iconLabel = QtWidgets.QLabel()
iconpath_check = os.path.join( iconpath_check = os.path.join(
self.NativeUI.iconpath, "exclamation-triangle-solid.png" self.NativeUI.iconpath, "exclamation-triangle-solid.png"
) )
pixmap = QtGui.QPixmap(iconpath_check).scaledToHeight(40) pixmap = QtGui.QPixmap(iconpath_check).scaledToHeight(popup_height)
iconLabel.setPixmap(pixmap) iconLabel.setPixmap(pixmap)
self.layout.addWidget(iconLabel) self.layout.addWidget(iconLabel)
self.textLabel = QtWidgets.QLabel() self.textLabel = QtWidgets.QLabel()
self.textLabel.setText('1 More Alarms') self.textLabel.setText("1 More Alarms")
self.textLabel.setFixedWidth(400) self.textLabel.setFixedWidth(NativeUI.alarm_popup_width)
self.textLabel.setAlignment(QtCore.Qt.AlignCenter) self.textLabel.setAlignment(QtCore.Qt.AlignCenter)
self.textLabel.setFont(NativeUI.text_font) self.textLabel.setFont(NativeUI.text_font)
#self.textLabel.setStyleSheet("font-size: " + NativeUI.text_size + ";") # self.textLabel.setStyleSheet("font-size: " + NativeUI.text_size + ";")
self.layout.addWidget(self.textLabel) self.layout.addWidget(self.textLabel)
self.setFixedHeight(40) self.setFixedHeight(popup_height)
self.setLayout(self.layout) self.setLayout(self.layout)
self.setStyleSheet("background-color:red;") self.setStyleSheet("background-color:red;")
#self.priority = "PRIORITY_LOW" # self.priority = "PRIORITY_LOW"
self.installEventFilter(self) self.installEventFilter(self)
self.setFixedSize(NativeUI.alarm_popup_width + popup_height, popup_height)
def update_text(self, num): def update_text(self, num):
self.textLabel.setText(str(num)+ ' More Alarms') self.textLabel.setText(str(num) + " More Alarms")
def eventFilter(self, source, event): def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.MouseButtonPress): if event.type() == QtCore.QEvent.MouseButtonPress:
self.NativeUI.widgets.page_buttons.alarms_button.click() self.NativeUI.widgets.page_buttons.alarms_button.click()
return False return False
......
...@@ -19,10 +19,10 @@ from datetime import datetime ...@@ -19,10 +19,10 @@ from datetime import datetime
class AlarmTable(QtWidgets.QTableWidget): class AlarmTable(QtWidgets.QTableWidget):
"""Table containing all of the alarms since power up are contained. Easily sorted"""
def __init__(self, NativeUI, *args, **kwargs): def __init__(self, NativeUI, *args, **kwargs):
super(AlarmTable, self).__init__(*args, **kwargs) super(AlarmTable, self).__init__(*args, **kwargs)
self.alarmDict = {}
self.setSizePolicy( self.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
) )
...@@ -40,40 +40,33 @@ class AlarmTable(QtWidgets.QTableWidget): ...@@ -40,40 +40,33 @@ class AlarmTable(QtWidgets.QTableWidget):
self.payloadKeys = ["alarm_type", "alarm_code"] self.payloadKeys = ["alarm_type", "alarm_code"]
self.resizeColumnsToContents() self.resizeColumnsToContents()
self.alarmDict = {} self.alarmCellDict = {}
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
self.timer.setInterval(100) self.timer.setInterval(100)
# self.timer.timeout.connect(self.updateDuration) # self.timer.timeout.connect(self.updateDuration)
self.timer.start() self.timer.start()
def addAlarm(self, abstractAlarm): # def addAlarm(self, abstractAlarm):
timestamp = str(datetime.now())[:-3] # timestamp = str(datetime.now())[:-3]
newItem = QtWidgets.QListWidgetItem( # newItem = QtWidgets.QListWidgetItem(
self.solidBell, # self.solidBell,
timestamp # timestamp
+ ": " # + ": "
+ abstractAlarm.alarmPayload["alarm_type"] # + abstractAlarm.alarmPayload["alarm_type"]
+ " - " # + " - "
+ abstractAlarm.alarmPayload["alarm_code"], # + abstractAlarm.alarmPayload["alarm_code"],
) # )
self.insertItem(0, newItem) # add to the top # self.insertItem(0, newItem) # add to the top
# self.labelList
# def removeAlarm(self, abstractAlarm):
# widg = self.cellWidget(rowNumber, 4) # for x in range(self.count() - 1):
# cellItem.setText(str(abstractAlarm.duration)) # if abstractAlarm.alarmPayload["alarm_code"] in self.item(x).text():
# abstractAlarm.alarmExpired.connect(lambda i =newItem, j = abstractAlarm: self.update_duration(i,j)) # self.takeItem(x)
# self.setItem(self.nrows, colnum, newItem)
# tableItem.setText(str(abstractAlarm.duration))
def removeAlarm(self, abstractAlarm):
for x in range(self.count() - 1):
if abstractAlarm.alarmPayload["alarm_code"] in self.item(x).text():
self.takeItem(x)
def addAlarmRow(self, abstractAlarm): def addAlarmRow(self, abstractAlarm):
"""Add a new row 1 cell at a time. Goes through alarm payload to fill information"""
self.setSortingEnabled(False) self.setSortingEnabled(False)
self.setRowCount(self.nrows + 1) self.setRowCount(self.nrows + 1)
colnum = 0
newItem = QtWidgets.QTableWidgetItem(str(abstractAlarm.startTime)[:-3]) newItem = QtWidgets.QTableWidgetItem(str(abstractAlarm.startTime)[:-3])
self.setItem(self.nrows, 0, newItem) self.setItem(self.nrows, 0, newItem)
...@@ -85,26 +78,20 @@ class AlarmTable(QtWidgets.QTableWidget): ...@@ -85,26 +78,20 @@ class AlarmTable(QtWidgets.QTableWidget):
self.setItem(self.nrows, 2, newItem) self.setItem(self.nrows, 2, newItem)
newItem = QtWidgets.QTableWidgetItem(" ") newItem = QtWidgets.QTableWidgetItem(" ")
self.alarmDict[self.nrows] = newItem self.alarmCellDict[self.nrows] = newItem
self.setItem(self.nrows, 3, self.alarmDict[self.nrows]) self.setItem(self.nrows, 3, self.alarmCellDict[self.nrows])
# abstractAlarm.alarmExpired.connect(lambda i = self.alarmDict[self.nrows], j = abstractAlarm: self.update_duration(i,j)) # abstractAlarm.alarmExpired.connect(lambda i = self.alarmCellDict[self.nrows], j = abstractAlarm: self.update_duration(i,j))
self.timer.timeout.connect( self.timer.timeout.connect(
lambda i=self.alarmDict[self.nrows], j=abstractAlarm: self.update_duration( lambda i=self.alarmCellDict[self.nrows], j=abstractAlarm: self.update_duration(
i, j i, j
) )
) )
if self.nrows == 1: #if self.nrows == 1:
self.resizeColumnsToContents() self.resizeColumnsToContents()
self.nrows = self.nrows + 1 self.nrows = self.nrows + 1
self.setSortingEnabled(True) self.setSortingEnabled(True)
def update_duration(self, cellItem, abstractAlarm): def update_duration(self, cellItem, abstractAlarm):
cellItem.setText(str(abstractAlarm.duration)) cellItem.setText(str(abstractAlarm.duration))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
widg = alarmList()
widg.show()
sys.exit(app.exec_())
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"settings":[ "settings":[
[["APNEA", "ms", "APNEA", "SET_THRESHOLD_MIN", "APNEA", 5, 20, 10, 1, 0]], [["APNEA", "ms", "APNEA", "SET_THRESHOLD_MIN", "APNEA", 5, 20, 10, 1, 0]],
[["Check Pressure Patient", "ms", "CHECK_P_PATIENT", "SET_THRESHOLD_MIN", "CHECK_P_PATIENT"],["Check Pressure Patient", "ms", "CHECK_P_PATIENT", "SET_THRESHOLD_MAX", "CHECK_P_PATIENT"]], [["Check Pressure Patient", "ms", "CHECK_P_PATIENT", "SET_THRESHOLD_MIN", "CHECK_P_PATIENT"],["Check Pressure Patient", "ms", "CHECK_P_PATIENT", "SET_THRESHOLD_MAX", "CHECK_P_PATIENT"]],
[["FIO2", "%", "HIGH_FIO2", "SET_THRESHOLD_MIN", "HIGH_FIO2", -10, 0, -5, 0.1, 1],["Percentage O2", "", "fiO2_percent", "SET_TARGET_CURRENT", "FIO2_PERCENT", 20, 100, 21, 1, 0],["FIO2", "%", "HIGH_FIO2", "SET_THRESHOLD_MAX", "HIGH_FIO2", 0, 10, 5, 0.1, 1]], [["FIO2", "%", "HIGH_FIO2", "SET_THRESHOLD_MIN", "HIGH_FIO2", -10, 0, -5, 1, 0],["Percentage O2", "", "fiO2_percent", "SET_TARGET_CURRENT", "FIO2_PERCENT", 0, 100, 51, 1, 0],["FIO2", "%", "HIGH_FIO2", "SET_THRESHOLD_MAX", "HIGH_FIO2", 0, 10, 5, 1, 0]],
[["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MIN", "HIGH_PRESSURE"],["Inhale Pressure","","inspiratory_pressure","SET_TARGET_CURRENT","INSPIRATORY_PRESSURE", 10, 50, 17, 1, 0],["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MAX", "HIGH_PRESSURE"],["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MAX", "HIGH_PRESSURE"]], [["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MIN", "HIGH_PRESSURE"],["Inhale Pressure","","inspiratory_pressure","SET_TARGET_CURRENT","INSPIRATORY_PRESSURE", 10, 50, 17, 1, 0],["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MAX", "HIGH_PRESSURE"],["Pressure", " ", "HIGH_PRESSURE", "SET_THRESHOLD_MAX", "HIGH_PRESSURE"]],
[["Respiratory Rate", " ", "HIGH_RR", "SET_THRESHOLD_MIN", "HIGH_RR", -10, 0, -5, 0.1, 1],["Respiratory Rate","/min","respiratory_rate","SET_TARGET_CURRENT","RESPIRATORY_RATE", 10, 20, 15, 0.1, 1],["Respiratory Rate", " ", "HIGH_RR", "SET_THRESHOLD_MAX", "HIGH_RR", 0, 10, 5, 0.1, 1]], [["Respiratory Rate", " ", "HIGH_RR", "SET_THRESHOLD_MIN", "HIGH_RR", -10, 0, -5, 0.1, 1],["Respiratory Rate","/min","respiratory_rate","SET_TARGET_CURRENT","RESPIRATORY_RATE", 10, 20, 15, 0.1, 1],["Respiratory Rate", " ", "HIGH_RR", "SET_THRESHOLD_MAX", "HIGH_RR", 0, 10, 5, 0.1, 1]],
[["VTE", " ", "HIGH_VTE", "SET_THRESHOLD_MIN", "HIGH_VTE", -10, 0, -5, 1, 0],["Inhale Volume", "", "volume", "SET_TARGET_CURRENT", "VOLUME", 200, 800, 400, 20, 0],["VTE", " ", "HIGH_VTE", "SET_THRESHOLD_MAX", "HIGH_VTE",0, 10, 5, 1, 0]], [["VTE", " ", "HIGH_VTE", "SET_THRESHOLD_MIN", "HIGH_VTE", -10, 0, -5, 1, 0],["Inhale Volume", "", "volume", "SET_TARGET_CURRENT", "VOLUME", 200, 800, 400, 20, 0],["VTE", " ", "HIGH_VTE", "SET_THRESHOLD_MAX", "HIGH_VTE",0, 10, 5, 1, 0]],
......
...@@ -5,22 +5,22 @@ ...@@ -5,22 +5,22 @@
"button_background_disabled":[100, 100, 100], "button_background_disabled":[100, 100, 100],
"button_foreground_enabled":[200, 200, 200], "button_foreground_enabled":[200, 200, 200],
"button_foreground_disabled":[30, 30, 30], "button_foreground_disabled":[30, 30, 30],
"button_background_highlight":[30,93,248],
"button_foreground_highlight":[200,200,200],
"label_background":[0, 0, 0], "label_background":[0, 0, 0],
"label_foreground":[200, 200, 200], "label_foreground":[200, 200, 200],
"display_background":[200, 200, 200], "display_background":[200, 200, 200],
"display_foreground":[0, 0, 0], "display_foreground":[0, 0, 0],
"display_foreground_changed":[0, 200, 0], "display_foreground_changed":[0, 200, 0],
"display_foreground_red":[200, 0, 0], "display_foreground_red":[200, 0, 0],
"plot_pressure":[0, 114, 178],
"plot_volume":[0, 158, 115],
"plot_flow":[240, 228, 66],
"plot_pressure_flow":[230, 159, 0],
"plot_flow_volume":[204, 121, 167],
"plot_volume_pressure":[86, 180, 233],
"highligh":[30,93,248],
"baby_blue":[144, 231, 211], "baby_blue":[144, 231, 211],
"red":[200, 0, 0], "red":[200, 0, 0],
"green":[0, 200, 0], "green":[0, 200, 0]
"pressure_plot":[0, 114, 178],
"volume_plot":[0, 158, 115],
"flow_plot":[240, 228, 66],
"pressure_flow_plot":[230, 159, 0],
"flow_volume_plot":[204, 121, 167],
"volume_pressure_plot":[86, 180, 233],
"red":[255, 0, 0],
"green":[0, 255, 0],
"baby-blue":[0, 0, 200]
} }
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
["Exhale Trigger Sensitivity","","exhale_trigger_threshold","SET_TARGET_","EXHALE_TRIGGER_THRESHOLD", 0, 50, 25, 0.2, 1], ["Exhale Trigger Sensitivity","","exhale_trigger_threshold","SET_TARGET_","EXHALE_TRIGGER_THRESHOLD", 0, 50, 25, 0.2, 1],
["Inhale Pressure","","inspiratory_pressure","SET_TARGET_","INSPIRATORY_PRESSURE", 10, 50, 17, 1, 0], ["Inhale Pressure","","inspiratory_pressure","SET_TARGET_","INSPIRATORY_PRESSURE", 10, 50, 17, 1, 0],
["Inhale Volume", "", "volume", "SET_TARGET_", "VOLUME", 200, 800, 400, 20, 0], ["Inhale Volume", "", "volume", "SET_TARGET_", "VOLUME", 200, 800, 400, 20, 0],
["Percentage O2", "", "fiO2_percent", "SET_TARGET_", "FIO2_PERCENT", 20, 100, 21, 1, 0]], ["Percentage O2", "", "fiO2_percent", "SET_TARGET_", "FIO2_PERCENT", 20, 100, 51, 0.1, 1]],
"radioSettings": ["Inhale Time", "IE Ratio"], "radioSettings": ["Inhale Time", "IE Ratio"],
"enableDict":{"PC/AC":[1, 1,0, 1, 1, 0, 1, 0, 1], "PC/AC-PRVC":[1, 1,1, 0, 1, 0, 1, 1, 1], "PC-PSV":[1, 1,1, 0, 1, 0, 1, 0, 1], "CPAP":[1, 1,0, 1, 1, 0, 1, 0, 1]}, "enableDict":{"PC/AC":[1, 1,0, 1, 1, 0, 1, 0, 1], "PC/AC-PRVC":[1, 1,1, 0, 1, 0, 1, 1, 1], "PC-PSV":[1, 1,1, 0, 1, 0, 1, 0, 1], "CPAP":[1, 1,0, 1, 1, 0, 1, 0, 1]},
"mainPageSettings": ["Inhale Pressure", "Respiratory Rate", "Inhale Time", "IE Ratio", "Percentage O2" ] "mainPageSettings": ["Inhale Pressure", "Respiratory Rate", "Inhale Time", "IE Ratio", "Percentage O2", "PEEP" ]
} }
\ No newline at end of file
...@@ -30,6 +30,7 @@ class SetConfirmPopup(QtWidgets.QDialog): ...@@ -30,6 +30,7 @@ class SetConfirmPopup(QtWidgets.QDialog):
"""Popup called when user wants to send new values to microcontroller. """Popup called when user wants to send new values to microcontroller.
This popup shows changes and asks for confirmation""" This popup shows changes and asks for confirmation"""
# a signal for each handler, so the UI knows which values were updated
ExpertSend = QtCore.Signal() ExpertSend = QtCore.Signal()
ModeSend = QtCore.Signal() ModeSend = QtCore.Signal()
PersonalSend = QtCore.Signal() PersonalSend = QtCore.Signal()
...@@ -41,6 +42,7 @@ class SetConfirmPopup(QtWidgets.QDialog): ...@@ -41,6 +42,7 @@ class SetConfirmPopup(QtWidgets.QDialog):
self.NativeUI = NativeUI self.NativeUI = NativeUI
self.handler = None self.handler = None
# list widget displays the changes to be sent to MCU in human readable way
self.listWidget = QtWidgets.QListWidget() self.listWidget = QtWidgets.QListWidget()
self.listWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.listWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
...@@ -61,18 +63,19 @@ class SetConfirmPopup(QtWidgets.QDialog): ...@@ -61,18 +63,19 @@ class SetConfirmPopup(QtWidgets.QDialog):
vlayout.addLayout(buttonHLayout) vlayout.addLayout(buttonHLayout)
self.setLayout(vlayout) self.setLayout(vlayout)
# self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
# self.setWindowOpacity(0.5)
def populatePopup(self, handlerWidget, messageList): def populatePopup(self, handlerWidget, messageList):
"""One popup is used for all the handlers. It is populated when called by a particular handler"""
self.handler = handlerWidget self.handler = handlerWidget
self.clearPopup() self.listWidget.clear()
if messageList == []: if messageList == []:
messageList = ["no values were set"] messageList = ["no values were set"]
for item in messageList: for item in messageList:
listItem = QtWidgets.QListWidgetItem(item) listItem = QtWidgets.QListWidgetItem(item)
listItem.setFlags(QtCore.Qt.NoItemFlags) listItem.setFlags(QtCore.Qt.NoItemFlags)
self.listWidget.addItem(listItem) self.listWidget.addItem(listItem)
# adjust size according to list contents
self.listWidget.setFixedHeight( self.listWidget.setFixedHeight(
self.listWidget.sizeHintForRow(0) * self.listWidget.count() + 10 self.listWidget.sizeHintForRow(0) * self.listWidget.count() + 10
) )
...@@ -82,14 +85,10 @@ class SetConfirmPopup(QtWidgets.QDialog): ...@@ -82,14 +85,10 @@ class SetConfirmPopup(QtWidgets.QDialog):
self.listWidget.update() self.listWidget.update()
self.update() self.update()
return 0
def clearPopup(self):
self.listWidget.clear()
self.commandList = []
def ok_button_pressed(self): def ok_button_pressed(self):
"""Send commands when ok button is clicked""" """Emit signal to connect with handler corresponding to editted values."""
# self.parentTemplate.liveUpdating = True
if self.handler is None: if self.handler is None:
logging.error("Popup ok_button_pressed called before popupatePopup") logging.error("Popup ok_button_pressed called before popupatePopup")
return 1 return 1
...@@ -114,6 +113,8 @@ class SetConfirmPopup(QtWidgets.QDialog): ...@@ -114,6 +113,8 @@ class SetConfirmPopup(QtWidgets.QDialog):
class confirmWidget(QtWidgets.QWidget): class confirmWidget(QtWidgets.QWidget):
"""A widget displaying an individual command confirmation from the MCU. Is contained in confirmPopup"""
def __init__(self, NativeUI, confirmMessage, *args, **kwargs): def __init__(self, NativeUI, confirmMessage, *args, **kwargs):
super(confirmWidget, self).__init__(*args, **kwargs) super(confirmWidget, self).__init__(*args, **kwargs)
self.hlayout = QtWidgets.QHBoxLayout() self.hlayout = QtWidgets.QHBoxLayout()
...@@ -137,16 +138,18 @@ class confirmWidget(QtWidgets.QWidget): ...@@ -137,16 +138,18 @@ class confirmWidget(QtWidgets.QWidget):
self.setLayout(self.hlayout) self.setLayout(self.hlayout)
self.setFixedHeight(50) self.setFixedHeight(50)
# create timer to handle timeout
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
self.timer.setInterval(10000) self.timer.setInterval(10000)
self.timer.timeout.connect(self.confirmTimeout) self.timer.timeout.connect(self.confirmTimeout)
self.timer.start() self.timer.start()
def confirmTimeout(self): def confirmTimeout(self):
"""Widget should expire after a defined time"""
self.parent().confirmDict.pop( self.parent().confirmDict.pop(
self.confirmMessage.replace("/", "_").replace("-", "_") self.confirmMessage.replace("/", "_").replace("-", "_") # - and / are not used in dictionary keys
) )
self.setParent(None) self.setParent(None) # delete self
class confirmPopup(QtWidgets.QDialog): class confirmPopup(QtWidgets.QDialog):
...@@ -173,12 +176,11 @@ class confirmPopup(QtWidgets.QDialog): ...@@ -173,12 +176,11 @@ class confirmPopup(QtWidgets.QDialog):
) # no window title ) # no window title
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
self.timer.setInterval(500) # just faster than 60Hz self.timer.setInterval(500)
self.timer.timeout.connect(self.adjustSize) self.timer.timeout.connect(self.adjustSize) # container needs to adjust to a new number of confirmWidgets
self.timer.start() self.timer.start()
def addConfirmation(self, confirmMessage): def addConfirmation(self, confirmMessage):
print('adding confirmation')
"""Add a confirmation to the popup. Triggered when UI receives a confirmation from the microcontroller""" """Add a confirmation to the popup. Triggered when UI receives a confirmation from the microcontroller"""
self.confirmDict[confirmMessage] = confirmWidget( self.confirmDict[confirmMessage] = confirmWidget(
self.NativeUI, confirmMessage self.NativeUI, confirmMessage
...@@ -187,8 +189,10 @@ class confirmPopup(QtWidgets.QDialog): ...@@ -187,8 +189,10 @@ class confirmPopup(QtWidgets.QDialog):
return 0 return 0
def location_on_window(self): def location_on_window(self):
"""Places confirmWidgets at the top center of the screen"""
screen = QtWidgets.QDesktopWidget().screenGeometry() screen = QtWidgets.QDesktopWidget().screenGeometry()
# widget = self.geometry() # widget = self.geometry()
x = screen.width() - screen.width() / 2 x = screen.width() - screen.width() / 2
y = 0 # screen.height() - widget.height() y = 0 # screen.height() - widget.height()
self.move(x, y) self.move(x, y)
return 0
...@@ -23,6 +23,7 @@ class AbstractTypeValPopup(QtWidgets.QDialog): ...@@ -23,6 +23,7 @@ class AbstractTypeValPopup(QtWidgets.QDialog):
"""Popup takes user input to put in spin box. """ """Popup takes user input to put in spin box. """
okPressed = QtCore.Signal(str) okPressed = QtCore.Signal(str)
cancelPressed = QtCore.Signal() cancelPressed = QtCore.Signal()
correctPassword = QtCore.Signal()
def __init__(self, NativeUI, characterType, *args, **kwargs): def __init__(self, NativeUI, characterType, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
...@@ -32,6 +33,8 @@ class AbstractTypeValPopup(QtWidgets.QDialog): ...@@ -32,6 +33,8 @@ class AbstractTypeValPopup(QtWidgets.QDialog):
grid = QtWidgets.QGridLayout() grid = QtWidgets.QGridLayout()
grid.setSpacing(1) grid.setSpacing(1)
#self.label_text, self.min, self.max, self.initVal, self.step, self.decPlaces = 'Enter Password', 0, 10000, 0, 0, 0
self.setStyleSheet("border-radius:4px; background-color:black") self.setStyleSheet("border-radius:4px; background-color:black")
self.characterType = characterType self.characterType = characterType
self.label = QtWidgets.QLabel() # self.label_text) self.label = QtWidgets.QLabel() # self.label_text)
...@@ -84,24 +87,17 @@ class AbstractTypeValPopup(QtWidgets.QDialog): ...@@ -84,24 +87,17 @@ class AbstractTypeValPopup(QtWidgets.QDialog):
self.numberpad.numberPressed.connect(self.handle_alphapress) self.numberpad.numberPressed.connect(self.handle_alphapress)
hlayout.addWidget(self.lineEdit) hlayout.addWidget(self.lineEdit)
# grid.addWidget(self.lineEdit, 0, 0, 1, 2)
self.hlayout2 = QtWidgets.QHBoxLayout() self.hlayout2 = QtWidgets.QHBoxLayout()
self.okButton = OkButtonWidget(NativeUI) self.okButton = OkButtonWidget(NativeUI)
self.okButton.setEnabled(True) self.okButton.setEnabled(True)
self.okButton.pressed.connect(self.handle_ok_press)
self.hlayout2.addWidget(self.okButton) self.hlayout2.addWidget(self.okButton)
# grid.addWidget(self.okButton, 1, 0)
self.cancelButton = CancelButtonWidget(NativeUI) self.cancelButton = CancelButtonWidget(NativeUI)
self.cancelButton.setEnabled(True) self.cancelButton.setEnabled(True)
self.hlayout2.addWidget(self.cancelButton) self.hlayout2.addWidget(self.cancelButton)
# grid.addWidget(self.cancelButton, 1, 1)
vlayout = QtWidgets.QVBoxLayout() vlayout = QtWidgets.QVBoxLayout()
vlayout.addWidget(self.label) vlayout.addWidget(self.label)
vlayout.addLayout(hlayout) vlayout.addLayout(hlayout)
...@@ -112,6 +108,13 @@ class AbstractTypeValPopup(QtWidgets.QDialog): ...@@ -112,6 +108,13 @@ class AbstractTypeValPopup(QtWidgets.QDialog):
self.setWindowFlags( self.setWindowFlags(
QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint
) # no window title ) # no window title
self.password = 'A'
def submit_password(self):
val = self.lineEdit.text()
if val == self.password:
self.correctPassword.emit()
self.lineEdit.setText('') # reset text whether or not password was successful
def handle_ok_press(self): def handle_ok_press(self):
val = self.lineEdit.text() val = self.lineEdit.text()
...@@ -131,7 +134,7 @@ class AbstractTypeValPopup(QtWidgets.QDialog): ...@@ -131,7 +134,7 @@ class AbstractTypeValPopup(QtWidgets.QDialog):
self.label_text = currentWidg.label_text self.label_text = currentWidg.label_text
self.label.setText(self.label_text) self.label.setText(self.label_text)
self.lineEdit.setText(str(currentWidg.value())) self.lineEdit.setText('')#str(currentWidg.value()))
def handle_numberpress(self, symbol): def handle_numberpress(self, symbol):
"""Handle number pad button press. Put button value in line edit text, and handle inputs """Handle number pad button press. Put button value in line edit text, and handle inputs
......
...@@ -14,6 +14,7 @@ __status__ = "Prototype" ...@@ -14,6 +14,7 @@ __status__ = "Prototype"
from PySide2 import QtCore, QtGui, QtWidgets from PySide2 import QtCore, QtGui, QtWidgets
from widget_library.ok_cancel_buttons_widget import OkButtonWidget, CancelButtonWidget from widget_library.ok_cancel_buttons_widget import OkButtonWidget, CancelButtonWidget
import json
# from global_widgets.global_ok_cancel_buttons import okButton, cancelButton # from global_widgets.global_ok_cancel_buttons import okButton, cancelButton
...@@ -23,6 +24,8 @@ class TabModeswitchButton(QtWidgets.QWidget): ...@@ -23,6 +24,8 @@ class TabModeswitchButton(QtWidgets.QWidget):
def __init__(self, NativeUI, *args, **kwargs): def __init__(self, NativeUI, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
"""Button opens popup for user to switch modes.
The label is updated to show the current operating mode"""
self.NativeUI = NativeUI self.NativeUI = NativeUI
...@@ -46,19 +49,19 @@ class TabModeswitchButton(QtWidgets.QWidget): ...@@ -46,19 +49,19 @@ class TabModeswitchButton(QtWidgets.QWidget):
# self.mode_popup.okbutton.pressed.connect(self.changeText) # self.mode_popup.okbutton.pressed.connect(self.changeText)
def update_mode(self, mode): def update_mode(self, mode):
print("updating mode") """Update button text to show operating mode"""
print(mode)
self.switchButton.setText(mode) self.switchButton.setText(mode)
# self.mode_popup.update_mode(mode) return 0
def switch_button_pressed(self): def switch_button_pressed(self):
"""Button pressed, open popup, ensure correct mode is selected in popup."""
if self.mode_popup == False: if self.mode_popup == False:
self.mode_popup = modeswitchPopup(self.NativeUI) self.mode_popup = modeswitchPopup(self.NativeUI)
self.mode_popup.okbutton.pressed.connect(self.changeText) self.mode_popup.okbutton.pressed.connect(self.changeText)
else: else:
self.mode_popup.radioButtons[self.NativeUI.currentMode].click() self.mode_popup.radioButtons[self.NativeUI.currentMode].click()
self.mode_popup.show() self.mode_popup.show()
return 0
def changeText(self): def changeText(self):
self.switchButton.setText(self.mode_popup.mode) self.switchButton.setText(self.mode_popup.mode)
...@@ -71,43 +74,15 @@ class TabModeswitchButton(QtWidgets.QWidget): ...@@ -71,43 +74,15 @@ class TabModeswitchButton(QtWidgets.QWidget):
class modeswitchPopup(QtWidgets.QWidget): class modeswitchPopup(QtWidgets.QWidget):
def __init__(self, NativeUI, *args, **kwargs): def __init__(self, NativeUI, *args, **kwargs):
"""A popup used to switch modes. Allows the user to compare the values they are setting with current setting
and to navigate to mode setting page to edit those values."""
super(modeswitchPopup, self).__init__(*args, **kwargs) super(modeswitchPopup, self).__init__(*args, **kwargs)
self.NativeUI = NativeUI self.NativeUI = NativeUI
self.settingsList = [ with open("NativeUI/configs/mode_config.json") as json_file:
[ modeDict = json.load(json_file)
"Respiratory Rate",
"/min", self.settingsList = modeDict['settings']
"respiratory_rate",
"SET_TARGET_",
"RESPIRATORY_RATE",
],
["Inhale Time", "s", "inhale_time", "SET_TARGET_", "INHALE_TIME"],
["IE Ratio", "", "ie_ratio", "SET_TARGET_", "IE_RATIO"],
[
"Inhale Trigger Sensitivity",
"",
"inhale_trigger_threshold",
"SET_TARGET_",
"INHALE_TRIGGER_THRESHOLD",
],
[
"Exhale Trigger Sensitivity",
"",
"exhale_trigger_threshold",
"SET_TARGET_",
"EXHALE_TRIGGER_THRESHOLD",
],
[
"Inhale Pressure",
"",
"inspiratory_pressure",
"SET_TARGET_",
"INSPIRATORY_PRESSURE",
],
["Inhale Volume", "", "volume", "SET_TARGET_", "VOLUME"],
["Percentage O2", "", "fiO2_percent", "SET_TARGET_", "FIO2_PERCENT"],
] # self.NativeUI.modes_view.modeTab.settingsList
modeList = self.NativeUI.modeList modeList = self.NativeUI.modeList
vradioLayout = QtWidgets.QVBoxLayout() vradioLayout = QtWidgets.QVBoxLayout()
...@@ -115,29 +90,27 @@ class modeswitchPopup(QtWidgets.QWidget): ...@@ -115,29 +90,27 @@ class modeswitchPopup(QtWidgets.QWidget):
self.radioButtons = {} self.radioButtons = {}
for mode in modeList: for mode in modeList:
button = QtWidgets.QRadioButton(mode) button = QtWidgets.QRadioButton(mode)
goToButton = QtWidgets.QPushButton(mode) goto_button = QtWidgets.QPushButton(mode)
goToButton.pressed.connect(lambda j=mode: self.goToPressed(j)) goto_button.pressed.connect(lambda j=mode: self.goto_pressed(j))
hlayout = QtWidgets.QHBoxLayout() hlayout = QtWidgets.QHBoxLayout()
hlayout.addWidget(button) hlayout.addWidget(button)
hlayout.addWidget(goToButton) hlayout.addWidget(goto_button)
self.radioButtons[mode] = button self.radioButtons[mode] = button
vradioLayout.addLayout(hlayout) vradioLayout.addLayout(hlayout)
button.pressed.connect(lambda i=button: self.update_settings_data(i))
if mode == self.NativeUI.currentMode:
button.click()
groupBox.setLayout(vradioLayout) groupBox.setLayout(vradioLayout)
## Values display ## Values display
valuesLayout = QtWidgets.QHBoxLayout() valuesLayout = QtWidgets.QHBoxLayout()
# Title labels:
initLabel = QtWidgets.QLabel(" ") # titles initLabel = QtWidgets.QLabel(" ")
initVal = QtWidgets.QLabel("Current") initVal = QtWidgets.QLabel("Current")
initVal.setAlignment(QtCore.Qt.AlignCenter) initVal.setAlignment(QtCore.Qt.AlignCenter)
newVal = QtWidgets.QLabel("New") newVal = QtWidgets.QLabel("New")
newVal.setAlignment(QtCore.Qt.AlignCenter) newVal.setAlignment(QtCore.Qt.AlignCenter)
newVal.setStyleSheet("color: red") newVal.setStyleSheet("color: red")
# Populate actual values in loop
self.labelList, self.currentLabelList, self.newLabelList = [], [], [] self.labelList, self.currentLabelList, self.newLabelList = [], [], []
vlayout1, vlayout2, vlayout3 = ( vlayout1, vlayout2, vlayout3 = (
QtWidgets.QVBoxLayout(), QtWidgets.QVBoxLayout(),
...@@ -186,6 +159,12 @@ class modeswitchPopup(QtWidgets.QWidget): ...@@ -186,6 +159,12 @@ class modeswitchPopup(QtWidgets.QWidget):
vlayout.addLayout(hlayout) vlayout.addLayout(hlayout)
vlayout.addLayout(hbuttonlayout) vlayout.addLayout(hbuttonlayout)
for mode in modeList:
button = self.radioButtons[mode]
button.pressed.connect(lambda i=button: self.update_settings_data(i))
if mode == self.NativeUI.currentMode:
button.click()
## Final, general, initiation steps ## Final, general, initiation steps
self.setLayout(vlayout) self.setLayout(vlayout)
...@@ -201,8 +180,8 @@ class modeswitchPopup(QtWidgets.QWidget): ...@@ -201,8 +180,8 @@ class modeswitchPopup(QtWidgets.QWidget):
) )
# self.radioButtons[self.NativeUI.currentMode].click() # self.radioButtons[self.NativeUI.currentMode].click()
def goToPressed(self, mode): def goto_pressed(self, mode):
# Switch to the modes page """On button press, show mode page in UI"""
self.NativeUI.widgets.page_stack.setCurrentWidget( self.NativeUI.widgets.page_stack.setCurrentWidget(
self.NativeUI.widgets.modes_page self.NativeUI.widgets.modes_page
) )
...@@ -219,25 +198,21 @@ class modeswitchPopup(QtWidgets.QWidget): ...@@ -219,25 +198,21 @@ class modeswitchPopup(QtWidgets.QWidget):
self.close() self.close()
def update_settings_data(self, button): def update_settings_data(self, button):
self.spinDict = self.NativeUI.widgets.mode_handler.spinDict """Respond to button press and update labels in modeswitch popup"""
self.mode = button.text() # .replace("/", "_").replace("-", "_") self.spinDict = self.NativeUI.mode_handler.spinDict
self.mode = button.text()
data = self.NativeUI.get_db("targets")
for settings, currentLabel, newLabel in zip( for settings, currentLabel, newLabel in zip(
self.settingsList, self.currentLabelList, self.newLabelList self.settingsList, self.currentLabelList, self.newLabelList
): ):
currentVal = self.spinDict[ currentVal = self.spinDict[
"spin_" + self.NativeUI.currentMode + "_" + settings[2] "spin_" + self.NativeUI.currentMode + "_" + settings[2]
].get_value() ].get_value()
# currentVal = self.spinDict[
# self.NativeUI.currentMode # .replace("/", "_").replace("-", "_")
# ][settings].get_value()
currentLabel.setText(str(round(currentVal, 4))) currentLabel.setText(str(round(currentVal, 4)))
setVal = self.spinDict["spin_" + self.mode + "_" + settings[2]].get_value() setVal = self.spinDict["spin_" + self.mode + "_" + settings[2]].get_value()
newLabel.setText(str(round(setVal, 4))) newLabel.setText(str(round(setVal, 4)))
print("done")
def ok_button_pressed(self): def ok_button_pressed(self):
"""Switch to selected mode"""
if self.NativeUI.currentMode == self.mode: if self.NativeUI.currentMode == self.mode:
a = 1 # do nothing a = 1 # do nothing
else: else:
...@@ -246,22 +221,13 @@ class modeswitchPopup(QtWidgets.QWidget): ...@@ -246,22 +221,13 @@ class modeswitchPopup(QtWidgets.QWidget):
) )
self.NativeUI.currentMode = self.mode self.NativeUI.currentMode = self.mode
self.close() self.close()
# ensure main page buttons display IE Ratio or Inhale Time as enabled return 0
# if self.NativeUI.widgets.mode_settings_tab.tabsDict[
# self.mode
# ].radioButtonRat.isChecked():
# # self.NativeUI.main_view.tab_spin.setStackWidget("IE Ratio")
# self.NativeUI.widgets.spin_buttons.setStackWidget("IE Ratio")
# else:
# # self.NativeUI.main_view.tab_spin.setStackWidget("Inhale Time")
# self.NativeUI.widgets.spin_buttons.setStackWidget("Inhale Time")
# self.modeSwitched.emit()
return 0
def cancel_button_pressed(self): def cancel_button_pressed(self):
"""Close popup without doing anything"""
self.close() self.close()
return 0 return 0
def update_mode(self, mode): def update_mode(self, mode):
"""When mode is changed the popup radio buttons should show the new mode"""
self.mode_popup.radioButtons[mode].click() self.mode_popup.radioButtons[mode].click()
...@@ -121,6 +121,13 @@ class ClinicalHandler(PayloadHandler): ...@@ -121,6 +121,13 @@ class ClinicalHandler(PayloadHandler):
self.active_payload() self.active_payload()
self.refresh_button_colour() self.refresh_button_colour()
def handle_cancel_pressed(self,buttonMode):
if buttonMode == self.NativeUI.currentMode:
print('modes match ')
self.commandSent()
else:
print('do nothing in clinical')
def commandSent(self): def commandSent(self):
self.commandList = [] self.commandList = []
for key, widget in dict(self.limSpinDict, **self.setSpinDict).items(): for key, widget in dict(self.limSpinDict, **self.setSpinDict).items():
......
...@@ -76,6 +76,9 @@ class ModeHandler(PayloadHandler): ...@@ -76,6 +76,9 @@ class ModeHandler(PayloadHandler):
setVal, setVal,
] ]
) )
if isinstance(self.buttonDict[key], OkSendButtonWidget):
message.append("change mode to " + str(mode))
command.append(["SET_MODE", mode.replace("/", "_").replace("-", "_")])
# create a signal emitting message, command, handler identifier - in nativeui connect to a popup widget # create a signal emitting message, command, handler identifier - in nativeui connect to a popup widget
# command sending should occur in handler # command sending should occur in handler
self.commandList = command self.commandList = command
...@@ -113,6 +116,20 @@ class ModeHandler(PayloadHandler): ...@@ -113,6 +116,20 @@ class ModeHandler(PayloadHandler):
self.commandSent() self.commandSent()
return 0 return 0
def handle_cancel_pressed(self, buttonMode):
for widget in self.spinDict:
if buttonMode in widget:
self.spinDict[widget].manuallyUpdated = False
if buttonMode == self.NativeUI.currentMode:
print('modes match ')
for widget in self.mainSpinDict:
self.mainSpinDict[widget].manuallyUpdated = False
else:
print('do nothing in clinical')
self.active_payload()
self.refresh_button_colour()
self.refresh_main_button_colour()
def commandSent(self): def commandSent(self):
self.commandList = [] self.commandList = []
for widget in self.spinDict: for widget in self.spinDict:
...@@ -127,7 +144,6 @@ class ModeHandler(PayloadHandler): ...@@ -127,7 +144,6 @@ class ModeHandler(PayloadHandler):
self.refresh_main_button_colour() self.refresh_main_button_colour()
def handle_manual_change(self, changed_spin_key): def handle_manual_change(self, changed_spin_key):
print('handle manual change')
self.active_payload() self.active_payload()
self.refresh_button_colour() self.refresh_button_colour()
self.refresh_main_button_colour() self.refresh_main_button_colour()
......
...@@ -185,6 +185,7 @@ class Layout: ...@@ -185,6 +185,7 @@ class Layout:
self.widgets.personal_display, self.widgets.personal_display,
self.widgets.localisation_button, self.widgets.localisation_button,
self.widgets.battery_display, self.widgets.battery_display,
self.widgets.lock_button,
] ]
) )
) )
...@@ -335,11 +336,11 @@ class Layout: ...@@ -335,11 +336,11 @@ class Layout:
page_settings = SwitchableStackWidget( page_settings = SwitchableStackWidget(
self.NativeUI.colors, self.NativeUI.colors,
self.NativeUI.text, self.NativeUI.text,
[self.layout_settings_expert(), tab_charts, tab_info], [tab_charts, tab_info,self.layout_settings_expert(),],
[ [
"button_label_settings_expert",
"button_label_settings_charts", "button_label_settings_charts",
"button_label_settings_info", "button_label_settings_info",
"button_label_settings_expert",
], ],
) )
page_settings.setFont(self.NativeUI.text_font) page_settings.setFont(self.NativeUI.text_font)
...@@ -697,11 +698,11 @@ class Layout: ...@@ -697,11 +698,11 @@ class Layout:
vlayout.addLayout(hButtonLayout) vlayout.addLayout(hButtonLayout)
passlock_stack = QtWidgets.QStackedWidget() #passlock_stack = #QtWidgets.QStackedWidget()
passlock_stack.addWidget(self.NativeUI.widgets.expert_password_widget) self.NativeUI.widgets.expert_passlock_stack.addWidget(self.NativeUI.widgets.expert_password_widget)
passlock_stack.addWidget(expert_tab) self.NativeUI.widgets.expert_passlock_stack.addWidget(expert_tab)
# break this here #break this here
return passlock_stack # expert_tab return self.NativeUI.widgets.expert_passlock_stack#expert_tab
def layout_main_spin_buttons(self) -> QtWidgets.QWidget: def layout_main_spin_buttons(self) -> QtWidgets.QWidget:
hlayout = QtWidgets.QHBoxLayout() hlayout = QtWidgets.QHBoxLayout()
......
...@@ -47,7 +47,7 @@ from widget_library.info_display_widgets import ( ...@@ -47,7 +47,7 @@ from widget_library.info_display_widgets import (
# from widget_library.tab_charts import TabChart # from widget_library.tab_charts import TabChart
from widget_library.chart_buttons_widget import ChartButtonsWidget from widget_library.chart_buttons_widget import ChartButtonsWidget
from widget_library.page_buttons_widget import PageButtonsWidget from widget_library.page_buttons_widget import PageButtonsWidget, PageButton
from widget_library.personal_display_widget import PersonalDisplayWidget from widget_library.personal_display_widget import PersonalDisplayWidget
from widget_library.plot_widget import ( from widget_library.plot_widget import (
ChartsPlotWidget, ChartsPlotWidget,
...@@ -136,10 +136,14 @@ class Widgets: ...@@ -136,10 +136,14 @@ class Widgets:
self.ventilator_start_stop_buttons_widget = VentilatorStartStopButtonsWidget( self.ventilator_start_stop_buttons_widget = VentilatorStartStopButtonsWidget(
NativeUI NativeUI
) )
self.lock_button = PageButton(
NativeUI,
"",
signal_value="lock_screen",
icon=NativeUI.icons["lock_screen"],
)
# Main Page Widgets # Main Page Widgets
# self.spin_buttons = SpinButtonsWidget(NativeUI)
# self.add_handled_widget(SpinButtonsWidget(NativeUI), 'spin_buttons', NativeUI.mode_handler)
self.history_buttons = HistoryButtonsWidget(NativeUI) self.history_buttons = HistoryButtonsWidget(NativeUI)
self.normal_plots = TimePlotsWidget(NativeUI) self.normal_plots = TimePlotsWidget(NativeUI)
self.detailed_plots = TimePlotsWidget(NativeUI) self.detailed_plots = TimePlotsWidget(NativeUI)
...@@ -209,7 +213,6 @@ class Widgets: ...@@ -209,7 +213,6 @@ class Widgets:
for setting in modeDict["settings"]: for setting in modeDict["settings"]:
if setting[0] in modeDict["mainPageSettings"]: if setting[0] in modeDict["mainPageSettings"]:
attrName = "CURRENT_" + setting[2] attrName = "CURRENT_" + setting[2]
#setting[3] = setting[3].replace('SET_TARGET_', 'SET_TARGET_CURRENT')
self.add_handled_widget( self.add_handled_widget(
SpinButton(NativeUI, NativeUI.typeValPopupNum,setting), attrName, NativeUI.mode_handler SpinButton(NativeUI, NativeUI.typeValPopupNum,setting), attrName, NativeUI.mode_handler
) )
...@@ -330,12 +333,10 @@ class Widgets: ...@@ -330,12 +333,10 @@ class Widgets:
) )
##### Settings Tab: Expert and Charts tabs ##### Settings Tab: Expert and Charts tabs
self.add_widget(AbstractTypeValPopup(NativeUI,'numeric'), 'expert_password_widget') self.add_widget(QStackedWidget(),'expert_passlock_stack')
self.add_handled_widget(AbstractTypeValPopup(NativeUI,'alpha'), 'expert_password_widget', NativeUI.expert_handler)
# Expert Tab # Expert Tab
# self.expert_confirm_popup = SetConfirmPopup(NativeUI)
# NativeUI.expert_handler = ExpertHandler(NativeUI, self.expert_confirm_popup)
print(os.listdir())
with open("NativeUI/configs/expert_config.json") as json_file: with open("NativeUI/configs/expert_config.json") as json_file:
controlDict = json.load(json_file) controlDict = json.load(json_file)
...@@ -378,6 +379,7 @@ class Widgets: ...@@ -378,6 +379,7 @@ class Widgets:
return 0 return 0
def add_handled_widget(self, widget, name, handler) -> int: def add_handled_widget(self, widget, name, handler) -> int:
"""Add a widget to Widgets and pass it into a handler"""
setattr(self, name, widget) setattr(self, name, widget)
handler.add_widget(widget, name) handler.add_widget(widget, name)
return 0 return 0
......
from global_widgets.global_spinbox import labelledSpin from global_widgets.global_spinbox import labelledSpin
from widget_library.ok_cancel_buttons_widget import OkButtonWidget, CancelButtonWidget, OkSendButtonWidget from widget_library.ok_cancel_buttons_widget import OkButtonWidget, CancelButtonWidget, OkSendButtonWidget
from global_widgets.global_typeval_popup import AbstractTypeValPopup
from PySide2 import QtWidgets, QtGui, QtCore from PySide2 import QtWidgets, QtGui, QtCore
from handler_library.handler import PayloadHandler from handler_library.handler import PayloadHandler
...@@ -29,6 +30,8 @@ class ExpertHandler(PayloadHandler): # chose QWidget over QDialog family becaus ...@@ -29,6 +30,8 @@ class ExpertHandler(PayloadHandler): # chose QWidget over QDialog family becaus
self.spinDict[key] = widget self.spinDict[key] = widget
if isinstance(widget, OkButtonWidget) or isinstance(widget, CancelButtonWidget) or isinstance(widget,OkSendButtonWidget): if isinstance(widget, OkButtonWidget) or isinstance(widget, CancelButtonWidget) or isinstance(widget,OkSendButtonWidget):
self.buttonDict[key] = widget self.buttonDict[key] = widget
if isinstance(widget, AbstractTypeValPopup):
self.password_lock = widget
def active_payload(self, *args) -> int: def active_payload(self, *args) -> int:
......
...@@ -36,10 +36,7 @@ class PageButtonsWidget(QtWidgets.QWidget): ...@@ -36,10 +36,7 @@ class PageButtonsWidget(QtWidgets.QWidget):
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
self.main_button = PageButton( self.main_button = PageButton(
NativeUI, "", signal_value="main_page", icon=NativeUI.icons["button_main_page"]
"",
signal_value="main_page",
icon=NativeUI.icons["button_main_page"],
) )
self.alarms_button = PageButton( self.alarms_button = PageButton(
"", signal_value="alarms_page", icon=NativeUI.icons["button_alarms_page"] "", signal_value="alarms_page", icon=NativeUI.icons["button_alarms_page"]
...@@ -64,17 +61,20 @@ class PageButtonsWidget(QtWidgets.QWidget): ...@@ -64,17 +61,20 @@ class PageButtonsWidget(QtWidgets.QWidget):
"QPushButton{" "QPushButton{"
" border:none" " border:none"
"}" "}"
"QPushButton:disabled{" "QPushButton[selected='0']{"
" background-color:" " background-color:"
+ NativeUI.colors["button_background_disabled"].name() + NativeUI.colors["button_background_enabled"].name()
+ ";" + ";"
" border:none"
"}" "}"
"QPushButton:enabled{" "QPushButton[selected='1']{"
" background-color:" " background-color:"
+ NativeUI.colors["button_background_enabled"].name() + NativeUI.colors["button_background_highlight"].name()
+ ";"
"}"
"QPushButton:disabled{"
" background-color:"
+ NativeUI.colors["button_background_disabled"].name()
+ ";" + ";"
" border:none"
"}" "}"
) )
...@@ -82,19 +82,14 @@ class PageButtonsWidget(QtWidgets.QWidget): ...@@ -82,19 +82,14 @@ class PageButtonsWidget(QtWidgets.QWidget):
# set button appearance # set button appearance
button.setStyleSheet(stylesheet) button.setStyleSheet(stylesheet)
button.setIconColor(NativeUI.colors["page_foreground"]) button.setIconColor(NativeUI.colors["page_foreground"])
button.pressed.connect(lambda i=button: self.set_pressed(i))
layout.addWidget(button) layout.addWidget(button)
self.setLayout(layout) self.setLayout(layout)
self.set_pressed(self.buttons[0])
# Connect the buttons so that pressing one enables all of the others def set_pressed(self, button_pressed) -> int:
for pressed_button in self.buttons:
for unpressed_button in self.buttons:
if pressed_button == unpressed_button:
continue
pressed_button.pressed.connect(unpressed_button.enable)
def set_pressed(self, pressed: str) -> int:
""" """
Set the specified buttons to enabled (unpressed) or disabled (pressed) states. Set the specified buttons to enabled (unpressed) or disabled (pressed) states.
By default, all buttons in self.buttons will be made enabled except those in the By default, all buttons in self.buttons will be made enabled except those in the
...@@ -102,13 +97,13 @@ class PageButtonsWidget(QtWidgets.QWidget): ...@@ -102,13 +97,13 @@ class PageButtonsWidget(QtWidgets.QWidget):
pressed can be str or list of str. pressed can be str or list of str.
""" """
if isinstance(pressed, str):
pressed = [pressed]
for button in self.buttons: for button in self.buttons:
button.setEnabled(True) if button == button_pressed:
for button_name in pressed: button.setProperty("selected", "1")
button = getattr(self, button_name) else:
button.setEnabled(False) button.setProperty("selected", "0")
button.style().unpolish(button)
button.style().polish(button)
return 0 return 0
def set_size(self, x: int, y: int, spacing: int = 10) -> int: def set_size(self, x: int, y: int, spacing: int = 10) -> int:
...@@ -165,9 +160,7 @@ class PageButtonsWidget(QtWidgets.QWidget): ...@@ -165,9 +160,7 @@ class PageButtonsWidget(QtWidgets.QWidget):
class PageButton(QtWidgets.QPushButton): class PageButton(QtWidgets.QPushButton):
PageButtonPressed = Signal(str) PageButtonPressed = Signal(str)
def __init__( def __init__(self, *args, signal_value: str = None, icon: str = None, **kwargs):
self, NativeUI, *args, signal_value: str = None, icon: str = None, **kwargs
):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.__signal_value = signal_value self.__signal_value = signal_value
self.__icon_path = icon self.__icon_path = icon
...@@ -186,15 +179,12 @@ class PageButton(QtWidgets.QPushButton): ...@@ -186,15 +179,12 @@ class PageButton(QtWidgets.QPushButton):
self.setIcon(QtGui.QIcon(pixmap)) self.setIcon(QtGui.QIcon(pixmap))
return 0 return 0
@Slot()
def enable(self):
self.setEnabled(True)
return 0
def on_press(self): def on_press(self):
""" """
When the button is pressed, disable it and emit the PageButtonPressed signal. When the button is pressed, disable it and emit the PageButtonPressed signal.
""" """
self.setEnabled(False)
self.PageButtonPressed.emit(self.__signal_value) self.PageButtonPressed.emit(self.__signal_value)
return 0 return 0
def localise_text(self, *args, **kwargs) -> int:
pass
...@@ -88,21 +88,21 @@ class TimePlotsWidget(QtWidgets.QWidget): ...@@ -88,21 +88,21 @@ class TimePlotsWidget(QtWidgets.QWidget):
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_pressure"], NativeUI.text["plot_line_label_pressure"],
NativeUI.colors["pressure_plot"].name(), NativeUI.colors["plot_pressure"].name(),
) )
self.flow_line = self.plot( self.flow_line = self.plot(
self.flow_plot, self.flow_plot,
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_flow"], NativeUI.text["plot_line_label_flow"],
NativeUI.colors["flow_plot"].name(), NativeUI.colors["plot_flow"].name(),
) )
self.volume_line = self.plot( self.volume_line = self.plot(
self.volume_plot, self.volume_plot,
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_volume"], NativeUI.text["plot_line_label_volume"],
NativeUI.colors["volume_plot"].name(), NativeUI.colors["plot_volume"].name(),
) )
self.setLayout(layout) self.setLayout(layout)
...@@ -227,21 +227,21 @@ class CirclePlotsWidget(QtWidgets.QWidget): ...@@ -227,21 +227,21 @@ class CirclePlotsWidget(QtWidgets.QWidget):
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_pressure_flow"], NativeUI.text["plot_line_label_pressure_flow"],
NativeUI.colors["pressure_flow_plot"].name(), NativeUI.colors["plot_pressure_flow"].name(),
) )
self.flow_volume_line = self.plot( self.flow_volume_line = self.plot(
self.flow_volume_plot, self.flow_volume_plot,
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_flow_volume"], NativeUI.text["plot_line_label_flow_volume"],
NativeUI.colors["flow_volume_plot"].name(), NativeUI.colors["plot_flow_volume"].name(),
) )
self.volume_pressure_line = self.plot( self.volume_pressure_line = self.plot(
self.volume_pressure_plot, self.volume_pressure_plot,
[0, 0], [0, 0],
[0, 0], [0, 0],
NativeUI.text["plot_line_label_volume_pressure"], NativeUI.text["plot_line_label_volume_pressure"],
NativeUI.colors["volume_pressure_plot"].name(), NativeUI.colors["plot_volume_pressure"].name(),
) )
self.setLayout(layout) self.setLayout(layout)
...@@ -332,7 +332,7 @@ class ChartsPlotWidget(QtWidgets.QWidget): ...@@ -332,7 +332,7 @@ class ChartsPlotWidget(QtWidgets.QWidget):
} }
# Store the colors of the lines # Store the colors of the lines
self.colors = {"pressure": colors["pressure_plot"], "flow": colors["flow_plot"]} self.colors = {"pressure": colors["plot_pressure"], "flow": colors["plot_flow"]}
self.graph_widget.setContentsMargins(0.0, 0.0, 0.0, 0.0) self.graph_widget.setContentsMargins(0.0, 0.0, 0.0, 0.0)
self.graph_widget.setBackground(colors["page_background"]) self.graph_widget.setBackground(colors["page_background"])
......
...@@ -140,7 +140,6 @@ class SpinButton(QtWidgets.QFrame): ...@@ -140,7 +140,6 @@ class SpinButton(QtWidgets.QFrame):
def manualChanged(self): def manualChanged(self):
print("manually changed" + self.label.text())
"""Called when user manually makes a change. Stops value from updating and changes colour""" """Called when user manually makes a change. Stops value from updating and changes colour"""
self.manuallyUpdated = True self.manuallyUpdated = True
self.setTextColour(2) self.setTextColour(2)
......
...@@ -125,7 +125,12 @@ class SelectorButtonWidget(QtWidgets.QPushButton): ...@@ -125,7 +125,12 @@ class SelectorButtonWidget(QtWidgets.QPushButton):
" border:none" " border:none"
"}" "}"
"QPushButton[selected='1']{" "QPushButton[selected='1']{"
" color: " + colors["button_foreground_disabled"].name() + ";" " color: " + colors["button_foreground_highlight"].name() + ";"
" background-color:" + colors["button_background_highlight"].name() + ";"
" border:none"
"}"
"QPushButton:disabled{"
" color:" + colors["button_foreground_disabled"].name() + ";"
" background-color:" + colors["button_background_disabled"].name() + ";" " background-color:" + colors["button_background_disabled"].name() + ";"
" border:none" " border:none"
"}" "}"
......
...@@ -60,6 +60,12 @@ class CMD_TYPE(Enum): ...@@ -60,6 +60,12 @@ class CMD_TYPE(Enum):
SET_PERSONAL = 15 SET_PERSONAL = 15
GET_THRESHOLD_MIN = 16 GET_THRESHOLD_MIN = 16
GET_THRESHOLD_MAX = 17 GET_THRESHOLD_MAX = 17
TEST_AUDIO_ALARM = 18
SKIP_NEXT_CALIBRATION = 19
DO_CALIBRATION = 20
MUTE_ALARM = 21
RESET_ALARM = 22
@unique @unique
...@@ -184,6 +190,14 @@ class ALARM_CODES(Enum): ...@@ -184,6 +190,14 @@ class ALARM_CODES(Enum):
O2_FAIL = 23 # HP O2_FAIL = 23 # HP
PRESSURE_SENSOR_FAULT = 24 # HP PRESSURE_SENSOR_FAULT = 24 # HP
ARDUINO_FAIL = 25 # HP ARDUINO_FAIL = 25 # HP
ALARM_TEST = 26 # HP
HIGH_VME = 27 # MP
LOW_VME = 28 # MP
HIGH_VMI = 29 # MP
LOW_VMI = 30 # MP
EXTENDED_HIGH_PRESSURE = 31 # HP
ALARMS_COUNT = 32
class CMD_MAP(Enum): class CMD_MAP(Enum):
...@@ -240,6 +254,9 @@ class PAYLOAD_TYPE(IntEnum): ...@@ -240,6 +254,9 @@ class PAYLOAD_TYPE(IntEnum):
BATTERY = 11 BATTERY = 11
LOOP_STATUS = 12 LOOP_STATUS = 12
PERSONAL = 13 PERSONAL = 13
ALARM_MUTE = 14
BAD_THRESHOLD = 15
class HEVVersionError(Exception): class HEVVersionError(Exception):
......
#!/usr/bin/env python3 #!/usr/bin/env python3
# © Copyright CERN, Riga Technical University and University of Liverpool 2020. # © Copyright CERN, Riga Technical University and University of Liverpool 2020.
# All rights not expressly granted are reserved. # All rights not expressly granted are reserved.
# #
# This file is part of hev-sw. # This file is part of hev-sw.
# #
# hev-sw is free software: you can redistribute it and/or modify it under # hev-sw is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public Licence as published by the Free # the terms of the GNU General Public Licence as published by the Free
# Software Foundation, either version 3 of the Licence, or (at your option) # Software Foundation, either version 3 of the Licence, or (at your option)
# any later version. # any later version.
# #
# hev-sw is distributed in the hope that it will be useful, but WITHOUT # hev-sw is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licence # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licence
# for more details. # for more details.
# #
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with hev-sw. If not, see <http://www.gnu.org/licenses/>. # with hev-sw. If not, see <http://www.gnu.org/licenses/>.
# #
# The authors would like to acknowledge the much appreciated support # The authors would like to acknowledge the much appreciated support
# of all those involved with the High Energy Ventilator project # of all those involved with the High Energy Ventilator project
# (https://hev.web.cern.ch/). # (https://hev.web.cern.ch/).
...@@ -40,21 +40,37 @@ from pathlib import Path ...@@ -40,21 +40,37 @@ from pathlib import Path
from hevtestdata import HEVTestData from hevtestdata import HEVTestData
from CommsLLI import CommsLLI from CommsLLI import CommsLLI
from BatteryLLI import BatteryLLI from BatteryLLI import BatteryLLI
from CommsCommon import PAYLOAD_TYPE, CMD_TYPE, CMD_GENERAL, CMD_SET_DURATION, VENTILATION_MODE, ALARM_TYPE, ALARM_CODES, CMD_MAP, CommandFormat, AlarmFormat, PersonalFormat from CommsCommon import (
PAYLOAD_TYPE,
CMD_TYPE,
CMD_GENERAL,
CMD_SET_DURATION,
VENTILATION_MODE,
ALARM_TYPE,
ALARM_CODES,
CMD_MAP,
CommandFormat,
AlarmFormat,
PersonalFormat,
)
from collections import deque from collections import deque
from serial.tools import list_ports from serial.tools import list_ports
from typing import List from typing import List
from struct import error as StructError from struct import error as StructError
import logging import logging
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s')
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s")
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
class HEVPacketError(Exception): class HEVPacketError(Exception):
pass pass
class HEVAlreadyRunning(Exception): class HEVAlreadyRunning(Exception):
pass pass
class HEVServer(object): class HEVServer(object):
def __init__(self, comms_lli, battery_lli): def __init__(self, comms_lli, battery_lli):
self._alarms = [] self._alarms = []
...@@ -89,16 +105,16 @@ class HEVServer(object): ...@@ -89,16 +105,16 @@ class HEVServer(object):
PAYLOAD_TYPE.ALARM, PAYLOAD_TYPE.ALARM,
PAYLOAD_TYPE.DEBUG, PAYLOAD_TYPE.DEBUG,
PAYLOAD_TYPE.IVT, PAYLOAD_TYPE.IVT,
#PAYLOAD_TYPE.LOGMSG, # PAYLOAD_TYPE.LOGMSG,
PAYLOAD_TYPE.PERSONAL, PAYLOAD_TYPE.PERSONAL,
PAYLOAD_TYPE.CMD PAYLOAD_TYPE.CMD,
] ]
if payload_type in whitelist: if payload_type in whitelist:
# fork data to broadcast threads # fork data to broadcast threads
for queue in self._broadcasts.values(): for queue in self._broadcasts.values():
self.push_to(queue, payload) self.push_to(queue, payload)
#if payload_type == PAYLOAD_TYPE.PERSONAL : print("PERSONAL") # if payload_type == PAYLOAD_TYPE.PERSONAL : print("PERSONAL")
elif payload_type in PAYLOAD_TYPE: elif payload_type in PAYLOAD_TYPE:
# valid payload but ignored # valid payload but ignored
pass pass
...@@ -106,14 +122,13 @@ class HEVServer(object): ...@@ -106,14 +122,13 @@ class HEVServer(object):
# invalid packet, don't throw exception just log and pop # invalid packet, don't throw exception just log and pop
logging.error(f"Received invalid packet, ignoring: {payload}") logging.error(f"Received invalid packet, ignoring: {payload}")
async def handle_battery(self) -> None: async def handle_battery(self) -> None:
while True: while True:
try: try:
# wait for a new battery state from the batterylli # wait for a new battery state from the batterylli
payload = await self._battery_lli.queue.get() payload = await self._battery_lli.queue.get()
logging.debug(f"Payload received: {payload}") logging.debug(f"Payload received: {payload}")
self._battery_lli.queue.task_done() # consume entry self._battery_lli.queue.task_done() # consume entry
if payload.getType() != PAYLOAD_TYPE.BATTERY: if payload.getType() != PAYLOAD_TYPE.BATTERY:
raise HEVPacketError("Battery state invalid") raise HEVPacketError("Battery state invalid")
...@@ -125,18 +140,19 @@ class HEVServer(object): ...@@ -125,18 +140,19 @@ class HEVServer(object):
self._comms_lli.writePayload(payload) self._comms_lli.writePayload(payload)
except HEVPacketError as e: except HEVPacketError as e:
logging.error(e) logging.error(e)
async def handle_request(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None: async def handle_request(
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
# listen for queries on the request socket # listen for queries on the request socket
data = await reader.readuntil(separator=b'\0') data = await reader.readuntil(separator=b"\0")
data = data[:-1] # snip off nullbyte data = data[:-1] # snip off nullbyte
request = json.loads(data.decode("utf-8")) request = json.loads(data.decode("utf-8"))
# logging # logging
addr = writer.get_extra_info("peername") addr = writer.get_extra_info("peername")
logging.info(f"Answering request from {addr}") logging.info(f"Answering request from {addr}")
try: try:
reqtype = request["type"] reqtype = request["type"]
if reqtype == "CMD": if reqtype == "CMD":
...@@ -144,12 +160,14 @@ class HEVServer(object): ...@@ -144,12 +160,14 @@ class HEVServer(object):
reqcmdtype = request["cmdtype"] reqcmdtype = request["cmdtype"]
reqparam = request["param"] if request["param"] is not None else 0 reqparam = request["param"] if request["param"] is not None else 0
command = CommandFormat(cmd_type=CMD_TYPE[reqcmdtype].value, command = CommandFormat(
cmd_code=CMD_MAP[reqcmdtype].value[reqcmd].value, cmd_type=CMD_TYPE[reqcmdtype].value,
param=reqparam) cmd_code=CMD_MAP[reqcmdtype].value[reqcmd].value,
param=reqparam,
)
#print('***sending cmd ') # print('***sending cmd ')
#print(command) # print(command)
self._comms_lli.writePayload(command) self._comms_lli.writePayload(command)
# processed and sent to controller, send ack to GUI since it's in enum # processed and sent to controller, send ack to GUI since it's in enum
...@@ -164,7 +182,7 @@ class HEVServer(object): ...@@ -164,7 +182,7 @@ class HEVServer(object):
elif reqtype == "CYCLE": elif reqtype == "CYCLE":
# ignore for the minute # ignore for the minute
pass pass
#elif reqtype == "LOGSMG": # elif reqtype == "LOGSMG":
# # ignore for the minute # # ignore for the minute
# pass # pass
elif reqtype == "TARGET": elif reqtype == "TARGET":
...@@ -172,13 +190,20 @@ class HEVServer(object): ...@@ -172,13 +190,20 @@ class HEVServer(object):
pass pass
elif reqtype == "PERSONAL": elif reqtype == "PERSONAL":
# ignore for the minute # ignore for the minute
name = request["name"].encode() name = request["name"].encode()
patient_id = request["patient_id"].encode() patient_id = request["patient_id"].encode()
age = int(request["age"]) age = int(request["age"])
sex = request["sex"].encode() sex = request["sex"].encode()
height = int(request["height"]) height = int(request["height"])
weight = int(request["weight"]) weight = int(request["weight"])
pfmt = PersonalFormat(name=name, patient_id=patient_id, age=age, sex=sex, height=height, weight=weight) pfmt = PersonalFormat(
name=name,
patient_id=patient_id,
age=age,
sex=sex,
height=height,
weight=weight,
)
self._comms_lli.writePayload(pfmt) self._comms_lli.writePayload(pfmt)
payload = {"type": "ack"} payload = {"type": "ack"}
pass pass
...@@ -194,9 +219,11 @@ class HEVServer(object): ...@@ -194,9 +219,11 @@ class HEVServer(object):
reqalarm_code = ALARM_CODES[request["alarm_code"]] reqalarm_code = ALARM_CODES[request["alarm_code"]]
reqparam = request["param"] if request["param"] is not None else 0 reqparam = request["param"] if request["param"] is not None else 0
alarm_to_ack = AlarmFormat(alarm_type=ALARM_TYPE[reqalarm_type], alarm_to_ack = AlarmFormat(
alarm_code=reqalarm_code, alarm_type=ALARM_TYPE[reqalarm_type],
param=reqparam) alarm_code=reqalarm_code,
param=reqparam,
)
try: try:
# delete alarm if it exists # delete alarm if it exists
with self._dblock: with self._dblock:
...@@ -205,7 +232,9 @@ class HEVServer(object): ...@@ -205,7 +232,9 @@ class HEVServer(object):
self._alarms.remove(alarm) self._alarms.remove(alarm)
payload = {"type": "ack"} payload = {"type": "ack"}
except NameError as e: except NameError as e:
raise HEVPacketError(f"Alarm could not be removed. May have been removed already. {e}") raise HEVPacketError(
f"Alarm could not be removed. May have been removed already. {e}"
)
else: else:
raise HEVPacketError(f"Invalid request type") raise HEVPacketError(f"Invalid request type")
except (NameError, KeyError, HEVPacketError, StructError) as e: except (NameError, KeyError, HEVPacketError, StructError) as e:
...@@ -217,18 +246,20 @@ class HEVServer(object): ...@@ -217,18 +246,20 @@ class HEVServer(object):
exit(1) exit(1)
# send reply and close connection # send reply and close connection
packet = json.dumps(payload).encode() + b'\0' packet = json.dumps(payload).encode() + b"\0"
writer.write(packet) writer.write(packet)
await writer.drain() await writer.drain()
writer.close() writer.close()
async def handle_broadcast(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None: async def handle_broadcast(
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
# log address # log address
addr = writer.get_extra_info("peername") addr = writer.get_extra_info("peername")
logging.info(f"Broadcasting to {addr!r}") logging.info(f"Broadcasting to {addr!r}")
bindex = str(addr[1]) bindex = str(addr[1])
self._broadcasts[bindex] = asyncio.Queue(maxsize=16) # append new queue self._broadcasts[bindex] = asyncio.Queue(maxsize=16) # append new queue
while self._broadcasting: while self._broadcasting:
# wait for data from queue # wait for data from queue
...@@ -249,10 +280,14 @@ class HEVServer(object): ...@@ -249,10 +280,14 @@ class HEVServer(object):
broadcast_packet[data_type] = payload.getDict() broadcast_packet[data_type] = payload.getDict()
broadcast_packet["alarms"] = [alarm.getDict() for alarm in alarms] if alarms is not None else [] broadcast_packet["alarms"] = (
[alarm.getDict() for alarm in alarms] if alarms is not None else []
)
self._broadcasts[bindex].task_done() self._broadcasts[bindex].task_done()
logging.info(f"Send data for timestamp: {broadcast_packet[data_type]['timestamp']}") logging.info(
f"Send data for timestamp: {broadcast_packet[data_type]['timestamp']}"
)
logging.debug(f"Send: {json.dumps(broadcast_packet,indent=4)}") logging.debug(f"Send: {json.dumps(broadcast_packet,indent=4)}")
try: try:
...@@ -269,8 +304,7 @@ class HEVServer(object): ...@@ -269,8 +304,7 @@ class HEVServer(object):
del self._broadcasts[bindex] del self._broadcasts[bindex]
async def serve_request(self, ip: str, port: int) -> None: async def serve_request(self, ip: str, port: int) -> None:
server = await asyncio.start_server( server = await asyncio.start_server(self.handle_request, ip, port)
self.handle_request, ip, port)
# get address for log # get address for log
addr = server.sockets[0].getsockname() addr = server.sockets[0].getsockname()
...@@ -280,8 +314,7 @@ class HEVServer(object): ...@@ -280,8 +314,7 @@ class HEVServer(object):
await server.serve_forever() await server.serve_forever()
async def serve_broadcast(self, ip: str, port: int) -> None: async def serve_broadcast(self, ip: str, port: int) -> None:
server = await asyncio.start_server( server = await asyncio.start_server(self.handle_broadcast, ip, port)
self.handle_broadcast, ip, port)
# get address for log # get address for log
addr = server.sockets[0].getsockname() addr = server.sockets[0].getsockname()
...@@ -291,16 +324,17 @@ class HEVServer(object): ...@@ -291,16 +324,17 @@ class HEVServer(object):
await server.serve_forever() await server.serve_forever()
async def main(self) -> None: async def main(self) -> None:
self._datavalid = threading.Event() # initially false self._datavalid = threading.Event() # initially false
LOCALHOST = "127.0.0.1" LOCALHOST = "127.0.0.1"
b1 = self.serve_broadcast(LOCALHOST, 54320) # WebUI broadcast b1 = self.serve_broadcast(LOCALHOST, 54320) # WebUI broadcast
r1 = self.serve_request(LOCALHOST, 54321) # joint request socket r1 = self.serve_request(LOCALHOST, 54321) # joint request socket
b2 = self.serve_broadcast(LOCALHOST, 54322) # NativeUI broadcast b2 = self.serve_broadcast(LOCALHOST, 54322) # NativeUI broadcast
battery = self.handle_battery() # Battery status battery = self.handle_battery() # Battery status
poll = self.polling() # Battery status poll = self.polling() # Battery status
tasks = [b1, r1, b2, poll, battery] tasks = [b1, r1, b2, poll, battery]
await asyncio.gather(*tasks, return_exceptions=True) await asyncio.gather(*tasks, return_exceptions=True)
def getArduinoPort(): def getArduinoPort():
# get arduino serial port # get arduino serial port
port_device = None port_device = None
...@@ -310,9 +344,9 @@ def getArduinoPort(): ...@@ -310,9 +344,9 @@ def getArduinoPort():
vidpid = f"{ port.vid:04x}:{port.pid:04x}".upper() vidpid = f"{ port.vid:04x}:{port.pid:04x}".upper()
logging.debug(vidpid) logging.debug(vidpid)
if port.manufacturer and "ARDUINO" in port.manufacturer.upper(): if port.manufacturer and "ARDUINO" in port.manufacturer.upper():
port_device = port.device port_device = port.device
elif vidpid == "10C4:EA60" : elif vidpid == "10C4:EA60":
port_device = port.device port_device = port.device
if port_device is None: if port_device is None:
logging.critical(f"Arduino disconnected") logging.critical(f"Arduino disconnected")
exit(1) exit(1)
...@@ -328,17 +362,32 @@ async def arduinoConnected(): ...@@ -328,17 +362,32 @@ async def arduinoConnected():
if __name__ == "__main__": if __name__ == "__main__":
tasks = [] # asyncio tasks tasks = [] # asyncio tasks
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
try: try:
#parser to allow us to pass arguments to hevserver # parser to allow us to pass arguments to hevserver
parser = argparse.ArgumentParser(description='Arguments to run hevserver') parser = argparse.ArgumentParser(description="Arguments to run hevserver")
parser.add_argument('-i', '--inputFile', type=str, default = '', help='Load data from file') parser.add_argument(
parser.add_argument('-d', '--debug', action='count', default=0, help='Show debug output') "-i", "--inputFile", type=str, default="", help="Load data from file"
parser.add_argument('--use-test-data', action='store_true', help='Use test data source') )
parser.add_argument('--use-dump-data', action='store_true', help='Use dump data source') parser.add_argument(
parser.add_argument('--dump', type=int, default=0, help='Dump NUM raw data packets to file') "-d", "--debug", action="count", default=0, help="Show debug output"
parser.add_argument('-o', '--dumpfile', type=str, default = '', help='File to dump to') )
parser.add_argument(
"--use-test-data", action="store_true", help="Use test data source"
)
parser.add_argument(
"--use-dump-data", action="store_true", help="Use dump data source"
)
parser.add_argument(
"--mcu-tty", type=str, default="", help="Specify tty serial device for MCU"
)
parser.add_argument(
"--dump", type=int, default=0, help="Dump NUM raw data packets to file"
)
parser.add_argument(
"-o", "--dumpfile", type=str, default="", help="File to dump to"
)
args = parser.parse_args() args = parser.parse_args()
if args.debug == 0: if args.debug == 0:
logging.getLogger().setLevel(logging.WARNING) logging.getLogger().setLevel(logging.WARNING)
...@@ -346,7 +395,7 @@ if __name__ == "__main__": ...@@ -346,7 +395,7 @@ if __name__ == "__main__":
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
else: else:
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
# check if hevserver is running # check if hevserver is running
pidfile = "/dev/shm/hevpid" pidfile = "/dev/shm/hevpid"
mypid = os.getpid() mypid = os.getpid()
...@@ -358,16 +407,18 @@ if __name__ == "__main__": ...@@ -358,16 +407,18 @@ if __name__ == "__main__":
pass pass
else: else:
if psutil.pid_exists(pid): if psutil.pid_exists(pid):
raise HEVAlreadyRunning(f"hevserver is already running. To kill it run:\n $ kill {pid}") raise HEVAlreadyRunning(
f"hevserver is already running. To kill it run:\n $ kill {pid}"
with open(pidfile, 'w') as f: )
with open(pidfile, "w") as f:
f.write(str(mypid)) f.write(str(mypid))
if args.use_test_data: if args.use_test_data:
comms_lli = HEVTestData() comms_lli = HEVTestData()
logging.info(f"Using test data source") logging.info(f"Using test data source")
elif args.inputFile != '': elif args.inputFile != "":
if args.inputFile[-1-3:] == '.txt': if args.inputFile[-1 - 3 :] == ".txt":
# just ignore actual filename and read from both valid inputfiles # just ignore actual filename and read from both valid inputfiles
comms_lli = hevfromtxt.hevfromtxt() comms_lli = hevfromtxt.hevfromtxt()
else: else:
...@@ -376,7 +427,12 @@ if __name__ == "__main__": ...@@ -376,7 +427,12 @@ if __name__ == "__main__":
# initialise low level interface # initialise low level interface
try: try:
if args.use_dump_data: if args.use_dump_data:
port_device = '/dev/shm/ttyEMU0' port_device = "/dev/shm/ttyEMU0"
elif args.mcu_tty is not "":
if not os.path.exists(args.mcu_tty):
logging.critical("MCU tty does not exist")
exit(1)
port_device = args.mcu_tty
else: else:
port_device = getArduinoPort() port_device = getArduinoPort()
connected = arduinoConnected() connected = arduinoConnected()
...@@ -385,14 +441,14 @@ if __name__ == "__main__": ...@@ -385,14 +441,14 @@ if __name__ == "__main__":
if args.dump == 0: if args.dump == 0:
comms_lli = CommsLLI(loop) comms_lli = CommsLLI(loop)
elif args.dump > 0: elif args.dump > 0:
if args.dumpfile == '': if args.dumpfile == "":
logging.critical("No dump file specified") logging.critical("No dump file specified")
raise KeyboardInterrupt # fake ctrl+c raise KeyboardInterrupt # fake ctrl+c
logging.warning(f"Dumping {args.dump} packets to {args.dumpfile}") logging.warning(f"Dumping {args.dump} packets to {args.dumpfile}")
comms_lli = CommsLLI(loop, file=args.dumpfile, number=args.dump) comms_lli = CommsLLI(loop, file=args.dumpfile, number=args.dump)
else: else:
logging.critical("Invalid number of packets to dump") logging.critical("Invalid number of packets to dump")
raise KeyboardInterrupt # fake ctrl+c raise KeyboardInterrupt # fake ctrl+c
comms = comms_lli.main(port_device, 115200) comms = comms_lli.main(port_device, 115200)
tasks.append(comms) tasks.append(comms)
logging.info(f"Serving data from device {port_device}") logging.info(f"Serving data from device {port_device}")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment