# I seems I need a hash here for Instuctables to accept it.

'''
    This is for a microcontroller using Micro Python.
    Written by Tim Jackson.1960
    
    Breef:
        Take readings from a rotational sensor AS5600 Analog output.
        Sensor is fixed to a rotating table.
        Two buttons to change a value.
        A display to show a point which is a division of a circle by the value set.
        The display is connected via the second SPI and has a SH1107 driver.
    
    Support files:
        lib>
            sh1107.py
            framebuf2.py
        Logo.py

'''

from machine import ADC, Pin, SPI
from Logo import logo
import sh1107
import framebuf2
import time

# Initialize SPI
spi = SPI(1, baudrate=20000000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11))
# Initialize OLED
oled = sh1107.SH1107_SPI(128, 64, spi, dc=Pin(8), res=Pin(12), cs=Pin(9))
# Initialize the ADC
adc = ADC(Pin(28))  # Pin connected to the OUT pin of the AS5600
# Initialize the value
Button_value = 2
# Initialize the Position
Position = 0
# Initialize the In_Position flag
In_Position = False
# Initialize the Display_NO flag
Display_NO = False

# Define the button pressed callbacks
def button0_pressed(pin):
    global Button_value
    Button_value -= 1
    if Button_value < 2:
        Button_value = 2
    update_display()

def button1_pressed(pin):
    global Button_value
    Button_value += 1
    update_display()

# Initialize the buttons
button0 = Pin(15, Pin.IN, Pin.PULL_UP)
button0.irq(trigger=Pin.IRQ_FALLING, handler=button0_pressed)
button1 = Pin(17, Pin.IN, Pin.PULL_UP)
button1.irq(trigger=Pin.IRQ_FALLING, handler=button1_pressed)

# Draw the image
def Draw_Image(image, width, height):
    for y in range(height):
        for x in range(width):
            byte = image[(y // 8) * width + x]
            bit = byte & (1 << (y % 8))
            oled.pixel(x, y, bit > 0)
    
def update_display():
    global In_Position, Button_value, Display_NO, Position
    # Convert the value to a string
    str_Button_value = str(Button_value)
        
    # Read the analog value
    value = adc.read_u16()

    # Convert the 16-bit ADC value to degrees
    degrees = (value * 360) / 65535
           
    # Check if degrees is within +/- 2 of a division point
    division = 360 / Button_value
    # Calculate which position
    Position = round(degrees / division)
    remainder = degrees % division
    if remainder <= 2 or remainder >= division - 2:
        In_Position = True
        Display_NO = False
    elif 2 < remainder < division/3 or 2*division/3 < remainder < division - 2:
        In_Position = False
        Display_NO = False
    else:
        Display_NO = True

    # Convert the degrees to a string with 1 decimal place
    str_degrees = "{:.1f}".format(degrees)

    # Convert the Position to a string
    str_Position = "{}/{}".format(Position, Button_value)

    # Estimate the width of the text
    text_width_degrees = len(str_degrees) * 8 * 1  # 8 pixels/character, 1x size
    text_width_position = len(str_Position) * 8 * 1  # 8 pixels/character, 1x size

    # Calculate the x position for right alignment
    x_pos_degrees = 128 - text_width_degrees  # 128 is the width of the screen
    x_pos_position = 128 - text_width_position  # 128 is the width of the screen

    # Clear the display
    oled.fill(0)
    
    # Display "OK" if In_Position is True, otherwise display ">>>>" or "<<<<"
    if In_Position:
        oled.large_text("CUT", 16, 36, 4, 1)  # Display "CUT"
    elif Display_NO:
        oled.large_text("<NO>", 0, 36, 4, 1)  # Display "<NO>"
    elif degrees > (division * round(degrees / division)):
        oled.large_text(">>>>", 0, 36, 4, 1)  # Display ">>>>"
    elif degrees < (division * round(degrees / division)):
        oled.large_text("<<<<", 0, 36, 4, 1)  # Display "<<<<"
    
    # Display Button value
    oled.large_text(str_Button_value, 0, 0, 4, 1)  # set size (x2) text

    # Display the degrees
    oled.large_text(str_degrees, x_pos_degrees, 0, 1, 1)  # set size (x1) text

    # Display the position
    oled.large_text(str_Position, x_pos_position, 10, 1, 1)  # set size (x1) text

    oled.show()

# Clear the display
oled.fill(0)
# Draw the logo
Draw_Image(logo, 48, 64)
# Display the degrees
oled.large_text("Tim's", 48, 4, 2, 1)  # set size (x2) text
oled.large_text("Pie", 60, 26, 1, 1)  # set size (x1) text
oled.large_text("Divider", 60, 36, 1, 1)  # set size (x1) text
oled.large_text("Ver. 1.0", 65, 56, 1, 1)  # set size (x1) text
oled.show()
# Wait for 2 seconds
time.sleep(4)

while True:
    update_display()
    time.sleep(0.2)
