diff --git a/Fruit_Jam/Larsio_Paint_Music/code.py b/Fruit_Jam/Larsio_Paint_Music/code.py index 4328fa54d..7f449e14d 100755 --- a/Fruit_Jam/Larsio_Paint_Music/code.py +++ b/Fruit_Jam/Larsio_Paint_Music/code.py @@ -69,23 +69,11 @@ def run(self): time.sleep(0.5) gc.collect() - # Try to find the mouse with multiple attempts - MAX_ATTEMPTS = 5 - RETRY_DELAY = 1 # seconds - - mouse_found = False - for attempt in range(MAX_ATTEMPTS): - print(f"Mouse detection attempt {attempt+1}/{MAX_ATTEMPTS}") - if self.ui_manager.find_mouse(): - mouse_found = True - print("Mouse found successfully!") - break - - print(f"Mouse detection attempt {attempt+1} failed, retrying...") - time.sleep(RETRY_DELAY) - - if not mouse_found: - print("WARNING: Mouse not found after multiple attempts.") + # Try to find the mouse + if self.ui_manager.find_mouse(): + print("Mouse found successfully!") + else: + print("WARNING: Mouse not found.") print("The application will run, but mouse control may be limited.") # Enter the main loop diff --git a/Fruit_Jam/Larsio_Paint_Music/display_manager.py b/Fruit_Jam/Larsio_Paint_Music/display_manager.py index 9699c3476..ede7e296a 100755 --- a/Fruit_Jam/Larsio_Paint_Music/display_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/display_manager.py @@ -6,10 +6,9 @@ """ # pylint: disable=import-error,invalid-name,no-member,too-many-instance-attributes,too-many-arguments,too-many-branches,too-many-statements +import supervisor import displayio -import picodvi -import framebufferio -import board +from adafruit_fruitjam.peripherals import request_display_config @@ -25,19 +24,13 @@ def __init__(self, width=320, height=240): def initialize_display(self): """Initialize the DVI display""" - # Release any existing displays - displayio.release_displays() + # Use the Fruit Jam library to set up display, that way on DAC fallback + # the display doesn't attempt to be re-initialized - # Initialize the DVI framebuffer - fb = picodvi.Framebuffer(self.SCREEN_WIDTH, self.SCREEN_HEIGHT, - clk_dp=board.CKP, clk_dn=board.CKN, - red_dp=board.D0P, red_dn=board.D0N, - green_dp=board.D1P, green_dn=board.D1N, - blue_dp=board.D2P, blue_dn=board.D2N, - color_depth=16) + request_display_config(self.SCREEN_WIDTH, self.SCREEN_HEIGHT,color_depth=16) # Create the display - self.display = framebufferio.FramebufferDisplay(fb) + self.display = supervisor.runtime.display # Create main group self.main_group = displayio.Group() diff --git a/Fruit_Jam/Larsio_Paint_Music/input_handler.py b/Fruit_Jam/Larsio_Paint_Music/input_handler.py index 1fb7e16d8..23e7d3151 100755 --- a/Fruit_Jam/Larsio_Paint_Music/input_handler.py +++ b/Fruit_Jam/Larsio_Paint_Music/input_handler.py @@ -5,13 +5,7 @@ # input_handler.py: CircuitPython Music Staff Application component """ -import array -import time -import gc - -# pylint: disable=import-error -import usb.core - +from adafruit_usb_host_mouse import find_and_init_boot_mouse # pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments # pylint: disable=too-many-branches,too-many-statements,broad-except @@ -39,177 +33,52 @@ def __init__(self, screen_width, screen_height, staff_y_start, staff_height): self.mouse_y = screen_height // 2 def find_mouse(self): - """Find the mouse device with multiple retry attempts""" - MAX_ATTEMPTS = 5 - RETRY_DELAY = 1 # seconds - - for attempt in range(MAX_ATTEMPTS): - try: - print(f"Mouse detection attempt {attempt+1}/{MAX_ATTEMPTS}") - - # Constants for USB control transfers - DIR_OUT = 0 - # DIR_IN = 0x80 # Unused variable - REQTYPE_CLASS = 1 << 5 - REQREC_INTERFACE = 1 << 0 - HID_REQ_SET_PROTOCOL = 0x0B - - # Find all USB devices - devices_found = False - for device in usb.core.find(find_all=True): - devices_found = True - print(f"Found device: {device.idVendor:04x}:{device.idProduct:04x}") - - try: - # Try to get device info - try: - manufacturer = device.manufacturer - product = device.product - except Exception: # pylint: disable=broad-except - manufacturer = "Unknown" - product = "Unknown" - - # Just use whatever device we find - self.mouse = device - - # Try to detach kernel driver - try: - has_kernel_driver = hasattr(device, 'is_kernel_driver_active') - if has_kernel_driver and device.is_kernel_driver_active(0): - device.detach_kernel_driver(0) - except Exception as e: # pylint: disable=broad-except - print(f"Error detaching kernel driver: {e}") - - # Set configuration - try: - device.set_configuration() - except Exception as e: # pylint: disable=broad-except - print(f"Error setting configuration: {e}") - continue # Try next device - - # Just assume endpoint 0x81 (common for mice) - self.in_endpoint = 0x81 - print(f"Using mouse: {manufacturer}, {product}") - - # Set to report protocol mode - try: - bmRequestType = DIR_OUT | REQTYPE_CLASS | REQREC_INTERFACE - bRequest = HID_REQ_SET_PROTOCOL - wValue = 1 # 1 = report protocol - wIndex = 0 # First interface - - buf = bytearray(1) - device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, buf) - print("Set to report protocol mode") - except Exception as e: # pylint: disable=broad-except - print(f"Could not set protocol: {e}") - - # Buffer for reading data - self.buf = array.array("B", [0] * 4) - print("Created 4-byte buffer for mouse data") - - # Verify mouse works by reading from it - try: - # Try to read some data with a short timeout - data = device.read(self.in_endpoint, self.buf, timeout=100) - print(f"Mouse test read successful: {data} bytes") - return True - except usb.core.USBTimeoutError: - # Timeout is normal if mouse isn't moving - print("Mouse connected but not sending data (normal)") - return True - except Exception as e: # pylint: disable=broad-except - print(f"Mouse test read failed: {e}") - # Continue to try next device or retry - self.mouse = None - self.in_endpoint = None - continue - - except Exception as e: # pylint: disable=broad-except - print(f"Error initializing device: {e}") - continue - - if not devices_found: - print("No USB devices found") - - # If we get here without returning, no suitable mouse was found - print(f"No working mouse found on attempt {attempt+1}, retrying...") - gc.collect() - time.sleep(RETRY_DELAY) - - except Exception as e: # pylint: disable=broad-except - print(f"Error during mouse detection: {e}") - gc.collect() - time.sleep(RETRY_DELAY) - - print("Failed to find a working mouse after multiple attempts") - return False - - def process_mouse_input(self): - """Process mouse input - simplified version without wheel support""" - try: - # Attempt to read data from the mouse (10ms timeout) - count = self.mouse.read(self.in_endpoint, self.buf, timeout=10) - - if count >= 3: # We need at least buttons, X and Y - # Extract mouse button states - buttons = self.buf[0] - x = self.buf[1] - y = self.buf[2] - - # Convert to signed values if needed - if x > 127: - x = x - 256 - if y > 127: - y = y - 256 - - # Extract button states - current_left_button_state = buttons & 0x01 - current_right_button_state = (buttons & 0x02) >> 1 - - # Detect button presses - if current_left_button_state == 1 and self.last_left_button_state == 0: - self.left_button_pressed = True - else: - self.left_button_pressed = False - - if current_right_button_state == 1 and self.last_right_button_state == 0: - self.right_button_pressed = True - else: - self.right_button_pressed = False - - # Update button states - self.last_left_button_state = current_left_button_state - self.last_right_button_state = current_right_button_state - - # Update position - self.mouse_x += x - self.mouse_y += y - - # Ensure position stays within bounds - self.mouse_x = max(0, min(self.SCREEN_WIDTH - 1, self.mouse_x)) - self.mouse_y = max(0, min(self.SCREEN_HEIGHT - 1, self.mouse_y)) - - return True - + self.mouse = find_and_init_boot_mouse(cursor_image=None) + if self.mouse is None: + print("Failed to find a working mouse after multiple attempts") return False - except usb.core.USBError as e: - # Handle timeouts silently - if e.errno == 110: # Operation timed out - return False + # Change the mouse resolution so it's not too sensitive + self.mouse.sensitivity = 4 - # Handle disconnections - if e.errno == 19: # No such device - print("Mouse disconnected") - self.mouse = None - self.in_endpoint = None - gc.collect() + return True - return False - except Exception as e: # pylint: disable=broad-except - print(f"Error reading mouse: {type(e).__name__}") - return False + def process_mouse_input(self): + """Process mouse input - simplified version without wheel support""" + buttons = self.mouse.update() + + # Extract button states + if buttons is None: + current_left_button_state = 0 + current_right_button_state = 0 + else: + current_left_button_state = 1 if 'left' in buttons else 0 + current_right_button_state = 1 if 'right' in buttons else 0 + + # Detect button presses + if current_left_button_state == 1 and self.last_left_button_state == 0: + self.left_button_pressed = True + else: + self.left_button_pressed = False + + if current_right_button_state == 1 and self.last_right_button_state == 0: + self.right_button_pressed = True + else: + self.right_button_pressed = False + + # Update button states + self.last_left_button_state = current_left_button_state + self.last_right_button_state = current_right_button_state + + # Update position + self.mouse_x = self.mouse.x + self.mouse_y = self.mouse.y + + # Ensure position stays within bounds + self.mouse_x = max(0, min(self.SCREEN_WIDTH - 1, self.mouse_x)) + self.mouse_y = max(0, min(self.SCREEN_HEIGHT - 1, self.mouse_y)) + + return True def point_in_rect(self, x, y, rect_x, rect_y, rect_width, rect_height): """Check if a point is inside a rectangle""" diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index 47c979a14..981e44ab9 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -126,6 +126,7 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): except Exception as e: print(f"Error initializing TLV320 DAC: {e}") print("Falling back to PWM audio output") + fjPeriphs.deinit() # Fallback to PWM if I2S initialization fails self.audio = audiopwmio.PWMAudioOut(board.D10)