added reader script
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
RP2040 Serial Log Reader
|
||||
Connects to RP2040 controller via serial and manages logs (read/clear)
|
||||
"""
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
class RP2040LogReader:
|
||||
def __init__(self):
|
||||
self.ser = None
|
||||
self.port = None
|
||||
self.baudrate = 115200 # Common baudrate for RP2040
|
||||
|
||||
def clear_screen(self):
|
||||
"""Clear the terminal screen"""
|
||||
os.system('clear' if os.name == 'posix' else 'cls')
|
||||
|
||||
def wait_for_continue(self):
|
||||
"""Wait for user to press Enter to continue"""
|
||||
input("\nPress Enter to return to menu...")
|
||||
self.clear_screen()
|
||||
|
||||
def find_ports(self):
|
||||
"""List available serial ports"""
|
||||
ports = serial.tools.list_ports.comports()
|
||||
return ports
|
||||
|
||||
def find_rp2040(self):
|
||||
"""Search for RP2040 device in available ports"""
|
||||
ports = self.find_ports()
|
||||
for port_info in ports:
|
||||
# Check for common RP2040 identifiers
|
||||
if any(identifier in port_info.description.lower() for identifier in ['rp2040', 'pico', 'feather', 'tinyusb']):
|
||||
return port_info.device
|
||||
return None
|
||||
|
||||
def connect(self, port=None, baudrate=115200):
|
||||
"""Connect to the serial port"""
|
||||
try:
|
||||
if port is None:
|
||||
# Try to auto-detect RP2040
|
||||
print("Looking for RP2040 device...")
|
||||
|
||||
rp2040_port = self.find_rp2040()
|
||||
|
||||
if rp2040_port:
|
||||
port = rp2040_port
|
||||
print(f"Found RP2040 at {port}")
|
||||
else:
|
||||
print("RP2040 not found. Waiting for device to connect...")
|
||||
print(" (Please plug in your RP2040 device)")
|
||||
|
||||
# Loop and wait for device
|
||||
while not rp2040_port:
|
||||
time.sleep(2)
|
||||
rp2040_port = self.find_rp2040()
|
||||
if rp2040_port:
|
||||
port = rp2040_port
|
||||
print(f"RP2040 detected at {port}")
|
||||
break
|
||||
print("Still waiting for RP2040...")
|
||||
|
||||
self.ser = serial.Serial(port, baudrate, timeout=2)
|
||||
self.port = port
|
||||
time.sleep(1) # Wait for connection to stabilize
|
||||
print(f"Connected to {port} at {baudrate} baud")
|
||||
return True
|
||||
|
||||
except serial.SerialException as e:
|
||||
print(f"Failed to connect: {e}")
|
||||
return False
|
||||
|
||||
def send_command(self, command):
|
||||
"""Send command to RP2040"""
|
||||
try:
|
||||
self.ser.write(f"{command}\n".encode())
|
||||
time.sleep(0.5)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error sending command: {e}")
|
||||
return False
|
||||
|
||||
def read_response(self):
|
||||
"""Read response from serial port"""
|
||||
try:
|
||||
response = ""
|
||||
while self.ser.in_waiting:
|
||||
response += self.ser.read(self.ser.in_waiting).decode(errors='ignore')
|
||||
time.sleep(0.1)
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"Error reading response: {e}")
|
||||
return ""
|
||||
|
||||
def extract_log_content(self, raw_response):
|
||||
"""Extract content between markers"""
|
||||
start_marker = "=== Key Log Start ==="
|
||||
end_marker = "=== End of Log ==="
|
||||
|
||||
start_idx = raw_response.find(start_marker)
|
||||
end_idx = raw_response.find(end_marker)
|
||||
|
||||
if start_idx == -1 or end_idx == -1:
|
||||
return None
|
||||
|
||||
# Extract content between markers
|
||||
content = raw_response[start_idx + len(start_marker):end_idx].strip()
|
||||
return content
|
||||
|
||||
def cleanup_log(self, raw_log):
|
||||
"""
|
||||
Clean up log by processing special character representations:
|
||||
- [BACKSPACE]: Remove previous character
|
||||
- [TAB]: Remove the tab (skip it)
|
||||
- [SPACE]: Convert to actual space character
|
||||
- [ENTER]: Remove the enter (skip it)
|
||||
"""
|
||||
cleaned = ""
|
||||
i = 0
|
||||
|
||||
while i < len(raw_log):
|
||||
# Check for special key patterns
|
||||
if raw_log[i:i+11] == "[BACKSPACE]":
|
||||
# Delete previous character if it exists
|
||||
if cleaned:
|
||||
cleaned = cleaned[:-1]
|
||||
i += 11
|
||||
elif raw_log[i:i+5] == "[TAB]":
|
||||
# Skip tabs
|
||||
i += 5
|
||||
elif raw_log[i:i+7] == "[SPACE]":
|
||||
# Convert to actual space
|
||||
cleaned += " "
|
||||
i += 7
|
||||
elif raw_log[i:i+7] == "[ENTER]":
|
||||
# Skip enters
|
||||
i += 7
|
||||
else:
|
||||
# Regular character
|
||||
cleaned += raw_log[i]
|
||||
i += 1
|
||||
|
||||
return cleaned.strip()
|
||||
|
||||
def read_log_raw(self):
|
||||
"""Option 1: Read and print raw log"""
|
||||
print("\nReading RAW Log...")
|
||||
print("-" * 50)
|
||||
|
||||
if not self.send_command("DUMP"):
|
||||
return
|
||||
|
||||
response = self.read_response()
|
||||
|
||||
if response:
|
||||
print(response)
|
||||
else:
|
||||
print("No response received")
|
||||
|
||||
print("-" * 50)
|
||||
self.wait_for_continue()
|
||||
|
||||
def read_log_clean(self):
|
||||
"""Option 2: Read and print cleaned log"""
|
||||
print("\nReading Cleaned Log...")
|
||||
print("-" * 50)
|
||||
|
||||
if not self.send_command("DUMP"):
|
||||
return
|
||||
|
||||
response = self.read_response()
|
||||
|
||||
if response:
|
||||
# Extract log content
|
||||
log_content = self.extract_log_content(response)
|
||||
|
||||
if log_content:
|
||||
# Clean up the log
|
||||
cleaned = self.cleanup_log(log_content)
|
||||
print("Cleaned Log:")
|
||||
print(cleaned)
|
||||
else:
|
||||
print("Could not find log markers in response")
|
||||
print("Raw response:")
|
||||
print(response)
|
||||
else:
|
||||
print("No response received")
|
||||
|
||||
print("-" * 50)
|
||||
self.wait_for_continue()
|
||||
|
||||
def clear_log(self):
|
||||
"""Option 3: Clear the log"""
|
||||
print("\nClearing Log...")
|
||||
print("-" * 50)
|
||||
|
||||
confirm = input("Are you sure you want to clear the log? (yes/no): ").strip().lower()
|
||||
|
||||
if confirm not in ['yes', 'y']:
|
||||
print("Clear cancelled")
|
||||
self.wait_for_continue()
|
||||
return
|
||||
|
||||
if not self.send_command("CLEAR"):
|
||||
return
|
||||
|
||||
response = self.read_response()
|
||||
|
||||
if response:
|
||||
print("Response from controller:")
|
||||
print(response)
|
||||
else:
|
||||
print("Clear command sent (no response)")
|
||||
|
||||
print("-" * 50)
|
||||
self.wait_for_continue()
|
||||
|
||||
def disconnect(self):
|
||||
"""Close serial connection"""
|
||||
if self.ser and self.ser.is_open:
|
||||
self.ser.close()
|
||||
print("Disconnected")
|
||||
|
||||
def show_menu(self):
|
||||
"""Display main menu"""
|
||||
print("\n" + "="*50)
|
||||
print(" RP2040 Log Reader")
|
||||
print("="*50)
|
||||
print("1. Read Log (RAW)")
|
||||
print("2. Read Log (Cleaned)")
|
||||
print("3. Clear Log")
|
||||
print("4. Exit")
|
||||
print("="*50)
|
||||
|
||||
def run(self):
|
||||
"""Main program loop"""
|
||||
# Connect to serial port
|
||||
if not self.connect():
|
||||
return
|
||||
|
||||
try:
|
||||
while True:
|
||||
self.clear_screen()
|
||||
self.show_menu()
|
||||
choice = input("Select option (1-4): ").strip()
|
||||
|
||||
# Immediately clear screen after selection
|
||||
self.clear_screen()
|
||||
|
||||
if choice == "1":
|
||||
self.read_log_raw()
|
||||
elif choice == "2":
|
||||
self.read_log_clean()
|
||||
elif choice == "3":
|
||||
self.clear_log()
|
||||
elif choice == "4":
|
||||
print("\nGoodbye!")
|
||||
break
|
||||
else:
|
||||
print("Invalid choice, please try again")
|
||||
time.sleep(1)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nProgram interrupted")
|
||||
|
||||
finally:
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
reader = RP2040LogReader()
|
||||
reader.run()
|
||||
Reference in New Issue
Block a user