#!/usr/bin/env python3 """ Lua Game Uploader for RP2350 Rapidly upload and execute Lua games via USB serial for quick iteration. Usage: python upload_game.py [serial_port] Example: python upload_game.py my_game.lua /dev/ttyACM0 python upload_game.py my_game.lua COM3 """ import sys import os import base64 import serial import time from pathlib import Path def find_serial_port(): """Auto-detect the RP2350 serial port""" import serial.tools.list_ports # Look for Pico/RP2350 devices ports = list(serial.tools.list_ports.comports()) for port in ports: # Common VID/PID for Raspberry Pi Pico if 'Pico' in port.description or \ 'RP2350' in port.description or \ 'RP2040' in port.description or \ (port.vid == 0x2E8A): # Raspberry Pi VID return port.device # Fallback: return first available port if ports: print(f"Warning: Could not find RP2350, using first available port: {ports[0].device}") return ports[0].device return None def upload_game(lua_file, serial_port=None): """Upload a Lua game file to the RP2350 and execute it""" # Check if file exists if not os.path.exists(lua_file): print(f"Error: File '{lua_file}' not found") return False # Read the file with open(lua_file, 'rb') as f: file_data = f.read() file_size = len(file_data) filename = os.path.basename(lua_file) # Ensure filename has .lua extension if not filename.endswith('.lua'): filename += '.lua' print(f"Uploading {filename} ({file_size} bytes)...") # Auto-detect serial port if not provided if serial_port is None: serial_port = find_serial_port() if serial_port is None: print("Error: No serial port found. Please specify manually.") return False print(f"Using serial port: {serial_port}") try: # Open serial connection ser = serial.Serial(serial_port, 115200, timeout=5) time.sleep(0.1) # Wait for connection to stabilize # Encode file data as base64 base64_data = base64.b64encode(file_data).decode('ascii') # Send upload command command = f"UPLOAD {filename} {file_size}\n" print(f"Sending command: {command.strip()}") ser.write(command.encode('ascii')) # Send base64-encoded file data print("Sending file data...") ser.write(base64_data.encode('ascii')) ser.write(b'\n') # Send END marker ser.write(b'END\n') print("Upload complete, waiting for confirmation...") # Read response from device start_time = time.time() response_lines = [] while time.time() - start_time < 10: # 10 second timeout if ser.in_waiting > 0: line = ser.readline().decode('utf-8', errors='ignore').strip() if line: print(f" << {line}") response_lines.append(line) # Check for success if line.startswith('OK'): print(f"✓ File written successfully!") if line.startswith('LAUNCHED'): game_name = line.split(' ', 1)[1] if ' ' in line else filename print(f"✓ Game '{game_name}' launched!") ser.close() return True # Check for error if line.startswith('ERROR'): print(f"✗ Upload failed: {line}") ser.close() return False print("Warning: No response received from device") ser.close() return False except serial.SerialException as e: print(f"Serial error: {e}") return False except Exception as e: print(f"Unexpected error: {e}") return False def main(): if len(sys.argv) < 2: print(__doc__) print("\nAvailable serial ports:") try: import serial.tools.list_ports for port in serial.tools.list_ports.comports(): print(f" {port.device}: {port.description}") except ImportError: print(" (install pyserial to see available ports)") sys.exit(1) lua_file = sys.argv[1] serial_port = sys.argv[2] if len(sys.argv) > 2 else None success = upload_game(lua_file, serial_port) sys.exit(0 if success else 1) if __name__ == '__main__': main()