238 lines
7.3 KiB
Python
Executable File
238 lines
7.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Genesis Laser Protocol Test Script
|
|
===================================
|
|
|
|
Simple command-line script to test NXP I2C-over-serial communication
|
|
with the Genesis SLM MX 532 laser.
|
|
|
|
Usage:
|
|
python test_genesis_protocol.py [port] [baudrate]
|
|
|
|
Example:
|
|
python test_genesis_protocol.py /dev/ttyUSB0 9600
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
import serial
|
|
from typing import Optional
|
|
|
|
|
|
class NXPProtocolTester:
|
|
"""Simple NXP I2C protocol tester"""
|
|
|
|
NXP_START = 0x53
|
|
NXP_STOP = 0x50
|
|
|
|
def __init__(self, port: str = "/dev/ttyUSB0", baudrate: int = 9600):
|
|
self.port = serial.Serial(
|
|
port=port,
|
|
baudrate=baudrate,
|
|
bytesize=serial.EIGHTBITS,
|
|
parity=serial.PARITY_NONE,
|
|
stopbits=serial.STOPBITS_ONE,
|
|
timeout=1.0
|
|
)
|
|
time.sleep(0.1)
|
|
print(f"Connected to {port} at {baudrate} baud")
|
|
|
|
def send_packet(self, i2c_addr: int, cmd: bytes, data: bytes = b''):
|
|
"""Send NXP I2C write packet"""
|
|
if not isinstance(cmd, bytes):
|
|
cmd = bytes([cmd])
|
|
if not isinstance(data, bytes):
|
|
data = bytes(data)
|
|
|
|
length = len(cmd) + len(data)
|
|
packet = bytes([self.NXP_START, i2c_addr, length]) + cmd + data + bytes([self.NXP_STOP])
|
|
|
|
print(f"TX: {' '.join(f'{b:02x}' for b in packet)}")
|
|
self.port.write(packet)
|
|
|
|
def read_packet(self, i2c_addr_write: int, cmd: bytes, cmd_len: int, data_len: int) -> Optional[bytes]:
|
|
"""Send NXP I2C read packet and return data"""
|
|
if not isinstance(cmd, bytes):
|
|
cmd = bytes([cmd])
|
|
|
|
i2c_addr_read = i2c_addr_write | 0x01
|
|
|
|
packet_write = bytes([self.NXP_START, i2c_addr_write, cmd_len]) + cmd
|
|
packet_read = bytes([self.NXP_START, i2c_addr_read, data_len, self.NXP_STOP])
|
|
packet = packet_write + packet_read
|
|
|
|
print(f"TX: {' '.join(f'{b:02x}' for b in packet)}")
|
|
self.port.write(packet)
|
|
|
|
time.sleep(0.05)
|
|
response = self.port.read(data_len)
|
|
|
|
if response:
|
|
print(f"RX: {' '.join(f'{b:02x}' for b in response)}")
|
|
return response
|
|
else:
|
|
print("RX: (no response)")
|
|
return None
|
|
|
|
def test_x9119_current(self, value: int = 100):
|
|
"""Test X9119 current control"""
|
|
print(f"\n=== Testing X9119 Current Control (value={value}) ===")
|
|
|
|
# X9119 current control at 0x52
|
|
# Command 0xa0, 2 bytes data (10-bit value)
|
|
value = max(0, min(1023, value))
|
|
msb = (value >> 8) & 0x03
|
|
lsb = value & 0xFF
|
|
|
|
self.send_packet(0x52, bytes([0xa0]), bytes([msb, lsb]))
|
|
print("Current command sent")
|
|
|
|
def test_pca9555_shutter(self, state: bool):
|
|
"""Test PCA9555 shutter control"""
|
|
print(f"\n=== Testing PCA9555 Shutter Control (state={'OPEN' if state else 'CLOSED'}) ===")
|
|
|
|
# Read current output port 0 value
|
|
print("Reading current port value...")
|
|
current = self.read_packet(0x4a, bytes([0x02]), 1, 1)
|
|
|
|
if current and len(current) == 1:
|
|
current_value = current[0]
|
|
print(f"Current port value: 0x{current_value:02x}")
|
|
|
|
# Modify bit 0 (shutter)
|
|
if state:
|
|
new_value = current_value | 0x01
|
|
else:
|
|
new_value = current_value & ~0x01
|
|
|
|
print(f"New port value: 0x{new_value:02x}")
|
|
|
|
# Write back
|
|
self.send_packet(0x4a, bytes([0x02]), bytes([new_value]))
|
|
print("Shutter command sent")
|
|
else:
|
|
print("Failed to read current port value")
|
|
|
|
def test_ads7828_current_reading(self):
|
|
"""Test ADS7828 current reading"""
|
|
print(f"\n=== Testing ADS7828 Current Reading ===")
|
|
|
|
# ADS7828 at 0x90/0x91
|
|
# Command byte: 0x80 (single-ended) | (channel << 4) | 0x0c (internal ref)
|
|
# Reading channel 0
|
|
cmd_byte = 0x80 | (0 << 4) | 0x0c
|
|
|
|
data = self.read_packet(0x90, bytes([cmd_byte]), 1, 2)
|
|
|
|
if data and len(data) == 2:
|
|
value = (data[0] << 8) | data[1]
|
|
value = (value >> 4) & 0x0FFF
|
|
print(f"Current reading: {value} counts (0x{value:03x})")
|
|
else:
|
|
print("Failed to read current")
|
|
|
|
def test_pca9555_read_ports(self):
|
|
"""Test reading all PCA9555 I/O expander ports"""
|
|
print(f"\n=== Testing PCA9555 Port Reads ===")
|
|
|
|
devices = [
|
|
(0x4a, "Main DIO (0x14a)"),
|
|
(0x48, "PS Glue (0x148)"),
|
|
(0x44, "Head DIO (0x144)"),
|
|
(0x40, "LDD Control (0x140)"),
|
|
]
|
|
|
|
for addr, name in devices:
|
|
print(f"\n{name}:")
|
|
for port in range(8):
|
|
data = self.read_packet(addr, bytes([port]), 1, 1)
|
|
if data and len(data) == 1:
|
|
print(f" Register 0x{port:02x}: 0x{data[0]:02x} (0b{data[0]:08b})")
|
|
else:
|
|
print(f" Register 0x{port:02x}: read failed")
|
|
time.sleep(0.05)
|
|
|
|
def close(self):
|
|
"""Close serial port"""
|
|
self.port.close()
|
|
print("\nConnection closed")
|
|
|
|
|
|
def main():
|
|
"""Main test function"""
|
|
# Parse command line arguments
|
|
port = sys.argv[1] if len(sys.argv) > 1 else "/dev/ttyUSB0"
|
|
baudrate = int(sys.argv[2]) if len(sys.argv) > 2 else 9600
|
|
|
|
try:
|
|
# Create tester
|
|
tester = NXPProtocolTester(port, baudrate)
|
|
|
|
# Menu
|
|
while True:
|
|
print("\n" + "="*60)
|
|
print("Genesis Laser Protocol Test Menu")
|
|
print("="*60)
|
|
print("1. Test X9119 current control (set to 100)")
|
|
print("2. Test PCA9555 shutter OPEN")
|
|
print("3. Test PCA9555 shutter CLOSE")
|
|
print("4. Test ADS7828 current reading")
|
|
print("5. Test read all PCA9555 ports")
|
|
print("6. Set current to 0 (safe state)")
|
|
print("7. Emergency stop (shutter close + current 0)")
|
|
print("8. Custom X9119 current value")
|
|
print("0. Exit")
|
|
print("="*60)
|
|
|
|
choice = input("Enter choice: ").strip()
|
|
|
|
if choice == "1":
|
|
tester.test_x9119_current(100)
|
|
|
|
elif choice == "2":
|
|
tester.test_pca9555_shutter(True)
|
|
|
|
elif choice == "3":
|
|
tester.test_pca9555_shutter(False)
|
|
|
|
elif choice == "4":
|
|
tester.test_ads7828_current_reading()
|
|
|
|
elif choice == "5":
|
|
tester.test_pca9555_read_ports()
|
|
|
|
elif choice == "6":
|
|
print("\n=== Setting current to 0 ===")
|
|
tester.test_x9119_current(0)
|
|
|
|
elif choice == "7":
|
|
print("\n=== EMERGENCY STOP ===")
|
|
tester.test_pca9555_shutter(False)
|
|
time.sleep(0.1)
|
|
tester.test_x9119_current(0)
|
|
print("Emergency stop complete")
|
|
|
|
elif choice == "8":
|
|
try:
|
|
value = int(input("Enter current value (0-1023): "))
|
|
tester.test_x9119_current(value)
|
|
except ValueError:
|
|
print("Invalid value")
|
|
|
|
elif choice == "0":
|
|
break
|
|
|
|
else:
|
|
print("Invalid choice")
|
|
|
|
tester.close()
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|