Skip to content

Commit d0da081

Browse files
peterhollenderNeuromod 2Alexgeorgevigelette
authored
Improve and fix hardware communication
Makes changes to the `io` module to improve communication with hardware. - Standardizes pin-mapping on transmit modules - Corrects for pulse length truncation when using long pulses - Fixes bugs in `test_watertank.py` - Fixes bugs with status and communication setup - Incorporates sequencing and messaging interface to firmware Closes #349 Closes #354 * sort pins and watertank improvements * adjust pin ordering * fix instantiation * update test_watertank * update watertank * Remove console supply voltage check when using external supply before setting solution. * WIP test update for element swaps * Fix logger message for log file output. * point dvc back to main * add 2x400 evt1 with pin map * Add 1x400 evt1 * pass trigger mode. Closes #349 * Merge George's changes * Update all mode parameters to be trigger_mode * switch mode -> trigger_mode in rest of places * Change max sequence time to 20 mins, default pulse width from 20ms to 20us * Create status variable in class, update get_status(), create set_status() in LIFUInterface * Add pulse length adjust * Remove duplicate TRIGGER_MODE_ definitations import these from LIFUConfig * Set status messages and add TODO's * Change write block logging to debug, make exception more specific (pylint fix) * Change debug level to INFO in TXDevice, small logger info/debug switch * added script async example * add async mode for update status messages --------- Co-authored-by: Neuromod 2 <lab@openwater.cc> Co-authored-by: Alex <akagan@openwater.cc> Co-authored-by: George Vigelette <george@openwater.cc>
1 parent a5f725a commit d0da081

16 files changed

+490
-145
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ Thumbs.db
160160
*.swp
161161
.vscode
162162
/db_dvc
163+
/logs
163164

164165
# ONNX checkpoints
165166
*.onnx

db_dvc.dvc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
outs:
2-
- md5: 9fccb7e2954839d729ab3d0fa1abb580.dir
3-
nfiles: 797
2+
- md5: 696cd731bd5fadd19cc1fda1da602fb7.dir
3+
nfiles: 802
44
hash: md5
55
path: db_dvc
6-
size: 2357262767

notebooks/test_async.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import logging
5+
import threading
6+
import time
7+
8+
from openlifu.io.LIFUInterface import LIFUInterface
9+
10+
# set PYTHONPATH=%cd%\src;%PYTHONPATH%
11+
# python notebooks/test_async.py
12+
13+
# Setup logging
14+
logging.basicConfig(level=logging.INFO)
15+
16+
interface = None
17+
18+
# Callbacks
19+
def on_connect(descriptor, port):
20+
print(f"🔌 CONNECTED: {descriptor} on port {port}")
21+
22+
def on_disconnect(descriptor, port):
23+
print(f"❌ DISCONNECTED: {descriptor} from port {port}")
24+
25+
def on_data_received(descriptor, packet):
26+
print(f"📦 DATA [{descriptor}]: {packet}")
27+
28+
def monitor_interface():
29+
"""Run the device monitor loop in a separate thread using asyncio."""
30+
asyncio.run(interface.start_monitoring(interval=1))
31+
32+
def rebind_tx_callbacks():
33+
"""Bind callbacks to the TX UART, if present."""
34+
if interface.txdevice and interface.txdevice.uart:
35+
interface.txdevice.uart.signal_connect.connect(on_connect)
36+
interface.txdevice.uart.signal_disconnect.connect(on_disconnect)
37+
interface.txdevice.uart.signal_data_received.connect(on_data_received)
38+
39+
def run_menu():
40+
while True:
41+
print("\n--- LIFU MENU ---")
42+
print("1. Turn ON 12V")
43+
print("2. Turn OFF 12V")
44+
print("3. Ping TX")
45+
print("4. Show Connection Status")
46+
print("5. Exit")
47+
choice = input("Enter choice: ").strip()
48+
49+
tx_connected, hv_connected = interface.is_device_connected()
50+
51+
if choice == "1":
52+
if hv_connected:
53+
print("⚡ Sending 12V ON...")
54+
interface.hvcontroller.turn_12v_on()
55+
time.sleep(2.0)
56+
print("🔄 Reinitializing TX...")
57+
rebind_tx_callbacks()
58+
else:
59+
print("⚠️ HV not connected.")
60+
61+
elif choice == "2":
62+
if hv_connected:
63+
print("🛑 Sending 12V OFF...")
64+
interface.hvcontroller.turn_12v_off()
65+
else:
66+
print("⚠️ HV not connected.")
67+
68+
elif choice == "3":
69+
if tx_connected:
70+
print("📡 Sending PING to TX...")
71+
resp = interface.txdevice.ping()
72+
if resp:
73+
print("✅ TX responded to PING.")
74+
else:
75+
print("❌ No response or error.")
76+
else:
77+
print("⚠️ TX not connected.")
78+
79+
elif choice == "4":
80+
print("Status:")
81+
print(f" TX: {'✅ Connected' if tx_connected else '❌ Not connected'}")
82+
print(f" HV: {'✅ Connected' if hv_connected else '❌ Not connected'}")
83+
84+
elif choice == "5":
85+
print("Exiting...")
86+
interface.stop_monitoring()
87+
break
88+
else:
89+
print("Invalid choice.")
90+
91+
if __name__ == "__main__":
92+
interface = LIFUInterface(HV_test_mode=False, run_async=False)
93+
94+
# Bind callbacks for HV and (initially connected) TX
95+
if interface.hvcontroller.uart:
96+
interface.hvcontroller.uart.signal_connect.connect(on_connect)
97+
interface.hvcontroller.uart.signal_disconnect.connect(on_disconnect)
98+
interface.hvcontroller.uart.signal_data_received.connect(on_data_received)
99+
100+
rebind_tx_callbacks()
101+
102+
print("🔍 Starting LIFU monitoring...")
103+
monitor_thread = threading.Thread(target=monitor_interface, daemon=True)
104+
monitor_thread.start()
105+
106+
try:
107+
run_menu()
108+
except KeyboardInterrupt:
109+
print("\n🛑 Stopped by user.")
110+
interface.stop_monitoring()

notebooks/test_async_mode.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
import time
5+
6+
from openlifu.io.LIFUInterface import LIFUInterface
7+
8+
# set PYTHONPATH=%cd%\src;%PYTHONPATH%
9+
# python notebooks/test_async_mode.py
10+
11+
def main():
12+
print("Starting LIFU Async Test Script...")
13+
interface = LIFUInterface()
14+
tx_connected, hv_connected = interface.is_device_connected()
15+
16+
if not tx_connected and not hv_connected:
17+
print("✅ LIFU Console not connected.")
18+
sys.exit(1)
19+
20+
if not tx_connected:
21+
print("TX device not connected. Attempting to turn on 12V...")
22+
interface.hvcontroller.turn_12v_on()
23+
time.sleep(2)
24+
25+
interface.stop_monitoring()
26+
del interface
27+
time.sleep(3)
28+
29+
print("Reinitializing LIFU interface after powering 12V...")
30+
interface = LIFUInterface()
31+
tx_connected, hv_connected = interface.is_device_connected()
32+
33+
if tx_connected and hv_connected:
34+
print("✅ LIFU Device fully connected.")
35+
else:
36+
print("❌ LIFU Device NOT fully connected.")
37+
print(f" TX Connected: {tx_connected}")
38+
print(f" HV Connected: {hv_connected}")
39+
sys.exit(1)
40+
41+
print("Ping the device")
42+
if not interface.txdevice.ping():
43+
print("❌ Failed comms with txdevice.")
44+
sys.exit(1)
45+
46+
version = interface.txdevice.get_version()
47+
print(f"Version: {version}")
48+
49+
curr_mode = interface.txdevice.async_mode()
50+
print(f"Current Async Mode: {curr_mode}")
51+
time.sleep(1)
52+
if curr_mode:
53+
print("Async mode is already enabled.")
54+
else:
55+
print("Enabling Async Mode...")
56+
interface.txdevice.async_mode(True)
57+
time.sleep(1)
58+
curr_mode = interface.txdevice.async_mode()
59+
print(f"Async Mode Enabled: {curr_mode}")
60+
time.sleep(1)
61+
print("Disabling Async Mode...")
62+
interface.txdevice.async_mode(False)
63+
time.sleep(1)
64+
curr_mode = interface.txdevice.async_mode()
65+
print(f"Async Mode Enabled: {curr_mode}")
66+
67+
if __name__ == "__main__":
68+
main()

notebooks/test_console_dfu.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from openlifu.io.LIFUInterface import LIFUInterface
66

77
# set PYTHONPATH=%cd%\src;%PYTHONPATH%
8-
# python notebooks/test_update_firmware.py
8+
# python notebooks/test_console_dfu.py
99
"""
1010
Test script to automate:
1111
1. Connect to the device.

notebooks/test_thermal_stress.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def log_temperature():
278278
delays = sol_dict['delays'],
279279
apodizations= sol_dict['apodizations'],
280280
sequence= sol_dict['sequence'],
281-
mode="continuous",
281+
trigger_mode="continuous",
282282
profile_index=profile_index,
283283
profile_increment=profile_increment
284284
)

notebooks/test_transmitter2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
delays = sol_dict['delays'],
8282
apodizations= sol_dict['apodizations'],
8383
sequence= sol_dict['sequence'],
84-
mode = "continuous",
84+
trigger_mode = "continuous",
8585
profile_index=profile_index,
8686
profile_increment=profile_increment
8787
)

notebooks/test_tx_trigger.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import sys
44
import time
55

6+
from openlifu.io.LIFUConfig import (
7+
TRIGGER_MODE_SEQUENCE,
8+
TRIGGER_MODE_SINGLE,
9+
)
610
from openlifu.io.LIFUInterface import LIFUInterface
711

812
# set PYTHONPATH=%cd%\src;%PYTHONPATH%
@@ -62,19 +66,26 @@ def main():
6266
print("❌ Failed comms with txdevice.")
6367
sys.exit(1)
6468

69+
version = interface.txdevice.get_version()
70+
print(f"Version: {version}")
71+
6572
while True:
6673
params = get_user_input()
6774
if params is None:
6875
print("Exiting...")
76+
if interface.txdevice.is_connected:
77+
print("Disconnecting TX device...")
78+
interface.txdevice.close()
79+
6980
break
7081

7182
json_trigger_data = {
7283
"TriggerFrequencyHz": params["freq"],
73-
"TriggerPulseCount": 1,
84+
"TriggerPulseCount": 10,
7485
"TriggerPulseWidthUsec": params["pulse_width"],
75-
"TriggerPulseTrainInterval": 0,
76-
"TriggerPulseTrainCount": 0,
77-
"TriggerMode": 1,
86+
"TriggerPulseTrainInterval": 300000,
87+
"TriggerPulseTrainCount": 10,
88+
"TriggerMode": TRIGGER_MODE_SEQUENCE, # Change to TRIGGER_MODE_CONTINUOUS or TRIGGER_MODE_SEQUENCE or TRIGGER_MODE_SINGLE as needed
7889
"ProfileIndex": 0,
7990
"ProfileIncrement": 0
8091
}
@@ -87,8 +98,38 @@ def main():
8798
print("Failed to set trigger setting.")
8899
continue
89100

90-
if interface.txdevice.start_trigger():
91-
print("Trigger Running. Press Enter to STOP:")
101+
if trigger_setting["TriggerMode"] == TRIGGER_MODE_SINGLE:
102+
print("Trigger Mode set to SINGLE. Press Enter to START:")
103+
if interface.txdevice.start_trigger():
104+
print("Trigger started successfully.")
105+
else:
106+
print("Failed to start trigger.")
107+
108+
elif trigger_setting["TriggerMode"] == TRIGGER_MODE_SEQUENCE:
109+
print("Trigger Mode set to SEQUENCE")
110+
if interface.txdevice.start_trigger():
111+
print("Trigger started successfully.")
112+
else:
113+
print("Failed to start trigger.")
114+
while True:
115+
trigger_status = interface.txdevice.get_trigger_json()
116+
if trigger_status is None:
117+
print("Failed to get trigger status! Fatal Error.")
118+
break
119+
120+
if trigger_status["TriggerStatus"] == "STOPPED":
121+
print("Run Complete.")
122+
break
123+
124+
time.sleep(.5)
125+
else:
126+
print("Trigger Running Continuous Mode. Press Enter to STOP:")
127+
128+
if interface.txdevice.start_trigger():
129+
print("Trigger started successfully.")
130+
else:
131+
print("Failed to start trigger.")
132+
92133
input() # Wait for the user to press Enter
93134
if interface.txdevice.stop_trigger():
94135
print("Trigger stopped successfully.")

notebooks/test_updated_if.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
delays = sol_dict['delays'],
140140
apodizations= sol_dict['apodizations'],
141141
sequence= sol_dict['sequence'],
142-
mode = "continuous",
142+
trigger_mode = "continuous",
143143
profile_index=profile_index,
144144
profile_increment=profile_increment
145145
)

0 commit comments

Comments
 (0)