Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions Fruit_Jam/Larsio_Paint_Music/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 6 additions & 13 deletions Fruit_Jam/Larsio_Paint_Music/display_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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



Expand All @@ -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()
Expand Down
217 changes: 43 additions & 174 deletions Fruit_Jam/Larsio_Paint_Music/input_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"""
Expand Down
1 change: 1 addition & 0 deletions Fruit_Jam/Larsio_Paint_Music/sound_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down