import serial import time from serial.tools import list_ports VENDOR_ID = 0x1A86 # CH340 PRODUCT_ID = 0x7523 # CH340 class SMDController: def __init__(self, port=None, baudrate=921600): """ Initialize SMD Controller with serial communication. If 'port' is None, we'll try auto-detect via VID/PID. """ self.port = port self.baudrate = baudrate self.serial_conn = None # Static commands that don't need user input self.static_commands = { 1: "WelcomeScreen**bonrix", 3: "DisplayFailQRCodeScreen**1234567890**ORD10594565**29-03-2023**10", 4: "DisplayCancelQRCodeScreen**1234567890**ORD10594565**29-03-2023**10", } @staticmethod def find_port_by_vid_pid(vid, pid): """ Scan available serial ports and return the first one matching VID/PID. Returns the device name (e.g., 'COM5' on Windows or '/dev/ttyUSB0' on Linux), or None if not found. """ for p in list_ports.comports(): # On most systems p.vid and p.pid exist; fall back to checking hwid if needed. if (getattr(p, "vid", None) == vid) and (getattr(p, "pid", None) == pid): return p.device # Fallback: parse HWID string if vid/pid attributes not populated if p.hwid: hwid = p.hwid.upper() if f"VID_{vid:04X}" in hwid and f"PID_{pid:04X}" in hwid: return p.device return None def connect(self): """Establish serial connection""" try: self.serial_conn = serial.Serial( port=self.port, baudrate=self.baudrate, timeout=1, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, ) # Optional: stabilize some CH340 boards on Windows self.serial_conn.reset_input_buffer() self.serial_conn.reset_output_buffer() print(f"Connected to {self.port} at {self.baudrate} baud") return True except serial.SerialException as e: print(f"Error connecting to {self.port}: {e}") return False def disconnect(self): """Close serial connection""" if self.serial_conn and self.serial_conn.is_open: self.serial_conn.close() print("Serial connection closed") def send_command(self, command): """Send command via serial connection""" if not self.serial_conn or not self.serial_conn.is_open: print("Error: Serial connection not established") return False try: command_with_newline = command + "\n" self.serial_conn.write(command_with_newline.encode("utf-8")) print(f"Command sent: {command}") time.sleep(0.1) if self.serial_conn.in_waiting: response = self.serial_conn.readline().decode("utf-8", "ignore").strip() if response: print(f"Response: {response}") return True except Exception as e: print(f"Error sending command: {e}") return False def get_success_command(self): """Get success command with user input for amount""" try: amount = input("Enter amount in rupees (e.g., 10, 50, 100): ").strip() if not amount.isdigit(): print("Invalid amount. Please enter a valid number.") return None return f"DisplaySuccessQRCodeScreen**1234567890**ORD10594565**29-03-2023**{amount}" except KeyboardInterrupt: print("\nOperation cancelled.") return None def get_qr_command(self): """Get QR code command with user input for UPI details""" try: upi_id = input("Enter UPI ID (e.g., 63270083167.payswiff@indus): ").strip() if not upi_id: print("UPI ID cannot be empty.") return None amount = input("Enter amount in rupees: ").strip() if not amount.isdigit(): print("Invalid amount. Please enter a valid number.") return None merchant_name = input("Enter merchant name (e.g., Bonrix): ").strip() or "Bonrix" upi_url = f"upi://pay?pa={upi_id}&pn={merchant_name}&cu=INR&am={amount}" return f"DisplayQRCodeScreen**{upi_url}**{amount}**{upi_id}" except KeyboardInterrupt: print("\nOperation cancelled.") return None def execute_command(self, input_number): """Execute command based on input number""" if input_number in self.static_commands: return self.send_command(self.static_commands[input_number]) if input_number == 2: cmd = self.get_success_command() return self.send_command(cmd) if cmd else False if input_number == 5: cmd = self.get_qr_command() return self.send_command(cmd) if cmd else False valid_inputs = list(self.static_commands.keys()) + [2, 5] print(f"Invalid input: {input_number}. Valid inputs are: {valid_inputs}") return False def show_menu(self): """Display available commands""" print("\n=== 7-inch SMD Controller ===") print("Available commands:") print("1. Welcome Screen") print("2. Success QR Code Screen (asks for amount)") print("3. Fail QR Code Screen") print("4. Cancel QR Code Screen") print("5. Payment QR Code Screen (asks for UPI ID, amount, merchant name)") print("0. Exit") print("================================") def main(): print("=== 7-inch SMD Controller Setup ===") # Auto-detect COM port by VID/PID auto_port = SMDController.find_port_by_vid_pid(VENDOR_ID, PRODUCT_ID) if auto_port: print(f"Auto-detected device: {auto_port} (VID=0x{VENDOR_ID:04X}, PID=0x{PRODUCT_ID:04X})") controller = SMDController(port=auto_port, baudrate=921600) else: print("No port matched the specified VID/PID.") # Show available ports to help user pick one ports = list(list_ports.comports()) if not ports: print("No serial ports found. Please connect your device and try again.") return print("Available ports:") for p in ports: print(f" - {p.device} | {p.description} | HWID={p.hwid}") # Fallback to manual input while True: try: com_port = input("Enter COM port (e.g., COM5 or /dev/ttyUSB0): ").strip() if com_port: break except KeyboardInterrupt: print("\nExiting...") return controller = SMDController(port=com_port, baudrate=921600) print(f"Attempting to connect to {controller.port} at {controller.baudrate} baud...") if not controller.connect(): print("Failed to connect. Please check:") print("1. Device is connected") print("2. Correct driver installed (CH340)") print("3. No other application is using the port") print("4. Permissions (on Linux: add user to 'dialout' or use udev rule)") return try: while True: controller.show_menu() try: user_input = input("\nEnter your choice (0-5): ").strip() if user_input == "0": print("Exiting...") break choice = int(user_input) if 1 <= choice <= 5: controller.execute_command(choice) else: print("Invalid choice. Please enter a number between 0-5.") except ValueError: print("Invalid input. Please enter a valid number.") except KeyboardInterrupt: print("\nExiting...") break except Exception as e: print(f"Unexpected error: {e}") finally: controller.disconnect() if __name__ == "__main__": main()