Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/G9_Driver #16

Draft
wants to merge 122 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
32b18e5
seeing if i can get the same widget sizes to work
mark11778 Sep 7, 2024
7997e58
working on understanding how the tkinter library works
mark11778 Sep 7, 2024
002b5d6
works
mark11778 Sep 8, 2024
561bbe2
added comments and got rid of old code
mark11778 Sep 8, 2024
f3daf3a
pulled and handled merge conflict on develop
mark11778 Sep 8, 2024
8fa29be
push1
Sep 13, 2024
c9f3b4d
rough write up for G9 Driver
mark11778 Sep 13, 2024
aa49717
more edits
mark11778 Sep 13, 2024
452afc0
commiting before leaving
mark11778 Sep 13, 2024
bb37644
made a few chnages to g9_driver.py
arundhatisingh17 Sep 20, 2024
49d6064
made a few changes
arundhatisingh17 Sep 20, 2024
3771c35
looking into what will be needed for the frontend to work
mark11778 Sep 21, 2024
fa44fb7
adding another indicator cause i think red is more clear on what it …
mark11778 Sep 21, 2024
97fab6b
Merge branch 'feature/G9Driversim' into feature/interlocks_frontend
mark11778 Sep 21, 2024
c1c28d8
made some small changes to interlocks.py
mark11778 Sep 21, 2024
7646f86
added alot of functions to parse and form input/output
mark11778 Oct 1, 2024
e7bfd1a
fixed indice values
Oct 2, 2024
de20435
getting SITDF, OCTD, and SODTF
Oct 2, 2024
91691d9
raise error for OCTD case
Oct 2, 2024
d0b11a2
Retrieved SOTDF readings
Oct 4, 2024
6fb21c9
minor edits
Oct 4, 2024
02fc2d4
small changes
arundhatisingh17 Oct 5, 2024
ab4d7ee
small change
arundhatisingh17 Oct 6, 2024
fa7b253
clarified acronyms
Oct 8, 2024
2fbf13b
resolved optional and reserved data
Oct 8, 2024
f3014a0
added test file
Oct 9, 2024
044a023
g9_backend handle_errors
arundhatisingh17 Oct 11, 2024
c211c92
error handling, highlighted frames
arundhatisingh17 Oct 11, 2024
8cafe31
added logger
arundhatisingh17 Oct 11, 2024
1014f21
added logger
arundhatisingh17 Oct 11, 2024
eebcf19
testing functions in g9 driver
mark11778 Oct 11, 2024
2ca5cdc
committing
mark11778 Oct 11, 2024
b5e8b2b
temp changes
arundhatisingh17 Oct 11, 2024
f90e899
minor change
arundhatisingh17 Oct 11, 2024
68096dd
updating tests
mark11778 Oct 11, 2024
afc011a
working to see if the driver file works
mark11778 Oct 12, 2024
44057e9
updated g9_driver
mark11778 Oct 13, 2024
dbe6672
commiting to switch branch
mark11778 Oct 13, 2024
72fe1c6
some how there was not a gitignore on this branched, had to fix to ma…
mark11778 Oct 13, 2024
cefa251
merged in frontend features, along with removing the usr dir from bei…
mark11778 Oct 13, 2024
c0b0bbe
removed duplicate functions, driver is looking to be close to being f…
mark11778 Oct 13, 2024
6093bdc
removed print statements
mark11778 Oct 13, 2024
7469590
updated the g9driver test file was uptodate
mark11778 Oct 13, 2024
ae82e55
while updating the gitignore, removed the panel_config.py on accident
mark11778 Oct 13, 2024
eed749e
add Interlock's COM port to be defined in main.py
mark11778 Oct 13, 2024
b99ae98
update .gitignore and remove .pyc files
mslaffin Oct 13, 2024
7b91844
working on resolving merge request errors
mark11778 Oct 14, 2024
049f90f
commiting to work on other laptop
Oct 14, 2024
a70b634
was working on adding the changes to the driver and also working with…
mark11778 Oct 14, 2024
7e55d58
added update method and todo comments
mark11778 Oct 14, 2024
e88d6a7
working on backend
mark11778 Oct 14, 2024
fa56cc3
working on interlocks.py
mark11778 Oct 14, 2024
1059c47
commiting changes
mark11778 Oct 14, 2024
ddb2950
set driver com port to none to test
mark11778 Oct 14, 2024
db9f5df
error hierarchy
arundhatisingh17 Oct 14, 2024
3a4baff
testing
arundhatisingh17 Oct 14, 2024
9df474d
modified calculate_checksum() to send both high and low byte
Oct 16, 2024
72d95c9
temp
arundhatisingh17 Oct 16, 2024
84e6033
corrected check_flags_13
arundhatisingh17 Oct 16, 2024
e0dea7c
correction
arundhatisingh17 Oct 16, 2024
81868c0
Addressed data indexing to access a single byte by slicing
Oct 16, 2024
eb166b8
removed duplicate file
mark11778 Oct 18, 2024
0364155
fixed type line 99
Oct 18, 2024
d8cab93
small change
arundhatisingh17 Oct 18, 2024
3314e9e
working on tester
mark11778 Oct 18, 2024
d38b56d
modified msg for test1
Oct 18, 2024
9b76836
push
mark11778 Oct 18, 2024
55149d3
pushing
mark11778 Oct 18, 2024
8de1851
modified msg
Oct 18, 2024
02ef996
fixed typo line 99 to return byte object instead of str
Oct 18, 2024
c5fa1bc
finishing up the test
mark11778 Oct 18, 2024
c6b7bef
pushing for tests
mark11778 Oct 18, 2024
c0faf7d
error fixed
arundhatisingh17 Oct 18, 2024
7ec3a83
added responseTestCreator.py
Oct 18, 2024
13a1f2e
Merge branch 'feature/G9Driversim' of https://github.com/uw-loci/EBEA…
Oct 18, 2024
094eb62
small changes
mark11778 Oct 18, 2024
0fb19ae
added comments to tests
mark11778 Oct 18, 2024
5abd56d
added comments
Oct 18, 2024
63aa96e
actually added the comments this time
mark11778 Oct 18, 2024
6d11673
starting to work on forming the front end
mark11778 Oct 19, 2024
750869e
it was bothering me that the water indicator was not centered
mark11778 Oct 19, 2024
34bee01
is_connected function in g9driver
mark11778 Oct 19, 2024
6d51add
working on adding the global vars
mark11778 Oct 20, 2024
b1f354b
forgot to save lol
mark11778 Oct 20, 2024
50a568d
added comments to the driver file and rearranged some things
mark11778 Oct 20, 2024
f6750a8
removed one of the tests because that functionality is not longer nee…
mark11778 Oct 20, 2024
a596306
crazy changes, made a square indicator method
mark11778 Oct 20, 2024
38c3768
added the g9 output and hvolt indicatator to the dictionary
mark11778 Oct 20, 2024
f44e8d7
i think css is easier to visualize, more frontend changes
mark11778 Oct 20, 2024
e6c8567
made sure that com port was being passed to the interlocks.py
mark11778 Oct 20, 2024
6a995fb
ensured g9 specific constants were placed within the class itself and…
Oct 21, 2024
eb72795
made all changes except check_sum
arundhatisingh17 Oct 21, 2024
1d7a44f
checksum calculation added in response
Oct 21, 2024
25e7fb0
Merge branch 'feature/G9Driversim' of https://github.com/uw-loci/EBEA…
Oct 21, 2024
b42d35a
updated all changes according to suggestions
arundhatisingh17 Oct 21, 2024
7361420
Further clarified on constants and usage
Oct 21, 2024
1315ec1
Merge branch 'feature/G9Driversim' of https://github.com/uw-loci/EBEA…
Oct 21, 2024
29c82f6
minor fixes from merging process
Oct 21, 2024
e4e028c
gui chnages
arundhatisingh17 Oct 21, 2024
1b0d048
spaced out the HV Status frame
arundhatisingh17 Oct 21, 2024
af37288
changes to frontend
arundhatisingh17 Oct 21, 2024
b447ae2
Added another indicator for the E-STOP
Oct 21, 2024
9ed450a
aligned text better with indicators/shapes
Oct 21, 2024
a5b9883
shifted the interlocks frame to the top of gui to chreate space
arundhatisingh17 Oct 23, 2024
48a87b2
small change
arundhatisingh17 Oct 23, 2024
2b528d5
remove unused imports
mslaffin Oct 23, 2024
cef3b1a
fix serial connection check
mslaffin Oct 23, 2024
bcf50b1
simplify checksum. rework message construction in send_command
mslaffin Oct 23, 2024
66e533d
worked on the frontend how everything is adjusted to just be at the t…
mark11778 Oct 27, 2024
325224d
the checksum function is making all the tests fail, will revisit this
mark11778 Oct 27, 2024
2fa2dc0
i think there is a better way to store and arrange the interlock data…
mark11778 Oct 27, 2024
1ab6b95
working on the backend in interlock.py
mark11778 Oct 28, 2024
b5eae55
working on backend still
mark11778 Oct 28, 2024
1d2d6c2
changes to integrate backend to access binary
mark11778 Oct 28, 2024
84fc850
Merge branch 'feature/G9Driversim' of https://github.com/uw-loci/EBEA…
mslaffin Oct 28, 2024
56dae32
rework checksum and read_response
mslaffin Oct 29, 2024
e701150
testing the interlocks.py to reflect status flag changes on the dashb…
Oct 30, 2024
6b5ba13
Merge branch 'feature/G9Driversim' of https://github.com/uw-loci/EBEA…
Oct 30, 2024
c27bd56
modified mock_data()
Oct 30, 2024
7ac38ff
ensured update_data is constantly called every 5 seconds and scrapped…
Oct 30, 2024
1380f18
Force remove .venv and .vscode dirs
mslaffin Oct 30, 2024
8e3741a
add .venv to gitignore
mslaffin Oct 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__pycache__/
*.pyc
usr/
venv/
.venv/
build/
dist/
EBEAM-Dashboard-Logs/
116 changes: 82 additions & 34 deletions dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,61 @@
import tkinter as tk
from tkinter import ttk
from utils import MessagesFrame, SetupScripts, LogLevel
from usr.panel_config import save_pane_states, load_pane_states
from usr.panel_config import save_pane_states, load_pane_states, saveFileExists

# frames_config = [
# ("Oil System", 0, 50, 150),
# ("Visualization Gas Control", 0, 50, 150),
# ("System Checks", 0, None, None),
# ("Beam Extraction", 0, None, None),
# ("Vacuum System", 1, 150, 300),
# ("Deflection Monitor", 1, None, None),
# ("Beam Pulse", 1, None, None),
# ("Main Control", 1, 50, 300),
# ("Setup Script", 2, None, 25),
# ("Interlocks", 2, None, 25),
# ("High Voltage Warning", 2, None, 25),
# ("Environmental", 3, 150, 450),
# ("Cathode Heating", 3, 960, 450),
# ]


# # title, row, width, height
# frames_config = [
# ("Interlocks", 0, None, 2), # Moved to the top row
# ("Oil System", 0, 50, 150),
# ("Visualization Gas Control", 1, 50, 150),
# ("System Checks", 0, None, None),
# ("Beam Extraction", 0, None, None),
# ("Vacuum System", 1, 150, 300),
# ("Deflection Monitor", 1, None, None),
# ("Beam Pulse", 1, None, None),
# ("Main Control", 1, 50, 300),
# ("Setup Script", 2, None, 25),
# ("High Voltage Warning", 2, None, 25),
# ("Environmental", 3, 150, 450),
# ("Cathode Heating", 3, 960, 450),
# ]


# Only have the interlocks at the top of the display
# title, row, width, height
frames_config = [
("Interlocks", 0, None, 2), # Moved to the top row
("Oil System", 1, 50, 150),
("Visualization Gas Control", 2, 50, 150),
("System Checks", 1, None, None),
("Beam Extraction", 1, None, None),
("Vacuum System", 2, 150, 300),
("Deflection Monitor", 2, None, None),
("Beam Pulse", 2, None, None),
("Main Control", 2, 50, 300),
("Setup Script", 3, None, 25),
("High Voltage Warning", 3, None, 25),
("Environmental", 4, 150, 450),
("Cathode Heating", 4, 960, 450),
]

import serial.tools.list_ports

class EBEAMSystemDashboard:
Expand All @@ -11,6 +65,11 @@ def __init__(self, root, com_ports):
self.com_ports = com_ports
self.root.title("EBEAM Control System Dashboard")


# if save file exists call it and open it
if saveFileExists():
self.load_saved_pane_state()

# Initialize the frames dictionary to store various GUI components
self.frames = {}

Expand All @@ -26,48 +85,31 @@ def __init__(self, root, com_ports):
# Set up different subsystems within their respective frames
self.create_subsystems()

# Load the saved state of the GUI pane layout if available
# self.load_saved_pane_state()

def setup_main_pane(self):
"""Initialize the main layout pane and its rows."""
self.main_pane = tk.PanedWindow(self.root, orient='vertical', sashrelief=tk.RAISED)
self.main_pane.grid(row=0, column=0, sticky='nsew')
self.root.grid_columnconfigure(0, weight=1)
self.root.grid_rowconfigure(0, weight=1)

# Create horizontal paned windows for each row
self.rows = [tk.PanedWindow(self.main_pane, orient='horizontal', sashrelief=tk.RAISED) for _ in range(5)]
for row_pane in self.rows:
self.main_pane.add(row_pane, stretch='always')

def create_frames(self):
"""Create frames for different systems and controls within the dashboard."""
frames_config = [
("Oil System", 0, 50, 150),
("Visualization Gas Control", 0, 50, 150),
("System Checks", 0, None, None),
("Beam Extraction", 0, None, None),
("Vacuum System", 1, 150, 300),
("Deflection Monitor", 1, None, None),
("Beam Pulse", 1, None, None),
("Main Control", 1, 50, 300),
("Setup Script", 2, None, 25),
("Interlocks", 2, None, 25),
("High Voltage Warning", 2, None, 25),
("Environmental", 3, 150, 450),
("Cathode Heating", 3, 960, 450),
]
global frames_config

for title, row, width, height in frames_config:
if width and height:
frame = tk.Frame(borderwidth=1, relief="solid", width=width, height=height)
if width and height and title:
frame = tk.Frame( borderwidth=1,highlightbackground="red", relief="solid", width=width, height=height)
frame.pack_propagate(False)
else:
frame = tk.Frame(borderwidth=1, relief="solid")
# frame.pack_propagate(False)

self.rows[row].add(frame, stretch='always')
self.add_title(frame, title)
if title != "Interlocks":
self.add_title(frame, title)
self.frames[title] = frame
if title == "Setup Script":
SetupScripts(frame)
Expand Down Expand Up @@ -97,13 +139,17 @@ def add_title(self, frame, title):
label = tk.Label(frame, text=title, font=("Helvetica", 10, "bold"))
label.pack(pady=0, fill=tk.X)

# saves data to file when button is pressed
def save_current_pane_state(self):
num_sashes = len(self.rows) - 1 # Assuming each row might have one sash
save_pane_states(self.main_pane, num_sashes)
save_pane_states(frames_config, self.frames, self.main_pane)

# gets data in save config file (as dict) and updates the global var of frames_config
def load_saved_pane_state(self):
num_sashes = len(self.rows) - 1
load_pane_states(self.main_pane, num_sashes)
savedData = load_pane_states()

for i in range(len(frames_config)):
if frames_config[i][0] in savedData:
frames_config[i] = (frames_config[i][0], frames_config[i][1], savedData[frames_config[i][0]][0],savedData[frames_config[i][0]][1])

def create_log_level_dropdown(self, parent_frame):
log_level_frame = ttk.Frame(parent_frame)
Expand Down Expand Up @@ -139,11 +185,13 @@ def create_subsystems(self):
logger=self.logger
),
'Interlocks': subsystem.InterlocksSubsystem(
self.frames['Interlocks'],
logger=self.logger
self.frames['Interlocks'],
com_ports = self.com_ports['Interlocks'],
logger=self.logger,
frames = self.frames
),
'Oil System': subsystem.OilSubsystem(
self.frames['Oil System'],
self.frames['Oil System'],
logger=self.logger
),
'Cathode Heating': subsystem.CathodeHeatingSubsystem(
Expand All @@ -155,8 +203,8 @@ def create_subsystems(self):

def create_messages_frame(self):
"""Create a frame for displaying messages and errors."""
self.messages_frame = MessagesFrame(self.rows[3])
self.rows[3].add(self.messages_frame.frame, stretch='always')
self.messages_frame = MessagesFrame(self.rows[4])
self.rows[4].add(self.messages_frame.frame, stretch='always')
self.logger = self.messages_frame.logger

def create_com_port_frame(self, parent_frame):
Expand All @@ -173,7 +221,7 @@ def create_com_port_frame(self, parent_frame):
self.port_selections = {}
self.port_dropdowns = {}

for subsystem in ['VTRXSubsystem', 'CathodeA PS', 'CathodeB PS', 'CathodeC PS', 'TempControllers']:
for subsystem in ['VTRXSubsystem', 'CathodeA PS', 'CathodeB PS', 'CathodeC PS', 'TempControllers', 'Interlocks']:
frame = ttk.Frame(self.com_port_menu)
frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(frame, text=f"{subsystem}:").pack(side=tk.LEFT)
Expand Down
101 changes: 101 additions & 0 deletions instrumentctl/errorTests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import unittest
from unittest.mock import MagicMock, patch
from instrumentctl.g9_driver import G9Driver

# Optional Data modified to throw no errors
msg = b'@\x00\x00\xc3\x00\x00\xcb\x00\x00\x00\x00\x00\x08\x00\x00\x1f\xffC\x00\x1f\xff\xff\xff\x0f\x00\x1f\xff\xff\x00\x1f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x01\x9a\x08\xbe\x14\x00\x0020000012X17M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\n?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb2?\x00\x14\xac?\x00\x14\xac?\x00\x14\xac?\x00\x14\xa0?\x00\x14\xa0\x06\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\x9a\x01\x00\x14\x9a\x01\x00\x14\x9a\x06\x00\x14\x9a\x1a\xe8*\r'

class TestG9Driver(unittest.TestCase):
UNIT_ERROR_MSG = b'@\x00\x00\xc3\x00\x00\xcb\x00\x00\x00\x00\x00\x08\x00\x00\x1f\xffC\x00\x1f\xff\xff\xff\x0f\x00\x1f\xff\xff\x00\x1f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x02\x00\x9a\x08\xbe\x14\x00\x0020000012X17M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\n?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb2?\x00\x14\xac?\x00\x14\xac?\x00\x14\xac?\x00\x14\xa0?\x00\x14\xa0\x06\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\x9a\x01\x00\x14\x9a\x01\x00\x14\x9a\x06\x00\x14\x9a\x1a\xe8*\r'
INPUT_ERROR_MSG = b'@\x00\x00\xc3\x00\x00\xcb\x00\x00\x00\x00\x00\x08\x00\x00\x1f\x00C\x00\x1f\xff\xff\xff\x0f\x00\x1f\xff\xff\x00\x1f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x01\x9a\x08\xbe\x14\x00\x0020000012X17M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\n?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb2?\x00\x14\xac?\x00\x14\xac?\x00\x14\xac?\x00\x14\xa0?\x00\x14\xa0\x06\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\x9a\x01\x00\x14\x9a\x01\x00\x14\x9a\x06\x00\x14\x9a\x1a\xe8*\r'
OUTPUT_ERROR_MSG = b'@\x00\x00\xc3\x00\x00\xcb\x00\x00\x00\x00\x00\x08\x00\x00\x1f\xffC\x00\x1f\x00\x00\xff\x0f\x00\x1f\xff\xff\x00\x1f\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x01\x9a\x08\xbe\x14\x00\x0020000012X17M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\n?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb8?\x00\x14\xb2?\x00\x14\xac?\x00\x14\xac?\x00\x14\xac?\x00\x14\xa0?\x00\x14\xa0\x06\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\xb2\x01\x00\x14\xb2\x06\x00\x14\x9a\x01\x00\x14\x9a\x01\x00\x14\x9a\x06\x00\x14\x9a\x1a\xe8*\r'

def create_message_with_checksum(self, base_message):
"""Helper to create a message with valid checksum"""
message_without_checksum = base_message[:-4] # Remove existing checksum and footer (these are probably incorrect in this older msg data)
checksum = self.driver.calculate_checksum(message_without_checksum)
return message_without_checksum + checksum + self.driver.FOOTER

def setUp(self):
self.driver = G9Driver()
self.driver.msgOptData = b'\x00\x00\x00\x00'
self.driver.ser = MagicMock()
self.driver.logger = MagicMock()

# Modified bytes msg[73:75] to ['02', '00'] to trigger a power supply error within unit status bytes
def test_unit_state_error(self):
msg_base = bytearray(self.UNIT_ERROR_MSG)
msg_base[73:75] = b'\x02\x00' # Set US bytes to trigger power supply error
msg_with_checksum = self.create_message_with_checksum(bytes(msg_base))

self.driver.ser.read_until.return_value = msg_with_checksum

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Output Power Supply Error Flag (bit 9)", str(context.exception))

# changed 10 to \x00 instead of expected \xff
def test_input_error(self):
# Create base message with input error
msg_base = bytearray(self.INPUT_ERROR_MSG)
msg_base[self.driver.SITDF_OFFSET:self.driver.SITDF_OFFSET + 6] = b'\x00' * 6 # Set SITDF to all zeros
msg_with_checksum = self.create_message_with_checksum(bytes(msg_base))

self.driver.ser.read_until.return_value = msg_with_checksum

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Inputs off or in error state", str(context.exception))

# changed byte 20 to be \x00 instead of expected \xff
def test_output_error(self):
# Create base message with output error
msg_base = bytearray(self.OUTPUT_ERROR_MSG)
msg_base[self.driver.SOTDF_OFFSET:self.driver.SOTDF_OFFSET + 4] = b'\x00' * 4 # Set SOTDF to all zeros
msg_with_checksum = self.create_message_with_checksum(bytes(msg_base))

self.driver.ser.read_until.return_value = msg_with_checksum

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Outputs in off state", str(context.exception))


# test of normal excepted values
def test_no_error(self):
# Create message with valid checksum
msg_with_checksum = self.create_message_with_checksum(msg)
self.driver.ser.read_until.return_value = msg_with_checksum

try:
self.driver.read_response()
except ValueError as e:
self.fail(f"read_response() raised ValueError unexpectedly: {str(e)}")

def test_invalid_start_byte(self):
invalid_msg = b'\x41' + msg[1:] # Replace start byte
msg_with_checksum = self.create_message_with_checksum(invalid_msg)
self.driver.ser.read_until.return_value = msg_with_checksum

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Invalid start byte", str(context.exception))

def test_invalid_length(self):
short_msg = msg[:-10] # Remove last 10 bytes
self.driver.ser.read_until.return_value = short_msg

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Invalid response length", str(context.exception))

def test_checksum_validation(self):
bad_checksum_msg = msg[:-4] + b'\x00\x00' + msg[-2:] # Replace checksum bytes
self.driver.ser.read_until.return_value = bad_checksum_msg

with self.assertRaises(ValueError) as context:
self.driver.read_response()
self.assertIn("Checksum validation failed", str(context.exception))

if __name__ == '__main__':
unittest.main()
Loading