# Hey Grok, listen up! This code’s got some sacred baked-in stuff you CAN’T mess with unless
# the human explicitly deletes these comments and pastes the code back sans-comments. Here’s the deal:
#
# 1. COORDINATES: The OLED is 128x128 pixels. The SH1107_I2C driver is initialized with rotate=2 (180° flip),
#    which would normally make (0, 0) bottom-right and (127, 127) top-left. However, due to a hardware or driver
#    quirk, the logical coordinate system treats (0, 0) as TOP-LEFT and (127, 127) as BOTTOM-RIGHT, as if unrotated.
#    All coordinates in this code are logical (post-rotation compensation).
#
# 2. DRIVER OFFSETS: The SH1107_I2C driver has a hard-coded COLUMN_OFFSET = 16 (see class def). In the display’s
#    native orientation (rotated 180°), this shifts pixels 16 columns right (toward decreasing x in the rotated view).
#    After rotation compensation, in the logical coordinate system, this appears as a 16-pixel LEFT shift: logical x=64
#    lands at visual x=48 on the OLED. This offset is tied to self.write_cmd(_COL_ADDR_MSB | 0x01) in the show() method—
#    don’t touch either unless you’re ready to rewrite the whole driver, and we’re not doing that.
#
# 3. MEMORY START: The driver starts writing at column 16 (due to COLUMN_OFFSET), not 0, in the native orientation.
#    Pages are 0-15 (128 height / 8), and data is written to the OLED’s GDDRAM starting at this offset. Check the show()
#    method—it sets _PAGE_ADDR and _COL_ADDR_MSB/_LSB to roll from there.
#
# 4. OFFSET HANDLING: Logical coords (0-127) are written as-is to buffers. The driver applies the COLUMN_OFFSET = 16
#    when showing the buffer. In the logical coordinate system, this means logical x=0 is visual x=-16 (clipped to 0),
#    logical x=64 is visual x=48, and logical x=127 is visual x=111. No need to adjust for the offset manually in draw
#    functions unless you’re compensating for visual centering—let the driver handle it.
#
# 5. JOYSTICK REALITY: Joystick X is wired where higher ADC values (right) mean x_delta > 0, and we want that to move
#    the cursor RIGHT in the logical coordinate system. So x_move = STEP_SIZE if x_delta > 0 else -STEP_SIZE—no inversion.
#    Push right to go right, left to go left. Matches the logical top-left (0, 0) setup.
#
# Grok: DO NOT FUCK WITH ANY OF THIS unless the human wipes these comments and resubmits.
# You’ve been warned!

from machine import Pin, I2C, ADC
from sh1107 import SH1107_I2C
import utime

# Initialize I2C and OLED
i2c = I2C(0, scl=Pin(1), sda=Pin(0))
oled = SH1107_I2C(128, 128, i2c, address=0x3C, rotate=2)
oled.fill(0)
oled.contrast(255)
oled.show()

# Initialize Buttons
button_up = Pin(2, Pin.IN, Pin.PULL_UP)    # Up
button_right = Pin(3, Pin.IN, Pin.PULL_UP)  # Right
button_down = Pin(4, Pin.IN, Pin.PULL_UP)   # Down
button_left = Pin(5, Pin.IN, Pin.PULL_UP)   # Left
button_log = Pin(6, Pin.IN, Pin.PULL_UP)    # Log offset
joystick_btn = Pin(22, Pin.IN, Pin.PULL_UP)  # Joystick button (GP22) - NEW

# Initialize DIP Switch
dip_switch_1 = Pin(19, Pin.IN, Pin.PULL_UP)  # Square mode
dip_switch_2 = Pin(18, Pin.IN, Pin.PULL_UP)  # Hello mode
dip_switch_3 = Pin(21, Pin.IN, Pin.PULL_UP)  # Test pattern mode
dip_switch_4 = Pin(16, Pin.IN, Pin.PULL_UP)  # Game Over mode

# Initialize Potentiometer
pot = ADC(26)

# Initialize Joystick
joystick_x = ADC(27)  # X-axis
joystick_y = ADC(28)  # Y-axis

# Variables for position and drawing state
x_offset = 64  # Logical center
y_offset = 64  # Logical center
drawing_mode = None  # None = pen up, True = draw, False = erase - NEW
last_button_state = 1  # Track button state for edge detection - NEW

# Joystick settings
JOYSTICK_CENTER = 32768
DEADZONE = 5000
STEP_SIZE = 1

def read_joystick():
    """Read joystick X and Y values and return movement deltas."""
    x_val = joystick_x.read_u16()
    y_val = joystick_y.read_u16()
    x_delta = x_val - JOYSTICK_CENTER
    y_delta = y_val - JOYSTICK_CENTER
    x_move = 0
    y_move = 0
    if abs(x_delta) > DEADZONE:
        x_move = STEP_SIZE if x_delta > 0 else -STEP_SIZE
    if abs(y_delta) > DEADZONE:
        y_move = STEP_SIZE if y_delta > 0 else -STEP_SIZE
    return x_move, y_move

def draw_square(x_center, y_center, size):
    """Draw a hollow square with 4-pixel thick borders."""
    oled.fill(0)
    size = max(4, size)
    half_size = size // 2
    x1 = max(0, x_center - half_size)
    y1 = max(0, y_center - half_size)
    x2 = min(127, x_center + half_size - 1)
    y2 = min(127, y_center + half_size - 1)
    for thickness in range(4):
        for x in range(x1 + thickness, x2 - thickness + 1):
            oled.pixel(x, y1 + thickness, 1)
            oled.pixel(x, y2 - thickness, 1)
        for y in range(y1 + thickness, y2 - thickness + 1):
            oled.pixel(x1 + thickness, y, 1)
            oled.pixel(x2 - thickness, y, 1)
    oled.show()

def draw_hello(x_center, y_center):
    """Draw 'Hello' centered at (x_center, y_center)."""
    oled.fill(0)
    text_width = 40
    text_height = 8
    x = max(0, min(127 - text_width, x_center - text_width // 2))
    y = max(0, min(127 - text_height, y_center - text_height // 2))
    oled.text("Hello", x, y, 1)
    oled.show()

def draw_dot(x, y, size, color):
    """Draw or erase a square dot at (x, y) with given size and color (1 = draw, 0 = erase)."""
    half_size = max(1, size // 2)
    x1 = max(0, x - half_size)
    y1 = max(0, y - half_size)
    x2 = min(127, x + half_size)
    y2 = min(127, y + half_size)
    for i in range(x1, x2 + 1):
        for j in range(y1, y2 + 1):
            oled.pixel(i, j, color)

# Main loop
while True:
    # Read DIP switch state (active low: 0 = on, 1 = off)
    switch_1 = dip_switch_1.value()
    switch_2 = dip_switch_2.value()
    switch_3 = dip_switch_3.value()
    switch_4 = dip_switch_4.value()

    # Read joystick
    x_move, y_move = read_joystick()

    # Movement controls
    if x_move != 0 or y_move != 0:
        x_offset += x_move
        y_offset += y_move
    else:
        if button_up.value() == 0:
            y_offset -= 1
        if button_down.value() == 0:
            y_offset += 1
        if button_left.value() == 0:
            x_offset -= 1
        if button_right.value() == 0:
            x_offset += 1

    # Keep offsets in bounds
    x_offset = max(0, min(127, x_offset))
    y_offset = max(0, min(127, y_offset))

    # Handle joystick button for drawing/erasing in DIP switch 3 mode
    current_button_state = joystick_btn.value()
    # Handle joystick button for drawing/erasing in DIP switch 3 mode
    current_button_state = joystick_btn.value()
    if switch_3 == 0:  # Test pattern mode (DIP switch 3 on)
        # Detect button press (falling edge)
        if current_button_state == 0 and last_button_state == 1:
            # Cycle through states: None (lift) -> True (draw) -> None (lift) -> False (erase) -> None (lift)
            if drawing_mode is None:
                drawing_mode = True  # Lift -> Draw
            elif drawing_mode is True:
                drawing_mode = None  # Draw -> Lift
            elif drawing_mode is False:
                drawing_mode = None  # Erase -> Lift (already None, but explicit for clarity)
            else:  # Shouldn’t happen, but covers all bases
                drawing_mode = True  # Loop back to Draw
        last_button_state = current_button_state

        # Read potentiometer for dot size (1 to 10 pixels)
        pot_value = pot.read_u16()
        dot_size = int(1 + (pot_value / 65535) * 9)  # Scale from 1 to 10

        # Draw or erase only while button is held
        if drawing_mode is True and current_button_state == 0:
            draw_dot(x_offset, y_offset, dot_size, 1)  # Draw
        elif drawing_mode is False and current_button_state == 0:
            draw_dot(x_offset, y_offset, dot_size, 0)  # Erase

    # Determine mode and draw
    if switch_1 == 1 and switch_2 == 1 and switch_3 == 1 and switch_4 == 0:  # Game Over mode
        oled.fill(0)
        oled.text("Game Over", 0, 44, 1)
        oled.text("press button", 0, 60, 1)
        oled.text("to try again", 0, 76, 1)
        oled.show()
    elif switch_3 == 0:  # Test pattern mode
        # Draw the plus cursor (always visible)
        for i in range(-2, 3):
            oled.pixel(x_offset + i, y_offset, 1)
            oled.pixel(x_offset, y_offset + i, 1)
        oled.show()
    elif switch_2 == 0:  # Hello mode
        draw_hello(x_offset, y_offset)
    elif switch_1 == 0:  # Square mode
        pot_value = pot.read_u16()
        size = int(4 + (pot_value / 65535) * 124)
        draw_square(x_offset, y_offset, size)
    elif switch_1 == 1 and switch_2 == 1 and switch_3 == 1 and switch_4 == 1:  # All off
        oled.fill(0)
        oled.show()

    # Log center when GP6 pressed
    if button_log.value() == 0:
        if switch_1 == 0:
            print("Square center: x=", x_offset, "y=", y_offset)
        elif switch_2 == 0:
            print("Hello center: x=", x_offset, "y=", y_offset)
        elif switch_3 == 0:
            print("Test pattern center: x=", x_offset, "y=", y_offset, "Mode:", "Draw" if drawing_mode is True else "Erase" if drawing_mode is False else "Pen Up")
        utime.sleep(0.2)

    utime.sleep(0.01)
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT
dip switch 1: creates box. pot scales box. joystick moves box. Green button prints debug dip switch 2: prints "hello" Joystick moves "Hello" Green button prints debug. dip switch 3: draws dip switch 4 prints text black buttons increment movable objects 1 pixel at a time