mirror of
https://github.com/MiSTer-devel/VT52_MiSTer.git
synced 2026-04-19 03:05:47 +00:00
146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
import serial
|
|
import serial.tools.list_ports
|
|
import keyboard
|
|
import time
|
|
import sys
|
|
from queue import Queue
|
|
from threading import Lock
|
|
|
|
def list_available_ports():
|
|
"""List all available COM ports."""
|
|
ports = serial.tools.list_ports.comports()
|
|
if not ports:
|
|
print("No COM ports found!")
|
|
return []
|
|
|
|
print("\nAvailable COM ports:")
|
|
for port in ports:
|
|
print(f"* {port.device}: {port.description}")
|
|
return [port.device for port in ports]
|
|
|
|
def setup_serial_port(port, baud_rate):
|
|
"""Configure and open serial port with error handling."""
|
|
try:
|
|
# First check if port exists
|
|
available_ports = list_available_ports()
|
|
if port not in available_ports:
|
|
print(f"\nError: {port} not found in available ports.")
|
|
return None
|
|
|
|
# Try to open the port
|
|
print(f"\nTrying to open {port}...")
|
|
ser = serial.Serial(
|
|
port=port,
|
|
baudrate=baud_rate,
|
|
bytesize=serial.EIGHTBITS,
|
|
parity=serial.PARITY_NONE,
|
|
stopbits=serial.STOPBITS_ONE,
|
|
timeout=0.1
|
|
)
|
|
return ser
|
|
except serial.SerialException as e:
|
|
if "PermissionError" in str(e):
|
|
print(f"\nError: Cannot access {port}. The port might be in use by another program.")
|
|
print("Please:\n1. Close any other programs using the port")
|
|
print("2. Check Device Manager to verify port status")
|
|
print("3. Try running this program as administrator")
|
|
else:
|
|
print(f"\nError opening serial port {port}: {e}")
|
|
return None
|
|
|
|
def hex_format(data):
|
|
"""Format byte data as hex string."""
|
|
return f"0x{data:02X}"
|
|
|
|
# Global queue for keyboard events
|
|
key_queue = Queue()
|
|
key_lock = Lock()
|
|
|
|
def on_key_event(e):
|
|
"""Callback for keyboard events"""
|
|
if e.event_type == keyboard.KEY_DOWN:
|
|
with key_lock:
|
|
key_queue.put(e)
|
|
|
|
def main():
|
|
# First list available ports
|
|
print("Scanning for available ports...")
|
|
available_ports = list_available_ports()
|
|
|
|
if not available_ports:
|
|
print("No ports available. Please connect a device and try again.")
|
|
return
|
|
|
|
# Let user select port if COM9 isn't available
|
|
port = "COM9"
|
|
if port not in available_ports:
|
|
print(f"\nDefault port {port} not found.")
|
|
if len(available_ports) == 1:
|
|
port = available_ports[0]
|
|
print(f"Using available port: {port}")
|
|
else:
|
|
print("\nPlease select a port by number:")
|
|
for i, p in enumerate(available_ports):
|
|
print(f"{i + 1}: {p}")
|
|
while True:
|
|
try:
|
|
choice = int(input("Enter port number: ")) - 1
|
|
if 0 <= choice < len(available_ports):
|
|
port = available_ports[choice]
|
|
break
|
|
else:
|
|
print("Invalid choice. Please try again.")
|
|
except ValueError:
|
|
print("Please enter a number.")
|
|
|
|
baud_rate = 115200
|
|
ser = setup_serial_port(port, baud_rate)
|
|
if not ser:
|
|
print("\nFailed to open serial port. Exiting...")
|
|
return
|
|
|
|
print(f"\nSuccessfully opened {port} at {baud_rate} baud")
|
|
print("Press Ctrl+C to exit")
|
|
|
|
# Set up keyboard hook
|
|
keyboard.hook(on_key_event)
|
|
|
|
try:
|
|
while True:
|
|
# Non-blocking keyboard check
|
|
with key_lock:
|
|
if not key_queue.empty():
|
|
event = key_queue.get()
|
|
key = event.name
|
|
if len(key) == 1: # Single characters
|
|
ser.write(key.encode('utf-8'))
|
|
hex_value = hex_format(ord(key))
|
|
print(f"Sent: {key} [{hex_value}]")
|
|
elif key == "space":
|
|
ser.write(b' ')
|
|
print("Sent: <space> [0x20]")
|
|
elif key == "enter":
|
|
ser.write(b'\r\n')
|
|
print("Sent: <enter> [0x0D 0x0A]")
|
|
|
|
# Check for received data and echo it
|
|
if ser.in_waiting > 0:
|
|
data = ser.read(ser.in_waiting)
|
|
print(f"Received: {data.hex()}")
|
|
for byte in data:
|
|
ser.write(bytes([byte]))
|
|
print(f"Echoed: {chr(byte) if 32 <= byte <= 126 else '<non-printable>'} [{hex_format(byte)}]")
|
|
ser.flush()
|
|
|
|
time.sleep(0.001)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\nExiting...")
|
|
finally:
|
|
keyboard.unhook_all()
|
|
if ser and ser.is_open:
|
|
ser.close()
|
|
print("Serial port closed")
|
|
|
|
if __name__ == "__main__":
|
|
main() |