# https://luma-oled.readthedocs.io/en/latest/software.html

import os
import sys
import time
import threading
import usb4vc_oled
from luma.core.render import canvas
import RPi.GPIO as GPIO
import usb4vc_usb_scan
import usb4vc_shared
import usb4vc_show_ev
import usb4vc_check_update
import json
import subprocess
from subprocess import Popen, PIPE

from usb4vc_shared import this_app_dir_path
from usb4vc_shared import config_dir_path
from usb4vc_shared import firmware_dir_path
from usb4vc_shared import temp_dir_path
from usb4vc_shared import ensure_dir
from usb4vc_shared import i2c_bootloader_pbid
from usb4vc_shared import usb_bootloader_pbid

config_file_path = os.path.join(config_dir_path, 'config.json')

ensure_dir(this_app_dir_path)
ensure_dir(config_dir_path)
ensure_dir(firmware_dir_path)
ensure_dir(temp_dir_path)

PLUS_BUTTON_PIN = 27
MINUS_BUTTON_PIN = 19
ENTER_BUTTON_PIN = 22
SHUTDOWN_BUTTON_PIN = 21

PBOARD_RESET_PIN = 25
PBOARD_BOOT0_PIN = 12
SLEEP_LED_PIN = 26

GPIO.setmode(GPIO.BCM)
GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
GPIO.setup(PBOARD_BOOT0_PIN, GPIO.IN)
GPIO.setup(SLEEP_LED_PIN, GPIO.OUT)
GPIO.output(SLEEP_LED_PIN, GPIO.LOW)

SPI_MOSI_MAGIC = 0xde
SPI_MOSI_MSG_TYPE_SET_PROTOCOL = 2
set_protocl_spi_msg_template = [SPI_MOSI_MAGIC, 0, SPI_MOSI_MSG_TYPE_SET_PROTOCOL] + [0]*29

class my_button(object):
    def __init__(self, bcm_pin):
        super(my_button, self).__init__()
        self.pin_number = bcm_pin
        GPIO.setup(self.pin_number, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        self.prev_state = GPIO.input(self.pin_number)

    def is_pressed(self):
        result = False
        current_state = GPIO.input(self.pin_number)
        if self.prev_state == 1 and current_state == 0:
            result = True
        self.prev_state = current_state
        return result
        
PBOARD_ID_UNKNOWN = 0
PBOARD_ID_IBMPC = 1
PBOARD_ID_ADB = 2
pboard_info_spi_msg = [0] * 32
this_pboard_id = PBOARD_ID_UNKNOWN

USBGP_BTN_SOUTH = 0x130
USBGP_BTN_EAST = 0x131
USBGP_BTN_C = 0x132
USBGP_BTN_NORTH = 0x133
USBGP_BTN_WEST = 0x134
USBGP_BTN_Z = 0x135
USBGP_BTN_TL = 0x136
USBGP_BTN_TR = 0x137
USBGP_BTN_TL2 = 0x138
USBGP_BTN_TR2 = 0x139
USBGP_BTN_SELECT = 0x13a
USBGP_BTN_START = 0x13b
USBGP_BTN_MODE = 0x13c
USBGP_BTN_THUMBL = 0x13d
USBGP_BTN_THUMBR = 0x13e

USBGP_BTN_A = USBGP_BTN_SOUTH
USBGP_BTN_B = USBGP_BTN_EAST
USBGP_BTN_X = USBGP_BTN_NORTH
USBGP_BTN_Y = USBGP_BTN_WEST

USBGP_ABS_X = 0x00 # left stick X
USBGP_ABS_Y = 0x01 # left stick Y
USBGP_ABS_Z = 0x02 # left analog trigger
USBGP_ABS_RX = 0x03 # right stick X
USBGP_ABS_RY = 0x04 # right stick Y
USBGP_ABS_RZ = 0x05 # right analog trigger
USBGP_ABS_HAT0X = 0x10 # D-pad X
USBGP_ABS_HAT0Y = 0x11 # D-pad Y

GENERIC_USB_GAMEPAD_TO_MOUSE_KB_DEAULT_MAPPING = {
    "MAPPING_TYPE": "DEFAULT_MOUSE_KB",
    'BTN_TL': {'code': 'BTN_LEFT'},
    'BTN_TR': {'code': 'BTN_RIGHT'},
    'BTN_TL2': {'code': 'BTN_LEFT'},
    'BTN_TR2': {'code': 'BTN_RIGHT'},
    'ABS_X': {'code': 'REL_X'},
    'ABS_Y': {'code': 'REL_Y'},
    'ABS_HAT0X': {'code': 'KEY_RIGHT', 'code_neg': 'KEY_LEFT'},
    'ABS_HAT0Y': {'code': 'KEY_DOWN', 'code_neg': 'KEY_UP'}
}

IBM_GENERIC_USB_GAMEPAD_TO_15PIN_GAMEPORT_GAMEPAD_DEAULT_MAPPING = {
    "MAPPING_TYPE": "DEFAULT_15PIN",
    # buttons to buttons
    'BTN_SOUTH': {'code':'IBM_GGP_BTN_1'},
    'BTN_NORTH': {'code':'IBM_GGP_BTN_2'},
    'BTN_EAST': {'code':'IBM_GGP_BTN_3'},
    'BTN_WEST': {'code':'IBM_GGP_BTN_4'},
    
    'BTN_TL': {'code':'IBM_GGP_BTN_1'},
    'BTN_TR': {'code':'IBM_GGP_BTN_2'},
    'BTN_Z': {'code':'IBM_GGP_BTN_3'},
    'BTN_C': {'code':'IBM_GGP_BTN_4'},
    
    'BTN_TL2': {'code':'IBM_GGP_BTN_1'},
    'BTN_TR2': {'code':'IBM_GGP_BTN_2'},

    # analog axes to analog axes
    'ABS_X': {'code':'IBM_GGP_JS1_X'},
    'ABS_Y': {'code':'IBM_GGP_JS1_Y'},
    'ABS_HAT0X': {'code':'IBM_GGP_JS1_X'},
    'ABS_HAT0Y': {'code':'IBM_GGP_JS1_Y'},
    'ABS_RX': {'code':'IBM_GGP_JS2_X'},
    'ABS_RY': {'code':'IBM_GGP_JS2_Y'},
}

PROTOCOL_OFF = {'pid':0, 'display_name':"OFF"}
PROTOCOL_AT_PS2_KB = {'pid':1, 'display_name':"AT/PS2"}
PROTOCOL_XT_KB = {'pid':2, 'display_name':"PC XT"}
PROTOCOL_ADB_KB = {'pid':3, 'display_name':"ADB"}
PROTOCOL_PS2_MOUSE_NORMAL = {'pid':4, 'display_name':"PS/2"}
PROTOCOL_MICROSOFT_SERIAL_MOUSE = {'pid':5, 'display_name':"Microsft Serial"}
PROTOCOL_ADB_MOUSE = {'pid':6, 'display_name':"ADB"}
PROTOCOL_15PIN_GAMEPORT_GAMEPAD = {'pid':7, 'display_name':"Generic 15-Pin", 'mapping':IBM_GENERIC_USB_GAMEPAD_TO_15PIN_GAMEPORT_GAMEPAD_DEAULT_MAPPING}
PROTOCOL_MOUSESYSTEMS_SERIAL_MOUSE = {'pid':8, 'display_name':"MouseSys Serial"}
PROTOCOL_USB_GP_TO_MOUSE_KB = {'pid':0, 'display_name':'Mouse & KB', 'mapping':GENERIC_USB_GAMEPAD_TO_MOUSE_KB_DEAULT_MAPPING}
PROTOCOL_RAW_KEYBOARD = {'pid':125, 'display_name':"Raw data"}
PROTOCOL_RAW_MOUSE = {'pid':126, 'display_name':"Raw data"}
PROTOCOL_RAW_GAMEPAD = {'pid':127, 'display_name':"Raw data"}

custom_profile_list = []

try:
    onlyfiles = [f for f in os.listdir(config_dir_path) if os.path.isfile(os.path.join(config_dir_path, f))]
    json_map_files = [os.path.join(config_dir_path, x) for x in onlyfiles if x.lower().startswith('usb4vc_map') and x.lower().endswith(".json")]
    for item in json_map_files:
        print('loading json file:', item)
        with open(item) as json_file:
            custom_profile_list.append(json.load(json_file))
except Exception as e:
    print('exception json load:', e)

def get_list_of_usb_drive():
    usb_drive_set = set()
    try:
        usb_drive_path = subprocess.getoutput(f"timeout 2 df -h | grep -i usb").replace('\r', '').split('\n')
        for item in [x for x in usb_drive_path if len(x) > 2]:
            usb_drive_set.add(os.path.join(item.split(' ')[-1], 'usb4vc'))
    except Exception as e:
        print("exception get_list_of_usb_drive:", e)
    return usb_drive_set

def copy_debug_log():
    usb_drive_set = get_list_of_usb_drive()
    if len(usb_drive_set) == 0:
        return False
    for this_path in usb_drive_set:
        if os.path.isdir(this_path):
            print('copying debug log to', this_path)
            os.system(f'sudo cp -v /home/pi/usb4vc/usb4vc_debug_log.txt {this_path}')
    return True

def check_usb_drive():
    usb_drive_set = get_list_of_usb_drive()

    if len(usb_drive_set) == 0:
        return False, 'USB Drive Not Found'

    for this_path in usb_drive_set:
        usb_config_path = os.path.join(this_path, 'config')
        if not os.path.isdir(usb_config_path):
            usb_config_path = None

        if usb_config_path is not None:
            return True, usb_config_path

    return False, 'No Update Data Found'

def get_pbid_and_version(dfu_file_name):
    pbid = None
    try:
        pbid = int(dfu_file_name.split('PBID')[-1].split('_')[0])
    except Exception as e:
        print("exception fw pbid parse:", e)
    fw_ver_tuple = None
    try:
        fw_ver = dfu_file_name.lower().split('_v')[-1].split('.')[0].split('_')
        fw_ver_tuple = (int(fw_ver[0]), int(fw_ver[1]), int(fw_ver[2]))
    except Exception as e:
        print('exception fw ver parse:', e)
    return pbid, fw_ver_tuple

def reset_pboard():
    print("resetting protocol board...")
    GPIO.setup(PBOARD_BOOT0_PIN, GPIO.IN)
    GPIO.setup(PBOARD_RESET_PIN, GPIO.OUT)
    GPIO.output(PBOARD_RESET_PIN, GPIO.LOW)
    time.sleep(0.05)
    GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
    time.sleep(0.05)
    print("done")

def enter_dfu():
    # RESET LOW: Enter reset
    GPIO.setup(PBOARD_RESET_PIN, GPIO.OUT)
    GPIO.output(PBOARD_RESET_PIN, GPIO.LOW)
    time.sleep(0.05)
    # BOOT0 HIGH: Boot into DFU mode
    GPIO.setup(PBOARD_BOOT0_PIN, GPIO.OUT)
    GPIO.output(PBOARD_BOOT0_PIN, GPIO.HIGH)
    time.sleep(0.05)
    # Release RESET, BOOT0 still HIGH, STM32 now in DFU mode
    GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
    time.sleep(1.5)

def exit_dfu():
    # Release BOOT0
    GPIO.setup(PBOARD_BOOT0_PIN, GPIO.IN)
    # Activate RESET
    GPIO.setup(PBOARD_RESET_PIN, GPIO.OUT)
    GPIO.output(PBOARD_RESET_PIN, GPIO.LOW)
    time.sleep(0.05)
    # Release RESET, BOOT0 is LOW, STM32 boots in normal mode
    GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
    time.sleep(1.5)

def fw_update(fw_path, pbid):
    is_updated = False
    if pbid in i2c_bootloader_pbid and fw_path.lower().endswith('.hex'):
        enter_dfu()
        os.system(f'sudo stm32flash -w {fw_path} -a 0x3b /dev/i2c-1')
        is_updated = True
    elif pbid in usb_bootloader_pbid and fw_path.lower().endswith('.dfu'):
        enter_dfu()
        lsusb_str = subprocess.getoutput("lsusb")
        if 'in DFU'.lower() not in lsusb_str.lower():
            with canvas(usb4vc_oled.oled_device) as draw:
                usb4vc_oled.oled_print_centered("Connect a USB cable", usb4vc_oled.font_regular, 0, draw)
                usb4vc_oled.oled_print_centered("from P-Card to RPi", usb4vc_oled.font_regular, 10, draw)
                usb4vc_oled.oled_print_centered("and try again", usb4vc_oled.font_regular, 20, draw)
            time.sleep(4)
        else:
            os.system(f'sudo dfu-util --device ,0483:df11 -a 0 -D {fw_path}')
            is_updated = True
    exit_dfu()
    return is_updated
    
def update_pboard_firmware(this_pid):
    onlyfiles = [f for f in os.listdir(firmware_dir_path) if os.path.isfile(os.path.join(firmware_dir_path, f))]
    firmware_files = [x for x in onlyfiles if x.startswith("PBFW_") and (x.lower().endswith(".dfu") or x.lower().endswith(".hex")) and "PBID" in x]
    this_pboard_version_tuple = (pboard_info_spi_msg[5], pboard_info_spi_msg[6], pboard_info_spi_msg[7])
    for item in firmware_files:
        pbid, fw_ver_tuple = get_pbid_and_version(item)
        if pbid is None or fw_ver_tuple is None:
            continue
        print('update_pboard_firmware:', this_pid, this_pboard_version_tuple, fw_ver_tuple)
        if pbid == this_pid and fw_ver_tuple > this_pboard_version_tuple:
            print("DOING IT NOW")
            with canvas(usb4vc_oled.oled_device) as draw:
                usb4vc_oled.oled_print_centered("Loading Firmware:", usb4vc_oled.font_medium, 0, draw)
                usb4vc_oled.oled_print_centered(item.strip("PBFW_").strip(".dfu").strip(".hex"), usb4vc_oled.font_regular, 16, draw)
            if fw_update(os.path.join(firmware_dir_path, item), this_pid):
                return True
    return False

def update_from_usb(usb_config_path):
    if usb_config_path is not None:
        os.system(f'cp -v /home/pi/usb4vc/config/config.json {usb_config_path}')
        os.system('mv -v /home/pi/usb4vc/config/config.json /home/pi/usb4vc/config.json')
        os.system('rm -rfv /home/pi/usb4vc/config/*')
        os.system(f"cp -v {os.path.join(usb_config_path, '*')} /home/pi/usb4vc/config")
        os.system("mv -v /home/pi/usb4vc/config.json /home/pi/usb4vc/config/config.json")

ibmpc_keyboard_protocols = [PROTOCOL_OFF, PROTOCOL_AT_PS2_KB, PROTOCOL_XT_KB]
ibmpc_mouse_protocols = [PROTOCOL_OFF, PROTOCOL_PS2_MOUSE_NORMAL, PROTOCOL_MICROSOFT_SERIAL_MOUSE, PROTOCOL_MOUSESYSTEMS_SERIAL_MOUSE]
ibmpc_gamepad_protocols = [PROTOCOL_OFF, PROTOCOL_15PIN_GAMEPORT_GAMEPAD, PROTOCOL_USB_GP_TO_MOUSE_KB]

adb_keyboard_protocols = [PROTOCOL_OFF, PROTOCOL_ADB_KB]
adb_mouse_protocols = [PROTOCOL_OFF, PROTOCOL_ADB_MOUSE]
adb_gamepad_protocols = [PROTOCOL_OFF, PROTOCOL_USB_GP_TO_MOUSE_KB]

raw_keyboard_protocols = [PROTOCOL_OFF, PROTOCOL_RAW_KEYBOARD]
raw_mouse_protocols = [PROTOCOL_OFF, PROTOCOL_RAW_MOUSE]
raw_gamepad_protocols = [PROTOCOL_OFF, PROTOCOL_RAW_GAMEPAD]

mouse_sensitivity_list = [1, 1.25, 1.5, 1.75, 0.25, 0.5, 0.75]

"""
key is protocol card ID
conf_dict[pbid]:
hw revision
current keyboard protocol
current mouse protocol
current gamepad procotol
mouse sensitivity
"""

configuration_dict = {}

LINUX_EXIT_CODE_TIMEOUT = 124

def bt_setup():
    rfkill_str = subprocess.getoutput("/usr/sbin/rfkill -n")
    if 'bluetooth' not in rfkill_str:
        return 1, "no BT receiver found"
    os.system('/usr/sbin/rfkill unblock bluetooth')
    time.sleep(0.1)
    exit_code = os.system('timeout 1 bluetoothctl agent NoInputNoOutput') >> 8
    if exit_code == LINUX_EXIT_CODE_TIMEOUT:
        return 2, 'bluetoothctl stuck'
    return 0, ''

def scan_bt_devices(timeout_sec = 5):
    exit_code = os.system(f"timeout {timeout_sec} bluetoothctl --agent NoInputNoOutput scan on") >> 8
    if exit_code != LINUX_EXIT_CODE_TIMEOUT:
        return None, 'scan error'
    device_str = subprocess.getoutput("bluetoothctl --agent NoInputNoOutput devices")
    dev_list = []
    for line in device_str.replace('\r', '').split('\n'):
        if 'device' not in line.lower():
            continue
        line_split = line.split(' ', maxsplit=2)
        # skip if device has no name
        if len(line_split) < 3 or line_split[2].count('-') == 5:
            continue
        dev_list.append((line_split[1], line_split[2]))
    return dev_list, ''

def pair_device(mac_addr):
    is_ready = False
    is_sent = False
    fail_phrases = ['fail', 'error', 'not available', 'excep']
    with Popen(["bluetoothctl", "--agent", "NoInputNoOutput"], stdout=PIPE, stdin=PIPE, bufsize=1,
               universal_newlines=True, shell=True) as p:
        for line in p.stdout:
            print(line, end='')
            line_lo = line.lower()
            if 'registered' in line_lo:
                is_ready = True
            if is_ready is False:
                continue
            if '#' in line_lo and is_sent == False:
                p.stdin.write(f'pair {mac_addr}\n')
                is_sent = True
            if 'PIN code:' in line:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Enter PIN code:", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(line.split('PIN code:')[-1], usb4vc_oled.font_medium, 15, draw)
            if '(yes/no)' in line:
                p.stdin.write('yes\n')
            if 'number in 0-999999' in line:
                return False, "Error: Passkey needed"
            if 'successful' in line_lo:
                p.stdin.write('exit\n')
                return True, 'Success!'
            for item in fail_phrases:
                if item in line_lo:
                    p.stdin.write('exit\n')
                    return False, line
    return False, "wtf"

def get_paired_devices():
    dev_set = set()
    try:
        device_str = subprocess.getoutput(f"timeout 5 bluetoothctl --agent NoInputNoOutput paired-devices")
        for line in device_str.replace('\r', '').split('\n'):
            if 'device' not in line.lower():
                continue
            line_split = line.split(' ', maxsplit=2)
            # skip if device has no name
            if len(line_split) < 3 or line_split[2].count('-') == 5:
                continue
            dev_set.add((line_split[1], line_split[2]))
    except Exception as e:
        print('exception get_paired_devices:', e)
    return dev_set

def load_config():
    global configuration_dict
    try:
        with open(config_file_path) as json_file:
            temp_dict = json.load(json_file)
            # json dump all keys as strings, need to convert them back to ints
            for key in temp_dict:
                if key.isdigit():
                    configuration_dict[int(key)] = temp_dict[key]
                else:
                    configuration_dict[key] = temp_dict[key]
    except Exception as e:
        print("exception config load failed!", e)

def get_ip_address():
    ip_str = subprocess.getoutput("timeout 1 hostname -I")
    ip_list = [x for x in ip_str.split(' ') if '.' in x]
    if len(ip_list) == 0:
        return "Offline"
    return f'{ip_list[0]}'

def save_config():
    try:
        with open(config_file_path, 'w', encoding='utf-8') as save_file:
           save_file.write(json.dumps(configuration_dict))
    except Exception as e:
        print("exception config save failed!", e)

curve_vertial_axis_x_pos = 80
curve_horizontal_axis_width = 32

curve_linear = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24, 25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35, 36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46, 47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68, 69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79, 80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90, 91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99, 100: 100, 101: 101, 102: 102, 103: 103, 104: 104, 105: 105, 106: 106, 107: 107, 108: 108, 109: 109, 110: 110, 111: 111, 112: 112, 113: 113, 114: 114, 115: 115, 116: 116, 117: 117, 118: 118, 119: 119, 120: 120, 121: 121, 122: 122, 123: 123, 124: 124, 125: 125, 126: 126, 127: 127}
curve1 = {0: 1, 1: 1, 2: 2, 3: 2, 4: 3, 5: 4, 6: 4, 7: 5, 8: 5, 9: 6, 10: 6, 11: 7, 12: 7, 13: 8, 14: 8, 15: 9, 16: 9, 17: 10, 18: 11, 19: 11, 20: 12, 21: 12, 22: 13, 23: 13, 24: 14, 25: 15, 26: 15, 27: 16, 28: 16, 29: 17, 30: 18, 31: 18, 32: 19, 33: 19, 34: 20, 35: 21, 36: 21, 37: 22, 38: 22, 39: 23, 40: 24, 41: 24, 42: 25, 43: 26, 44: 26, 45: 27, 46: 28, 47: 28, 48: 29, 49: 30, 50: 30, 51: 31, 52: 32, 53: 33, 54: 33, 55: 34, 56: 35, 57: 36, 58: 36, 59: 37, 60: 38, 61: 39, 62: 39, 63: 40, 64: 41, 65: 42, 66: 43, 67: 44, 68: 45, 69: 46, 70: 46, 71: 47, 72: 48, 73: 49, 74: 50, 75: 51, 76: 52, 77: 53, 78: 55, 79: 56, 80: 57, 81: 58, 82: 59, 83: 60, 84: 61, 85: 62, 86: 63, 87: 65, 88: 66, 89: 67, 90: 68, 91: 70, 92: 71, 93: 72, 94: 73, 95: 75, 96: 76, 97: 77, 98: 79, 99: 80, 100: 81, 101: 83, 102: 84, 103: 86, 104: 87, 105: 89, 106: 90, 107: 92, 108: 93, 109: 95, 110: 96, 111: 98, 112: 100, 113: 101, 114: 103, 115: 105, 116: 106, 117: 108, 118: 110, 119: 112, 120: 113, 121: 115, 122: 117, 123: 119, 124: 121, 125: 123, 126: 125, 127: 127}
curve2 = {0: 1, 1: 1, 2: 1, 3: 1, 4: 2, 5: 2, 6: 2, 7: 2, 8: 2, 9: 3, 10: 3, 11: 3, 12: 3, 13: 4, 14: 4, 15: 4, 16: 4, 17: 5, 18: 5, 19: 5, 20: 5, 21: 6, 22: 6, 23: 6, 24: 7, 25: 7, 26: 7, 27: 8, 28: 8, 29: 8, 30: 8, 31: 9, 32: 9, 33: 9, 34: 10, 35: 10, 36: 10, 37: 11, 38: 11, 39: 12, 40: 12, 41: 12, 42: 13, 43: 13, 44: 13, 45: 14, 46: 14, 47: 15, 48: 15, 49: 15, 50: 16, 51: 16, 52: 17, 53: 17, 54: 18, 55: 18, 56: 19, 57: 19, 58: 20, 59: 20, 60: 21, 61: 21, 62: 22, 63: 22, 64: 23, 65: 23, 66: 24, 67: 24, 68: 25, 69: 26, 70: 26, 71: 27, 72: 28, 73: 28, 74: 29, 75: 30, 76: 30, 77: 31, 78: 32, 79: 33, 80: 34, 81: 35, 82: 36, 83: 37, 84: 38, 85: 39, 86: 40, 87: 41, 88: 42, 89: 43, 90: 44, 91: 45, 92: 47, 93: 48, 94: 49, 95: 51, 96: 52, 97: 53, 98: 55, 99: 56, 100: 58, 101: 59, 102: 61, 103: 63, 104: 64, 105: 66, 106: 68, 107: 70, 108: 71, 109: 73, 110: 75, 111: 78, 112: 80, 113: 82, 114: 84, 115: 86, 116: 89, 117: 92, 118: 94, 119: 96, 120: 100, 121: 102, 122: 106, 123: 110, 124: 112, 125: 116, 126: 120, 127: 125}
curve3 = {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1, 12: 1, 13: 1, 14: 1, 15: 1, 16: 1, 17: 1, 18: 1, 19: 1, 20: 1, 21: 2, 22: 2, 23: 2, 24: 2, 25: 2, 26: 2, 27: 2, 28: 2, 29: 2, 30: 2, 31: 3, 32: 3, 33: 3, 34: 3, 35: 3, 36: 3, 37: 3, 38: 4, 39: 4, 40: 4, 41: 4, 42: 4, 43: 4, 44: 5, 45: 5, 46: 5, 47: 5, 48: 5, 49: 6, 50: 6, 51: 6, 52: 6, 53: 7, 54: 7, 55: 7, 56: 7, 57: 8, 58: 8, 59: 8, 60: 8, 61: 9, 62: 9, 63: 9, 64: 10, 65: 10, 66: 10, 67: 11, 68: 11, 69: 11, 70: 12, 71: 12, 72: 12, 73: 13, 74: 13, 75: 14, 76: 14, 77: 15, 78: 15, 79: 16, 80: 16, 81: 17, 82: 17, 83: 18, 84: 19, 85: 19, 86: 20, 87: 21, 88: 21, 89: 22, 90: 23, 91: 24, 92: 25, 93: 26, 94: 27, 95: 28, 96: 29, 97: 30, 98: 32, 99: 33, 100: 34, 101: 35, 102: 37, 103: 38, 104: 40, 105: 41, 106: 43, 107: 45, 108: 46, 109: 48, 110: 50, 111: 52, 112: 54, 113: 56, 114: 59, 115: 61, 116: 64, 117: 66, 118: 69, 119: 72, 120: 76, 121: 79, 122: 83, 123: 87, 124: 92, 125: 99, 126: 104, 127: 118}
joystick_curve_list = [curve_linear, curve1, curve2, curve3]

class usb4vc_menu(object):
    def cap_index(self, index, list_size):
        if index >= list_size:
            return 0
        return index
    def __init__(self, pboard, conf_dict):
        super(usb4vc_menu, self).__init__()
        self.current_level = 0
        self.current_page = 0
        self.level_size = 6
        self.page_size = [7, 6, 4, 1, 1, 5]
        self.kb_protocol_list = list(pboard['protocol_list_keyboard'])
        self.mouse_protocol_list = list(pboard['protocol_list_mouse'])
        self.gamepad_protocol_list = list(pboard['protocol_list_gamepad'])
        self.pb_info = dict(pboard)
        self.current_keyboard_protocol_index =  self.cap_index(conf_dict.get('keyboard_protocol_index', 0), len(self.kb_protocol_list))
        self.current_mouse_protocol_index =  self.cap_index(conf_dict.get("mouse_protocol_index", 0), len(self.mouse_protocol_list))
        self.current_mouse_sensitivity_offset_index =  self.cap_index(conf_dict.get("mouse_sensitivity_index", 0), len(mouse_sensitivity_list))
        self.current_gamepad_protocol_index =  self.cap_index(conf_dict.get("gamepad_protocol_index", 0), len(self.gamepad_protocol_list))
        self.current_keyboard_protocol = self.kb_protocol_list[self.current_keyboard_protocol_index]
        self.current_mouse_protocol = self.mouse_protocol_list[self.current_mouse_protocol_index]
        self.current_gamepad_protocol = self.gamepad_protocol_list[self.current_gamepad_protocol_index]
        self.current_joystick_curve_index =  self.cap_index(conf_dict.get("joystick_curve_index", 0), len(joystick_curve_list))
        self.last_spi_message = []
        self.bluetooth_device_list = None
        self.error_message = ''
        self.pairing_result = ''
        self.bt_scan_timeout_sec = 10
        self.paired_devices_list = []
        self.send_protocol_set_spi_msg()

    def switch_page(self, amount):
        self.current_page = (self.current_page + amount) % self.page_size[self.current_level]

    def goto_page(self, new_page):
        if new_page < self.page_size[self.current_level]:
            self.current_page = new_page

    def goto_level(self, new_level):
        if new_level < self.level_size:
            self.current_level = new_level
            self.current_page = 0

    def draw_joystick_curve(self):
        this_curve = joystick_curve_list[self.current_joystick_curve_index % len(joystick_curve_list)]
        with canvas(usb4vc_oled.oled_device) as draw:
            draw.text((0, 0), "Joystick", font=usb4vc_oled.font_medium, fill="white")
            draw.text((0, 15), "Curve", font=usb4vc_oled.font_medium, fill="white")
            draw.line((curve_vertial_axis_x_pos, 0, curve_vertial_axis_x_pos, curve_vertial_axis_x_pos), fill="white")
            draw.line((curve_vertial_axis_x_pos, 31, curve_vertial_axis_x_pos+curve_horizontal_axis_width, 31), fill="white")
            for xxx in range(curve_horizontal_axis_width):
                dict_key = xxx*4
                this_point_x = xxx + curve_vertial_axis_x_pos
                this_point_y = usb4vc_oled.OLED_HEIGHT - this_curve[dict_key]//4 - 1
                draw.line((this_point_x,this_point_y,this_point_x,this_point_y), fill="white")

    def display_page(self, level, page):
        if level == 0:
            if page == 0:
                with canvas(usb4vc_oled.oled_device) as draw:
                    mouse_count, kb_count, gp_count = usb4vc_usb_scan.get_device_count()
                    draw.text((0, 0),  f"KBD {kb_count} {self.current_keyboard_protocol['display_name']}", font=usb4vc_oled.font_regular, fill="white")
                    draw.text((0, 10), f"MOS {mouse_count} {self.current_mouse_protocol['display_name']}", font=usb4vc_oled.font_regular, fill="white")
                    draw.text((0, 20), f"GPD {gp_count} {self.current_gamepad_protocol['display_name']}", font=usb4vc_oled.font_regular, fill="white")
            if page == 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    if 'Unknown' in self.pb_info['full_name']:
                        draw.text((0, 0), f"{self.pb_info['full_name']} PID {this_pboard_id}", font=usb4vc_oled.font_regular, fill="white")
                    else:
                        draw.text((0, 0), f"{self.pb_info['full_name']}", font=usb4vc_oled.font_regular, fill="white")
                    draw.text((0, 10), f"PB {self.pb_info['fw_ver'][0]}.{self.pb_info['fw_ver'][1]}.{self.pb_info['fw_ver'][2]}  RPi {usb4vc_shared.RPI_APP_VERSION_TUPLE[0]}.{usb4vc_shared.RPI_APP_VERSION_TUPLE[1]}.{usb4vc_shared.RPI_APP_VERSION_TUPLE[2]}", font=usb4vc_oled.font_regular, fill="white")
                    draw.text((0, 20), f"IP: {get_ip_address()}", font=usb4vc_oled.font_regular, fill="white")
            if page == 2:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Load Custom", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("Config from USB", usb4vc_oled.font_medium, 16, draw)
            if page == 3:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Internet Update", usb4vc_oled.font_medium, 10, draw)
            if page == 4:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Show Event Codes", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("(experimental)", usb4vc_oled.font_regular, 20, draw)
            if page == 5:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Remove BT Device", usb4vc_oled.font_medium, 10, draw)
            if page == 6:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Pair Bluetooth", usb4vc_oled.font_medium, 10, draw)
        if level == 1:
            if page == 0:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Keyboard Protocol", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(self.kb_protocol_list[self.current_keyboard_protocol_index]['display_name'], usb4vc_oled.font_medium, 15, draw)
            if page == 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Mouse Protocol", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(self.mouse_protocol_list[self.current_mouse_protocol_index]['display_name'], usb4vc_oled.font_medium, 15, draw)
            if page == 2:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Gamepad Protocol", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(self.gamepad_protocol_list[self.current_gamepad_protocol_index]['display_name'], usb4vc_oled.font_medium, 15, draw)
            if page == 3:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Mouse Sensitivity", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(f"{mouse_sensitivity_list[self.current_mouse_sensitivity_offset_index]}", usb4vc_oled.font_medium, 15, draw)
            if page == 4:
                self.draw_joystick_curve()
            if page == 5:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Save & Quit", usb4vc_oled.font_medium, 10, draw)
        if level == 2:
            if page == 0:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Put your device in", usb4vc_oled.font_regular, 0, draw)
                    usb4vc_oled.oled_print_centered("pairing mode now.", usb4vc_oled.font_regular, 10, draw)
                    usb4vc_oled.oled_print_centered("Press enter to start", usb4vc_oled.font_regular, 20, draw)
            if page == 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Scanning...", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("Please wait", usb4vc_oled.font_medium, 15, draw)
                result, self.error_message = bt_setup()
                if result != 0:
                    self.goto_page(3)
                    self.display_curent_page()
                    return
                paired_devices_set = get_paired_devices()
                self.bluetooth_device_list, self.error_message = scan_bt_devices(self.bt_scan_timeout_sec)
                self.bluetooth_device_list = list(set(self.bluetooth_device_list) - paired_devices_set)
                if len(self.bluetooth_device_list) == 0:
                    self.error_message = "Nothing was found"
                    self.goto_page(3)
                    self.display_curent_page()
                    return
                print("BT LIST:", self.bluetooth_device_list)
                # set up level 3 menu structure
                self.page_size[3] = len(self.bluetooth_device_list) + 1
                self.goto_level(3)
                self.display_curent_page()
            if page == 2:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Pairing result:", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(self.pairing_result, usb4vc_oled.font_regular, 20, draw)
            if page == 3:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Bluetooth Error!", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered(self.error_message, usb4vc_oled.font_regular, 20, draw)
        if level == 3:
            if page == self.page_size[3] - 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Exit", usb4vc_oled.font_medium, 10, draw)
            else:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered(f"Found {len(self.bluetooth_device_list)}. Pair this?", usb4vc_oled.font_regular, 0, draw)
                    usb4vc_oled.oled_print_centered(f"{self.bluetooth_device_list[page][1]}", usb4vc_oled.font_regular, 10, draw)
                    usb4vc_oled.oled_print_centered(f"{self.bluetooth_device_list[page][0]}", usb4vc_oled.font_regular, 20, draw)
        if level == 4:
            if page == self.page_size[4] - 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Exit", usb4vc_oled.font_medium, 10, draw)
            else:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered(f"Remove this?", usb4vc_oled.font_regular, 0, draw)
                    usb4vc_oled.oled_print_centered(f"{self.paired_devices_list[page][1]}", usb4vc_oled.font_regular, 10, draw)
                    usb4vc_oled.oled_print_centered(f"{self.paired_devices_list[page][0]}", usb4vc_oled.font_regular, 20, draw)
        if level == 5:
            if page == 0:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Power Down", usb4vc_oled.font_medium, 10, draw)
            if page == 1:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Relaunch", usb4vc_oled.font_medium, 10, draw)
            if page == 2:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Reboot", usb4vc_oled.font_medium, 10, draw)
            if page == 3:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Exit to Linux", usb4vc_oled.font_medium, 10, draw)
            if page == 4:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Cancel", usb4vc_oled.font_medium, 10, draw)

    def send_protocol_set_spi_msg(self):
        status_dict = {}
        for index, item in enumerate(self.kb_protocol_list):
            if item['pid'] & 0x7f in status_dict and status_dict[item['pid'] & 0x7f] == 1:
                continue
            status_dict[item['pid'] & 0x7f] = 0
            if index == self.current_keyboard_protocol_index:
                status_dict[item['pid'] & 0x7f] = 1

        for index, item in enumerate(self.mouse_protocol_list):
            if item['pid'] & 0x7f in status_dict and status_dict[item['pid'] & 0x7f] == 1:
                continue
            status_dict[item['pid'] & 0x7f] = 0
            if index == self.current_mouse_protocol_index:
                status_dict[item['pid'] & 0x7f] = 1

        for index, item in enumerate(self.gamepad_protocol_list):
            if item['pid'] & 0x7f in status_dict and status_dict[item['pid'] & 0x7f] == 1:
                continue
            status_dict[item['pid'] & 0x7f] = 0
            if index == self.current_gamepad_protocol_index:
                status_dict[item['pid'] & 0x7f] = 1

        protocol_bytes = []
        for key in status_dict:
            if key == PROTOCOL_OFF['pid']:
                continue
            if status_dict[key]:
                protocol_bytes.append(key | 0x80)
            else:
                protocol_bytes.append(key)

        this_msg = list(set_protocl_spi_msg_template)
        this_msg[3:3+len(protocol_bytes)] = protocol_bytes

        self.current_keyboard_protocol = self.kb_protocol_list[self.current_keyboard_protocol_index]
        self.current_mouse_protocol = self.mouse_protocol_list[self.current_mouse_protocol_index]
        self.current_gamepad_protocol = self.gamepad_protocol_list[self.current_gamepad_protocol_index]

        if this_msg == self.last_spi_message:
            print("SPI: no need to send")
            return
        print("set_protocol:", [hex(x) for x in this_msg])
        usb4vc_usb_scan.set_protocol(this_msg)
        print('new status:', [hex(x) for x in usb4vc_usb_scan.get_pboard_info()])
        self.last_spi_message = list(this_msg)

    def action(self, level, page):
        if level == 0:
            if page == 2:
                usb_present, config_path = check_usb_drive()
                if usb_present is False:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Error:", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered(str(config_path), usb4vc_oled.font_regular, 16, draw)
                    time.sleep(3)
                    self.goto_level(0)
                else:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Copying", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered("Debug Log...", usb4vc_oled.font_medium, 16, draw)
                    copy_debug_log()
                    time.sleep(2)
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Copying custom", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered("mapping...", usb4vc_oled.font_medium, 16, draw)
                    time.sleep(2)
                    update_from_usb(config_path)
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Update complete!", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered("Relaunching...", usb4vc_oled.font_medium, 16, draw)
                    time.sleep(3)
                    usb4vc_oled.oled_device.clear()
                    os._exit(0)
                self.goto_level(0)
            elif page == 3:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Updating...", usb4vc_oled.font_medium, 10, draw)
                fffff = usb4vc_check_update.download_latest_firmware(this_pboard_id)
                if fffff != 0:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Unable to download", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered(f"firmware: {fffff}", usb4vc_oled.font_medium, 16, draw)
                elif update_pboard_firmware(this_pboard_id):
                        with canvas(usb4vc_oled.oled_device) as draw:
                            usb4vc_oled.oled_print_centered("Firmware updated!", usb4vc_oled.font_medium, 10, draw)
                else:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("FW update ERR or", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered("already newest", usb4vc_oled.font_medium, 15, draw)
                time.sleep(3)
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Updating code...", usb4vc_oled.font_medium, 10, draw)
                time.sleep(1)
                update_result = usb4vc_check_update.update(temp_dir_path)
                if update_result[0] == 0:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Update complete!", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered("Relaunching...", usb4vc_oled.font_medium, 16, draw)
                else:
                    with canvas(usb4vc_oled.oled_device) as draw:
                        usb4vc_oled.oled_print_centered("Update failed:", usb4vc_oled.font_medium, 0, draw)
                        usb4vc_oled.oled_print_centered(f"{update_result[-1]} {update_result[0]}", usb4vc_oled.font_regular, 16, draw)
                time.sleep(4)
                usb4vc_oled.oled_device.clear()
                os._exit(0)
            elif page == 4:
                try:
                    usb4vc_show_ev.ev_loop([plus_button, minus_button, enter_button])
                except Exception as e:
                    print('exception ev_loop:', e)
                self.goto_level(0)
            elif page == 5:
                self.paired_devices_list = list(get_paired_devices())
                self.page_size[4] = len(self.paired_devices_list) + 1
                self.goto_level(4)
            elif page == 6:
                self.goto_level(2)
            else:
                self.goto_level(1)
        if level == 1:
            if page == 0:
                self.current_keyboard_protocol_index = (self.current_keyboard_protocol_index + 1) % len(self.kb_protocol_list)
            if page == 1:
                self.current_mouse_protocol_index = (self.current_mouse_protocol_index + 1) % len(self.mouse_protocol_list)
            if page == 2:
                self.current_gamepad_protocol_index = (self.current_gamepad_protocol_index + 1) % len(self.gamepad_protocol_list)
            if page == 3:
                self.current_mouse_sensitivity_offset_index = (self.current_mouse_sensitivity_offset_index + 1) % len(mouse_sensitivity_list)
            if page == 4:
                self.current_joystick_curve_index = (self.current_joystick_curve_index + 1) % len(joystick_curve_list)
                self.draw_joystick_curve()
            if page == 5:
                configuration_dict[this_pboard_id]["keyboard_protocol_index"] = self.current_keyboard_protocol_index
                configuration_dict[this_pboard_id]["mouse_protocol_index"] = self.current_mouse_protocol_index
                configuration_dict[this_pboard_id]["mouse_sensitivity_index"] = self.current_mouse_sensitivity_offset_index
                configuration_dict[this_pboard_id]["gamepad_protocol_index"] = self.current_gamepad_protocol_index
                configuration_dict[this_pboard_id]["joystick_curve_index"] = self.current_joystick_curve_index
                save_config()
                self.send_protocol_set_spi_msg()
                self.goto_level(0)
        if level == 2:
            if page == 0:  
                self.switch_page(1)
            if page == 2:
                self.goto_level(0)
            if page == 3:
                self.goto_level(0)
        if level == 3:
            if page == self.page_size[3] - 1:
                self.goto_level(0)
            else:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Pairing...", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("Please wait", usb4vc_oled.font_medium, 15, draw)
                print("pairing", self.bluetooth_device_list[page])
                bt_mac_addr = self.bluetooth_device_list[page][0]
                is_successful, result_message = pair_device(bt_mac_addr)
                self.pairing_result = result_message.split('.')[-1].strip()[-22:]
                if is_successful:
                    os.system(f'timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput trust {bt_mac_addr}')
                    os.system(f'timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput connect {bt_mac_addr}')
                self.goto_level(2)
                self.goto_page(2)
        if level == 4:
            if page == self.page_size[4] - 1:
                self.goto_level(0)
            else:
                os.system(f'timeout 5 bluetoothctl --agent NoInputNoOutput untrust {self.paired_devices_list[page][0]}')
                os.system(f'timeout 5 bluetoothctl --agent NoInputNoOutput remove {self.paired_devices_list[page][0]}')
                self.goto_level(0)
        if level == 5:
            if page == 0:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Wait Until Green", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("LED Stops Blinking", usb4vc_oled.font_medium, 15, draw)
                time.sleep(2)
                os.system("sudo halt")
                while 1:
                    time.sleep(1)
            if page == 1:
                usb4vc_oled.oled_device.clear()
                os._exit(0)
            if page == 2:
                with canvas(usb4vc_oled.oled_device) as draw:
                    usb4vc_oled.oled_print_centered("Rebooting...", usb4vc_oled.font_medium, 0, draw)
                    usb4vc_oled.oled_print_centered("Unplug if stuck >10s", usb4vc_oled.font_regular, 16, draw)
                os.system("sudo reboot")
                while 1:
                    time.sleep(1)
            if page == 3:
                usb4vc_oled.oled_device.clear()
                os._exit(169)
            if page == 4:
                self.goto_level(0)
        self.display_curent_page()

    def action_current_page(self):
        self.action(self.current_level, self.current_page)

    def display_curent_page(self):
        self.display_page(self.current_level, self.current_page)

    def update_usb_status(self):
        if self.current_level == 0 and self.current_page == 0:
            self.display_page(0, 0)

    def update_board_status(self):
        if self.current_level == 0 and self.current_page == 1:
            self.display_page(0, 1)

pboard_database = {
    PBOARD_ID_UNKNOWN:{'author':'Unknown', 'fw_ver':(0,0,0), 'full_name':'Unknown', 'hw_rev':0, 'protocol_list_keyboard':raw_keyboard_protocols, 'protocol_list_mouse':raw_mouse_protocols, 'protocol_list_gamepad':raw_gamepad_protocols},
    PBOARD_ID_IBMPC:{'author':'dekuNukem', 'fw_ver':(0,0,0), 'full_name':'IBM PC Compatible', 'hw_rev':0, 'protocol_list_keyboard':ibmpc_keyboard_protocols, 'protocol_list_mouse':ibmpc_mouse_protocols, 'protocol_list_gamepad':ibmpc_gamepad_protocols},
    PBOARD_ID_ADB:{'author':'dekuNukem', 'fw_ver':(0,0,0), 'full_name':'Apple Desktop Bus', 'hw_rev':0, 'protocol_list_keyboard':adb_keyboard_protocols, 'protocol_list_mouse':adb_mouse_protocols, 'protocol_list_gamepad':adb_gamepad_protocols},
}

def get_pboard_dict(pid):
    if pid not in pboard_database:
        pid = 0
    return pboard_database[pid]

def get_mouse_sensitivity():
    return mouse_sensitivity_list[configuration_dict[this_pboard_id]["mouse_sensitivity_index"]]

def ui_init():
    global pboard_info_spi_msg
    global this_pboard_id
    load_config()
    pboard_info_spi_msg = usb4vc_usb_scan.get_pboard_info()
    print("PB INFO:", pboard_info_spi_msg)
    this_pboard_id = pboard_info_spi_msg[3]
    if this_pboard_id in pboard_database:
        # load custom profile mapping into protocol list
        for item in custom_profile_list:
            this_mapping_bid = usb4vc_shared.board_id_lookup.get(item['protocol_board'], 0)
            if this_mapping_bid == this_pboard_id and item['device_type'] in pboard_database[this_pboard_id]:
                this_mapping_pid = usb4vc_shared.protocol_id_lookup.get(item['protocol_name'])
                item['pid'] = this_mapping_pid
                pboard_database[this_pboard_id][item['device_type']].append(item)
        pboard_database[this_pboard_id]['hw_rev'] = pboard_info_spi_msg[4]
        pboard_database[this_pboard_id]['fw_ver'] = (pboard_info_spi_msg[5], pboard_info_spi_msg[6], pboard_info_spi_msg[7])
    if 'rpi_app_ver' not in configuration_dict:
        configuration_dict['rpi_app_ver'] = usb4vc_shared.RPI_APP_VERSION_TUPLE
    if this_pboard_id not in configuration_dict:
        configuration_dict[this_pboard_id] = {"keyboard_protocol_index":1, "mouse_protocol_index":1, "mouse_sensitivity_index":0, "gamepad_protocol_index":1}

plus_button = my_button(PLUS_BUTTON_PIN)
minus_button = my_button(MINUS_BUTTON_PIN)
enter_button = my_button(ENTER_BUTTON_PIN)
shutdown_button = my_button(SHUTDOWN_BUTTON_PIN)

class oled_sleep_control(object):
    def __init__(self):
        super(oled_sleep_control, self).__init__()
        self.is_sleeping = False
        self.last_input_event = time.time()
        self.ui_loop_count = 0
    def sleep(self):
        if self.is_sleeping is False:
            print("sleeping!")
            usb4vc_oled.oled_device.clear()
            self.is_sleeping = True
            # GPIO.output(SLEEP_LED_PIN, GPIO.HIGH)
    def wakeup(self):
        if self.is_sleeping:
            print("waking up!")
            my_menu.display_curent_page()
            self.last_input_event = time.time()
            self.is_sleeping = False
            # GPIO.output(SLEEP_LED_PIN, GPIO.LOW)
    def check_sleep(self):
        # time.time() might jump ahead a lot when RPi gets its time from network
        # this ensures OLED won't go to sleep too early
        if self.ui_loop_count <= 1500:
            return
        if time.time() - self.last_input_event > 180:
            self.sleep()
        else:
            self.wakeup()
    def kick(self):
        self.last_input_event = time.time()

my_oled = oled_sleep_control()
my_menu = None
def ui_worker():
    global my_menu
    print(configuration_dict)
    print("ui_worker started")
    my_menu = usb4vc_menu(get_pboard_dict(this_pboard_id), configuration_dict[this_pboard_id])
    my_menu.display_page(0, 0)
    for x in range(2):
        GPIO.output(SLEEP_LED_PIN, GPIO.HIGH)
        time.sleep(0.2)
        GPIO.output(SLEEP_LED_PIN, GPIO.LOW)
        time.sleep(0.2)
    while 1: 
        time.sleep(0.1)
        my_oled.ui_loop_count += 1
        if my_oled.is_sleeping is False and my_oled.ui_loop_count % 5 == 0:
            my_menu.update_usb_status()
            my_menu.update_board_status()

        if plus_button.is_pressed():
            my_oled.kick()
            if my_oled.is_sleeping:
                my_oled.wakeup()
            elif my_menu.current_level != 2:
                my_menu.switch_page(1)
                my_menu.display_curent_page()

        if minus_button.is_pressed():
            my_oled.kick()
            if my_oled.is_sleeping:
                my_oled.wakeup()
            elif my_menu.current_level != 2:
                my_menu.switch_page(-1)
                my_menu.display_curent_page()

        if enter_button.is_pressed():
            my_oled.kick()
            if my_oled.is_sleeping:
                my_oled.wakeup()
            else:
                my_menu.action_current_page()

        if shutdown_button.is_pressed():
            my_oled.kick()
            if my_oled.is_sleeping:
                my_oled.wakeup()
            else:
                my_menu.goto_level(5)
                my_menu.display_curent_page()
        my_oled.check_sleep()

def get_gamepad_protocol():
    return my_menu.current_gamepad_protocol

def get_joystick_curve():
    return joystick_curve_list[my_menu.current_joystick_curve_index]

def oled_print_model_changed():
    with canvas(usb4vc_oled.oled_device) as draw:
        usb4vc_oled.oled_print_centered("RPi Model Changed!", usb4vc_oled.font_regular, 0, draw)
        usb4vc_oled.oled_print_centered("Recompiling BT Driver", usb4vc_oled.font_regular, 10, draw)
        usb4vc_oled.oled_print_centered("Might take a while...", usb4vc_oled.font_regular, 20, draw)

def oled_print_oneline(msg):
    with canvas(usb4vc_oled.oled_device) as draw:
        usb4vc_oled.oled_print_centered(msg, usb4vc_oled.font_medium, 10, draw)

def oled_print_reboot():
    with canvas(usb4vc_oled.oled_device) as draw:
        usb4vc_oled.oled_print_centered("Done! Rebooting..", usb4vc_oled.font_medium, 0, draw)
        usb4vc_oled.oled_print_centered("Unplug if stuck >10s", usb4vc_oled.font_regular, 16, draw)

ui_thread = threading.Thread(target=ui_worker, daemon=True)

[((26, 19, 26, 63), 'os.path.join', 'os.path.join', ({(26, 32, 26, 47): 'config_dir_path', (26, 49, 26, 62): '"""config.json"""'}, {}), "(config_dir_path, 'config.json')", False, 'import os\n'), ((28, 0, 28, 29), 'usb4vc_shared.ensure_dir', 'ensure_dir', ({(28, 11, 28, 28): 'this_app_dir_path'}, {}), '(this_app_dir_path)', False, 'from usb4vc_shared import ensure_dir\n'), ((29, 0, 29, 27), 'usb4vc_shared.ensure_dir', 'ensure_dir', ({(29, 11, 29, 26): 'config_dir_path'}, {}), '(config_dir_path)', False, 'from usb4vc_shared import ensure_dir\n'), ((30, 0, 30, 29), 'usb4vc_shared.ensure_dir', 'ensure_dir', ({(30, 11, 30, 28): 'firmware_dir_path'}, {}), '(firmware_dir_path)', False, 'from usb4vc_shared import ensure_dir\n'), ((31, 0, 31, 25), 'usb4vc_shared.ensure_dir', 'ensure_dir', ({(31, 11, 31, 24): 'temp_dir_path'}, {}), '(temp_dir_path)', False, 'from usb4vc_shared import ensure_dir\n'), ((42, 0, 42, 22), 'RPi.GPIO.setmode', 'GPIO.setmode', ({(42, 13, 42, 21): 'GPIO.BCM'}, {}), '(GPIO.BCM)', True, 'import RPi.GPIO as GPIO\n'), ((43, 0, 43, 37), 'RPi.GPIO.setup', 'GPIO.setup', ({(43, 11, 43, 27): 'PBOARD_RESET_PIN', (43, 29, 43, 36): 'GPIO.IN'}, {}), '(PBOARD_RESET_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((44, 0, 44, 37), 'RPi.GPIO.setup', 'GPIO.setup', ({(44, 11, 44, 27): 'PBOARD_BOOT0_PIN', (44, 29, 44, 36): 'GPIO.IN'}, {}), '(PBOARD_BOOT0_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((45, 0, 45, 35), 'RPi.GPIO.setup', 'GPIO.setup', ({(45, 11, 45, 24): 'SLEEP_LED_PIN', (45, 26, 45, 34): 'GPIO.OUT'}, {}), '(SLEEP_LED_PIN, GPIO.OUT)', True, 'import RPi.GPIO as GPIO\n'), ((46, 0, 46, 36), 'RPi.GPIO.output', 'GPIO.output', ({(46, 12, 46, 25): 'SLEEP_LED_PIN', (46, 27, 46, 35): 'GPIO.LOW'}, {}), '(SLEEP_LED_PIN, GPIO.LOW)', True, 'import RPi.GPIO as GPIO\n'), ((976, 12, 976, 59), 'threading.Thread', 'threading.Thread', (), '', False, 'import threading\n'), ((218, 4, 218, 41), 'RPi.GPIO.setup', 'GPIO.setup', ({(218, 15, 218, 31): 'PBOARD_BOOT0_PIN', (218, 33, 218, 40): 'GPIO.IN'}, {}), '(PBOARD_BOOT0_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((219, 4, 219, 42), 'RPi.GPIO.setup', 'GPIO.setup', ({(219, 15, 219, 31): 'PBOARD_RESET_PIN', (219, 33, 219, 41): 'GPIO.OUT'}, {}), '(PBOARD_RESET_PIN, GPIO.OUT)', True, 'import RPi.GPIO as GPIO\n'), ((220, 4, 220, 43), 'RPi.GPIO.output', 'GPIO.output', ({(220, 16, 220, 32): 'PBOARD_RESET_PIN', (220, 34, 220, 42): 'GPIO.LOW'}, {}), '(PBOARD_RESET_PIN, GPIO.LOW)', True, 'import RPi.GPIO as GPIO\n'), ((221, 4, 221, 20), 'time.sleep', 'time.sleep', ({(221, 15, 221, 19): '(0.05)'}, {}), '(0.05)', False, 'import time\n'), ((222, 4, 222, 41), 'RPi.GPIO.setup', 'GPIO.setup', ({(222, 15, 222, 31): 'PBOARD_RESET_PIN', (222, 33, 222, 40): 'GPIO.IN'}, {}), '(PBOARD_RESET_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((223, 4, 223, 20), 'time.sleep', 'time.sleep', ({(223, 15, 223, 19): '(0.05)'}, {}), '(0.05)', False, 'import time\n'), ((228, 4, 228, 42), 'RPi.GPIO.setup', 'GPIO.setup', ({(228, 15, 228, 31): 'PBOARD_RESET_PIN', (228, 33, 228, 41): 'GPIO.OUT'}, {}), '(PBOARD_RESET_PIN, GPIO.OUT)', True, 'import RPi.GPIO as GPIO\n'), ((229, 4, 229, 43), 'RPi.GPIO.output', 'GPIO.output', ({(229, 16, 229, 32): 'PBOARD_RESET_PIN', (229, 34, 229, 42): 'GPIO.LOW'}, {}), '(PBOARD_RESET_PIN, GPIO.LOW)', True, 'import RPi.GPIO as GPIO\n'), ((230, 4, 230, 20), 'time.sleep', 'time.sleep', ({(230, 15, 230, 19): '(0.05)'}, {}), '(0.05)', False, 'import time\n'), ((232, 4, 232, 42), 'RPi.GPIO.setup', 'GPIO.setup', ({(232, 15, 232, 31): 'PBOARD_BOOT0_PIN', (232, 33, 232, 41): 'GPIO.OUT'}, {}), '(PBOARD_BOOT0_PIN, GPIO.OUT)', True, 'import RPi.GPIO as GPIO\n'), ((233, 4, 233, 44), 'RPi.GPIO.output', 'GPIO.output', ({(233, 16, 233, 32): 'PBOARD_BOOT0_PIN', (233, 34, 233, 43): 'GPIO.HIGH'}, {}), '(PBOARD_BOOT0_PIN, GPIO.HIGH)', True, 'import RPi.GPIO as GPIO\n'), ((234, 4, 234, 20), 'time.sleep', 'time.sleep', ({(234, 15, 234, 19): '(0.05)'}, {}), '(0.05)', False, 'import time\n'), ((236, 4, 236, 41), 'RPi.GPIO.setup', 'GPIO.setup', ({(236, 15, 236, 31): 'PBOARD_RESET_PIN', (236, 33, 236, 40): 'GPIO.IN'}, {}), '(PBOARD_RESET_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((237, 4, 237, 19), 'time.sleep', 'time.sleep', ({(237, 15, 237, 18): '(1.5)'}, {}), '(1.5)', False, 'import time\n'), ((241, 4, 241, 41), 'RPi.GPIO.setup', 'GPIO.setup', ({(241, 15, 241, 31): 'PBOARD_BOOT0_PIN', (241, 33, 241, 40): 'GPIO.IN'}, {}), '(PBOARD_BOOT0_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((243, 4, 243, 42), 'RPi.GPIO.setup', 'GPIO.setup', ({(243, 15, 243, 31): 'PBOARD_RESET_PIN', (243, 33, 243, 41): 'GPIO.OUT'}, {}), '(PBOARD_RESET_PIN, GPIO.OUT)', True, 'import RPi.GPIO as GPIO\n'), ((244, 4, 244, 43), 'RPi.GPIO.output', 'GPIO.output', ({(244, 16, 244, 32): 'PBOARD_RESET_PIN', (244, 34, 244, 42): 'GPIO.LOW'}, {}), '(PBOARD_RESET_PIN, GPIO.LOW)', True, 'import RPi.GPIO as GPIO\n'), ((245, 4, 245, 20), 'time.sleep', 'time.sleep', ({(245, 15, 245, 19): '(0.05)'}, {}), '(0.05)', False, 'import time\n'), ((247, 4, 247, 41), 'RPi.GPIO.setup', 'GPIO.setup', ({(247, 15, 247, 31): 'PBOARD_RESET_PIN', (247, 33, 247, 40): 'GPIO.IN'}, {}), '(PBOARD_RESET_PIN, GPIO.IN)', True, 'import RPi.GPIO as GPIO\n'), ((248, 4, 248, 19), 'time.sleep', 'time.sleep', ({(248, 15, 248, 18): '(1.5)'}, {}), '(1.5)', False, 'import time\n'), ((326, 17, 326, 60), 'subprocess.getoutput', 'subprocess.getoutput', ({(326, 38, 326, 59): '"""/usr/sbin/rfkill -n"""'}, {}), "('/usr/sbin/rfkill -n')", False, 'import subprocess\n'), ((329, 4, 329, 51), 'os.system', 'os.system', ({(329, 14, 329, 50): '"""/usr/sbin/rfkill unblock bluetooth"""'}, {}), "('/usr/sbin/rfkill unblock bluetooth')", False, 'import os\n'), ((330, 4, 330, 19), 'time.sleep', 'time.sleep', ({(330, 15, 330, 18): '(0.1)'}, {}), '(0.1)', False, 'import time\n'), ((340, 17, 340, 85), 'subprocess.getoutput', 'subprocess.getoutput', ({(340, 38, 340, 84): '"""bluetoothctl --agent NoInputNoOutput devices"""'}, {}), "('bluetoothctl --agent NoInputNoOutput devices')", False, 'import subprocess\n'), ((416, 13, 416, 58), 'subprocess.getoutput', 'subprocess.getoutput', ({(416, 34, 416, 57): '"""timeout 1 hostname -I"""'}, {}), "('timeout 1 hostname -I')", False, 'import subprocess\n'), ((849, 26, 849, 59), 'usb4vc_usb_scan.get_pboard_info', 'usb4vc_usb_scan.get_pboard_info', ({}, {}), '()', False, 'import usb4vc_usb_scan\n'), ((56, 8, 56, 70), 'RPi.GPIO.setup', 'GPIO.setup', (), '', True, 'import RPi.GPIO as GPIO\n'), ((57, 26, 57, 53), 'RPi.GPIO.input', 'GPIO.input', ({(57, 37, 57, 52): 'self.pin_number'}, {}), '(self.pin_number)', True, 'import RPi.GPIO as GPIO\n'), ((61, 24, 61, 51), 'RPi.GPIO.input', 'GPIO.input', ({(61, 35, 61, 50): 'self.pin_number'}, {}), '(self.pin_number)', True, 'import RPi.GPIO as GPIO\n'), ((158, 22, 158, 54), 'os.path.join', 'os.path.join', ({(158, 35, 158, 50): 'config_dir_path', (158, 52, 158, 53): 'x'}, {}), '(config_dir_path, x)', False, 'import os\n'), ((181, 11, 181, 35), 'os.path.isdir', 'os.path.isdir', ({(181, 25, 181, 34): 'this_path'}, {}), '(this_path)', False, 'import os\n'), ((193, 26, 193, 59), 'os.path.join', 'os.path.join', ({(193, 39, 193, 48): 'this_path', (193, 50, 193, 58): '"""config"""'}, {}), "(this_path, 'config')", False, 'import os\n'), ((254, 8, 254, 69), 'os.system', 'os.system', ({(254, 18, 254, 68): 'f"""sudo stm32flash -w {fw_path} -a 0x3b /dev/i2c-1"""'}, {}), "(f'sudo stm32flash -w {fw_path} -a 0x3b /dev/i2c-1')", False, 'import os\n'), ((291, 8, 291, 80), 'os.system', 'os.system', ({(291, 18, 291, 79): 'f"""cp -v /home/pi/usb4vc/config/config.json {usb_config_path}"""'}, {}), "(f'cp -v /home/pi/usb4vc/config/config.json {usb_config_path}')", False, 'import os\n'), ((292, 8, 292, 89), 'os.system', 'os.system', ({(292, 18, 292, 88): '"""mv -v /home/pi/usb4vc/config/config.json /home/pi/usb4vc/config.json"""'}, {}), "(\n    'mv -v /home/pi/usb4vc/config/config.json /home/pi/usb4vc/config.json')", False, 'import os\n'), ((293, 8, 293, 53), 'os.system', 'os.system', ({(293, 18, 293, 52): '"""rm -rfv /home/pi/usb4vc/config/*"""'}, {}), "('rm -rfv /home/pi/usb4vc/config/*')", False, 'import os\n'), ((295, 8, 295, 89), 'os.system', 'os.system', ({(295, 18, 295, 88): '"""mv -v /home/pi/usb4vc/config.json /home/pi/usb4vc/config/config.json"""'}, {}), "(\n    'mv -v /home/pi/usb4vc/config.json /home/pi/usb4vc/config/config.json')", False, 'import os\n'), ((331, 16, 331, 73), 'os.system', 'os.system', ({(331, 26, 331, 72): '"""timeout 1 bluetoothctl agent NoInputNoOutput"""'}, {}), "('timeout 1 bluetoothctl agent NoInputNoOutput')", False, 'import os\n'), ((337, 16, 337, 96), 'os.system', 'os.system', ({(337, 26, 337, 95): 'f"""timeout {timeout_sec} bluetoothctl --agent NoInputNoOutput scan on"""'}, {}), "(f'timeout {timeout_sec} bluetoothctl --agent NoInputNoOutput scan on'\n    )", False, 'import os\n'), ((356, 9, 357, 51), 'subprocess.Popen', 'Popen', (), '', False, 'from subprocess import Popen, PIPE\n'), ((388, 21, 388, 107), 'subprocess.getoutput', 'subprocess.getoutput', ({(388, 42, 388, 106): 'f"""timeout 5 bluetoothctl --agent NoInputNoOutput paired-devices"""'}, {}), "(\n    f'timeout 5 bluetoothctl --agent NoInputNoOutput paired-devices')", False, 'import subprocess\n'), ((663, 8, 663, 46), 'usb4vc_usb_scan.set_protocol', 'usb4vc_usb_scan.set_protocol', ({(663, 37, 663, 45): 'this_msg'}, {}), '(this_msg)', False, 'import usb4vc_usb_scan\n'), ((876, 32, 876, 43), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((901, 32, 901, 43), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((912, 8, 912, 45), 'RPi.GPIO.output', 'GPIO.output', ({(912, 20, 912, 33): 'SLEEP_LED_PIN', (912, 35, 912, 44): 'GPIO.HIGH'}, {}), '(SLEEP_LED_PIN, GPIO.HIGH)', True, 'import RPi.GPIO as GPIO\n'), ((913, 8, 913, 23), 'time.sleep', 'time.sleep', ({(913, 19, 913, 22): '(0.2)'}, {}), '(0.2)', False, 'import time\n'), ((914, 8, 914, 44), 'RPi.GPIO.output', 'GPIO.output', ({(914, 20, 914, 33): 'SLEEP_LED_PIN', (914, 35, 914, 43): 'GPIO.LOW'}, {}), '(SLEEP_LED_PIN, GPIO.LOW)', True, 'import RPi.GPIO as GPIO\n'), ((915, 8, 915, 23), 'time.sleep', 'time.sleep', ({(915, 19, 915, 22): '(0.2)'}, {}), '(0.2)', False, 'import time\n'), ((917, 8, 917, 23), 'time.sleep', 'time.sleep', ({(917, 19, 917, 22): '(0.1)'}, {}), '(0.1)', False, 'import time\n'), ((962, 9, 962, 40), 'luma.core.render.canvas', 'canvas', ({(962, 16, 962, 39): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((963, 8, 963, 96), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(963, 40, 963, 60): '"""RPi Model Changed!"""', (963, 62, 963, 86): 'usb4vc_oled.font_regular', (963, 88, 963, 89): '(0)', (963, 91, 963, 95): 'draw'}, {}), "('RPi Model Changed!', usb4vc_oled.\n    font_regular, 0, draw)", False, 'import usb4vc_oled\n'), ((964, 8, 964, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(964, 40, 964, 63): '"""Recompiling BT Driver"""', (964, 65, 964, 89): 'usb4vc_oled.font_regular', (964, 91, 964, 93): '(10)', (964, 95, 964, 99): 'draw'}, {}), "('Recompiling BT Driver', usb4vc_oled.\n    font_regular, 10, draw)", False, 'import usb4vc_oled\n'), ((965, 8, 965, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(965, 40, 965, 63): '"""Might take a while..."""', (965, 65, 965, 89): 'usb4vc_oled.font_regular', (965, 91, 965, 93): '(20)', (965, 95, 965, 99): 'draw'}, {}), "('Might take a while...', usb4vc_oled.\n    font_regular, 20, draw)", False, 'import usb4vc_oled\n'), ((968, 9, 968, 40), 'luma.core.render.canvas', 'canvas', ({(968, 16, 968, 39): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((969, 8, 969, 79), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(969, 40, 969, 43): 'msg', (969, 45, 969, 68): 'usb4vc_oled.font_medium', (969, 70, 969, 72): '(10)', (969, 74, 969, 78): 'draw'}, {}), '(msg, usb4vc_oled.font_medium, 10, draw)', False, 'import usb4vc_oled\n'), ((972, 9, 972, 40), 'luma.core.render.canvas', 'canvas', ({(972, 16, 972, 39): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((973, 8, 973, 94), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(973, 40, 973, 59): '"""Done! Rebooting.."""', (973, 61, 973, 84): 'usb4vc_oled.font_medium', (973, 86, 973, 87): '(0)', (973, 89, 973, 93): 'draw'}, {}), "('Done! Rebooting..', usb4vc_oled.\n    font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((974, 8, 974, 99), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(974, 40, 974, 62): '"""Unplug if stuck >10s"""', (974, 64, 974, 88): 'usb4vc_oled.font_regular', (974, 90, 974, 92): '(16)', (974, 94, 974, 98): 'draw'}, {}), "('Unplug if stuck >10s', usb4vc_oled.\n    font_regular, 16, draw)", False, 'import usb4vc_oled\n'), ((157, 28, 157, 55), 'os.listdir', 'os.listdir', ({(157, 39, 157, 54): 'config_dir_path'}, {}), '(config_dir_path)', False, 'import os\n'), ((183, 12, 183, 85), 'os.system', 'os.system', ({(183, 22, 183, 84): 'f"""sudo cp -v /home/pi/usb4vc/usb4vc_debug_log.txt {this_path}"""'}, {}), "(f'sudo cp -v /home/pi/usb4vc/usb4vc_debug_log.txt {this_path}')", False, 'import os\n'), ((194, 15, 194, 45), 'os.path.isdir', 'os.path.isdir', ({(194, 29, 194, 44): 'usb_config_path'}, {}), '(usb_config_path)', False, 'import os\n'), ((258, 20, 258, 49), 'subprocess.getoutput', 'subprocess.getoutput', ({(258, 41, 258, 48): '"""lsusb"""'}, {}), "('lsusb')", False, 'import subprocess\n'), ((272, 28, 272, 57), 'os.listdir', 'os.listdir', ({(272, 39, 272, 56): 'firmware_dir_path'}, {}), '(firmware_dir_path)', False, 'import os\n'), ((405, 24, 405, 44), 'json.load', 'json.load', ({(405, 34, 405, 43): 'json_file'}, {}), '(json_file)', False, 'import json\n'), ((483, 13, 483, 44), 'luma.core.render.canvas', 'canvas', ({(483, 20, 483, 43): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((855, 31, 855, 91), 'usb4vc_shared.board_id_lookup.get', 'usb4vc_shared.board_id_lookup.get', ({(855, 65, 855, 87): "item['protocol_board']", (855, 89, 855, 90): '0'}, {}), "(item['protocol_board'], 0)", False, 'import usb4vc_shared\n'), ((881, 12, 881, 43), 'usb4vc_oled.oled_device.clear', 'usb4vc_oled.oled_device.clear', ({}, {}), '()', False, 'import usb4vc_oled\n'), ((888, 36, 888, 47), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((157, 74, 157, 106), 'os.path.join', 'os.path.join', ({(157, 87, 157, 102): 'config_dir_path', (157, 104, 157, 105): 'f'}, {}), '(config_dir_path, f)', False, 'import os\n'), ((162, 39, 162, 59), 'json.load', 'json.load', ({(162, 49, 162, 58): 'json_file'}, {}), '(json_file)', False, 'import json\n'), ((264, 12, 264, 25), 'time.sleep', 'time.sleep', ({(264, 23, 264, 24): '(4)'}, {}), '(4)', False, 'import time\n'), ((266, 12, 266, 77), 'os.system', 'os.system', ({(266, 22, 266, 76): 'f"""sudo dfu-util --device ,0483:df11 -a 0 -D {fw_path}"""'}, {}), "(f'sudo dfu-util --device ,0483:df11 -a 0 -D {fw_path}')", False, 'import os\n'), ((272, 76, 272, 110), 'os.path.join', 'os.path.join', ({(272, 89, 272, 106): 'firmware_dir_path', (272, 108, 272, 109): 'f'}, {}), '(firmware_dir_path, f)', False, 'import os\n'), ((282, 17, 282, 48), 'luma.core.render.canvas', 'canvas', ({(282, 24, 282, 47): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((283, 16, 283, 102), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(283, 48, 283, 67): '"""Loading Firmware:"""', (283, 69, 283, 92): 'usb4vc_oled.font_medium', (283, 94, 283, 95): '(0)', (283, 97, 283, 101): 'draw'}, {}), "('Loading Firmware:', usb4vc_oled.\n    font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((285, 25, 285, 62), 'os.path.join', 'os.path.join', ({(285, 38, 285, 55): 'firmware_dir_path', (285, 57, 285, 61): 'item'}, {}), '(firmware_dir_path, item)', False, 'import os\n'), ((425, 27, 425, 57), 'json.dumps', 'json.dumps', ({(425, 38, 425, 56): 'configuration_dict'}, {}), '(configuration_dict)', False, 'import json\n'), ((788, 16, 788, 120), 'os.system', 'os.system', ({(788, 26, 788, 119): 'f"""timeout 5 bluetoothctl --agent NoInputNoOutput untrust {self.paired_devices_list[page][0]}"""'}, {}), "(\n    f'timeout 5 bluetoothctl --agent NoInputNoOutput untrust {self.paired_devices_list[page][0]}'\n    )", False, 'import os\n'), ((789, 16, 789, 119), 'os.system', 'os.system', ({(789, 26, 789, 118): 'f"""timeout 5 bluetoothctl --agent NoInputNoOutput remove {self.paired_devices_list[page][0]}"""'}, {}), "(\n    f'timeout 5 bluetoothctl --agent NoInputNoOutput remove {self.paired_devices_list[page][0]}'\n    )", False, 'import os\n'), ((796, 16, 796, 29), 'time.sleep', 'time.sleep', ({(796, 27, 796, 28): '(2)'}, {}), '(2)', False, 'import time\n'), ((797, 16, 797, 38), 'os.system', 'os.system', ({(797, 26, 797, 37): '"""sudo halt"""'}, {}), "('sudo halt')", False, 'import os\n'), ((801, 16, 801, 47), 'usb4vc_oled.oled_device.clear', 'usb4vc_oled.oled_device.clear', ({}, {}), '()', False, 'import usb4vc_oled\n'), ((802, 16, 802, 27), 'os._exit', 'os._exit', ({(802, 25, 802, 26): '(0)'}, {}), '(0)', False, 'import os\n'), ((807, 16, 807, 40), 'os.system', 'os.system', ({(807, 26, 807, 39): '"""sudo reboot"""'}, {}), "('sudo reboot')", False, 'import os\n'), ((811, 16, 811, 47), 'usb4vc_oled.oled_device.clear', 'usb4vc_oled.oled_device.clear', ({}, {}), '()', False, 'import usb4vc_oled\n'), ((812, 16, 812, 29), 'os._exit', 'os._exit', ({(812, 25, 812, 28): '(169)'}, {}), '(169)', False, 'import os\n'), ((857, 35, 857, 94), 'usb4vc_shared.protocol_id_lookup.get', 'usb4vc_shared.protocol_id_lookup.get', ({(857, 72, 857, 93): "item['protocol_name']"}, {}), "(item['protocol_name'])", False, 'import usb4vc_shared\n'), ((896, 11, 896, 22), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((260, 17, 260, 48), 'luma.core.render.canvas', 'canvas', ({(260, 24, 260, 47): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((261, 16, 261, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(261, 48, 261, 69): '"""Connect a USB cable"""', (261, 71, 261, 95): 'usb4vc_oled.font_regular', (261, 97, 261, 98): '(0)', (261, 100, 261, 104): 'draw'}, {}), "('Connect a USB cable', usb4vc_oled.\n    font_regular, 0, draw)", False, 'import usb4vc_oled\n'), ((262, 16, 262, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(262, 48, 262, 68): '"""from P-Card to RPi"""', (262, 70, 262, 94): 'usb4vc_oled.font_regular', (262, 96, 262, 98): '(10)', (262, 100, 262, 104): 'draw'}, {}), "('from P-Card to RPi', usb4vc_oled.\n    font_regular, 10, draw)", False, 'import usb4vc_oled\n'), ((263, 16, 263, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(263, 48, 263, 63): '"""and try again"""', (263, 65, 263, 89): 'usb4vc_oled.font_regular', (263, 91, 263, 93): '(20)', (263, 95, 263, 99): 'draw'}, {}), "('and try again', usb4vc_oled.font_regular, \n    20, draw)", False, 'import usb4vc_oled\n'), ((294, 27, 294, 61), 'os.path.join', 'os.path.join', ({(294, 40, 294, 55): 'usb_config_path', (294, 57, 294, 60): '"""*"""'}, {}), "(usb_config_path, '*')", False, 'import os\n'), ((369, 21, 369, 52), 'luma.core.render.canvas', 'canvas', ({(369, 28, 369, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((370, 20, 370, 104), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(370, 52, 370, 69): '"""Enter PIN code:"""', (370, 71, 370, 94): 'usb4vc_oled.font_medium', (370, 96, 370, 97): '(0)', (370, 99, 370, 103): 'draw'}, {}), "('Enter PIN code:', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((497, 21, 497, 52), 'luma.core.render.canvas', 'canvas', ({(497, 28, 497, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((498, 54, 498, 88), 'usb4vc_usb_scan.get_device_count', 'usb4vc_usb_scan.get_device_count', ({}, {}), '()', False, 'import usb4vc_usb_scan\n'), ((503, 21, 503, 52), 'luma.core.render.canvas', 'canvas', ({(503, 28, 503, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((511, 21, 511, 52), 'luma.core.render.canvas', 'canvas', ({(511, 28, 511, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((512, 20, 512, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(512, 52, 512, 65): '"""Load Custom"""', (512, 67, 512, 90): 'usb4vc_oled.font_medium', (512, 92, 512, 93): '(0)', (512, 95, 512, 99): 'draw'}, {}), "('Load Custom', usb4vc_oled.font_medium, 0, draw\n    )", False, 'import usb4vc_oled\n'), ((513, 20, 513, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(513, 52, 513, 69): '"""Config from USB"""', (513, 71, 513, 94): 'usb4vc_oled.font_medium', (513, 96, 513, 98): '(16)', (513, 100, 513, 104): 'draw'}, {}), "('Config from USB', usb4vc_oled.font_medium,\n    16, draw)", False, 'import usb4vc_oled\n'), ((515, 21, 515, 52), 'luma.core.render.canvas', 'canvas', ({(515, 28, 515, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((516, 20, 516, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(516, 52, 516, 69): '"""Internet Update"""', (516, 71, 516, 94): 'usb4vc_oled.font_medium', (516, 96, 516, 98): '(10)', (516, 100, 516, 104): 'draw'}, {}), "('Internet Update', usb4vc_oled.font_medium,\n    10, draw)", False, 'import usb4vc_oled\n'), ((518, 21, 518, 52), 'luma.core.render.canvas', 'canvas', ({(518, 28, 518, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((519, 20, 519, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(519, 52, 519, 70): '"""Show Event Codes"""', (519, 72, 519, 95): 'usb4vc_oled.font_medium', (519, 97, 519, 98): '(0)', (519, 100, 519, 104): 'draw'}, {}), "('Show Event Codes', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((520, 20, 520, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(520, 52, 520, 68): '"""(experimental)"""', (520, 70, 520, 94): 'usb4vc_oled.font_regular', (520, 96, 520, 98): '(20)', (520, 100, 520, 104): 'draw'}, {}), "('(experimental)', usb4vc_oled.font_regular,\n    20, draw)", False, 'import usb4vc_oled\n'), ((522, 21, 522, 52), 'luma.core.render.canvas', 'canvas', ({(522, 28, 522, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((523, 20, 523, 106), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(523, 52, 523, 70): '"""Remove BT Device"""', (523, 72, 523, 95): 'usb4vc_oled.font_medium', (523, 97, 523, 99): '(10)', (523, 101, 523, 105): 'draw'}, {}), "('Remove BT Device', usb4vc_oled.font_medium,\n    10, draw)", False, 'import usb4vc_oled\n'), ((525, 21, 525, 52), 'luma.core.render.canvas', 'canvas', ({(525, 28, 525, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((526, 20, 526, 104), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(526, 52, 526, 68): '"""Pair Bluetooth"""', (526, 70, 526, 93): 'usb4vc_oled.font_medium', (526, 95, 526, 97): '(10)', (526, 99, 526, 103): 'draw'}, {}), "('Pair Bluetooth', usb4vc_oled.font_medium, \n    10, draw)", False, 'import usb4vc_oled\n'), ((529, 21, 529, 52), 'luma.core.render.canvas', 'canvas', ({(529, 28, 529, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((530, 20, 530, 106), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(530, 52, 530, 71): '"""Keyboard Protocol"""', (530, 73, 530, 96): 'usb4vc_oled.font_medium', (530, 98, 530, 99): '(0)', (530, 101, 530, 105): 'draw'}, {}), "('Keyboard Protocol', usb4vc_oled.\n    font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((531, 20, 531, 163), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(531, 52, 531, 127): "self.kb_protocol_list[self.current_keyboard_protocol_index]['display_name']", (531, 129, 531, 152): 'usb4vc_oled.font_medium', (531, 154, 531, 156): '(15)', (531, 158, 531, 162): 'draw'}, {}), "(self.kb_protocol_list[self.\n    current_keyboard_protocol_index]['display_name'], usb4vc_oled.\n    font_medium, 15, draw)", False, 'import usb4vc_oled\n'), ((533, 21, 533, 52), 'luma.core.render.canvas', 'canvas', ({(533, 28, 533, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((534, 20, 534, 103), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(534, 52, 534, 68): '"""Mouse Protocol"""', (534, 70, 534, 93): 'usb4vc_oled.font_medium', (534, 95, 534, 96): '(0)', (534, 98, 534, 102): 'draw'}, {}), "('Mouse Protocol', usb4vc_oled.font_medium, \n    0, draw)", False, 'import usb4vc_oled\n'), ((535, 20, 535, 163), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(535, 52, 535, 127): "self.mouse_protocol_list[self.current_mouse_protocol_index]['display_name']", (535, 129, 535, 152): 'usb4vc_oled.font_medium', (535, 154, 535, 156): '(15)', (535, 158, 535, 162): 'draw'}, {}), "(self.mouse_protocol_list[self.\n    current_mouse_protocol_index]['display_name'], usb4vc_oled.font_medium,\n    15, draw)", False, 'import usb4vc_oled\n'), ((537, 21, 537, 52), 'luma.core.render.canvas', 'canvas', ({(537, 28, 537, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((538, 20, 538, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(538, 52, 538, 70): '"""Gamepad Protocol"""', (538, 72, 538, 95): 'usb4vc_oled.font_medium', (538, 97, 538, 98): '(0)', (538, 100, 538, 104): 'draw'}, {}), "('Gamepad Protocol', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((539, 20, 539, 167), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(539, 52, 539, 131): "self.gamepad_protocol_list[self.current_gamepad_protocol_index]['display_name']", (539, 133, 539, 156): 'usb4vc_oled.font_medium', (539, 158, 539, 160): '(15)', (539, 162, 539, 166): 'draw'}, {}), "(self.gamepad_protocol_list[self.\n    current_gamepad_protocol_index]['display_name'], usb4vc_oled.\n    font_medium, 15, draw)", False, 'import usb4vc_oled\n'), ((541, 21, 541, 52), 'luma.core.render.canvas', 'canvas', ({(541, 28, 541, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((542, 20, 542, 106), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(542, 52, 542, 71): '"""Mouse Sensitivity"""', (542, 73, 542, 96): 'usb4vc_oled.font_medium', (542, 98, 542, 99): '(0)', (542, 101, 542, 105): 'draw'}, {}), "('Mouse Sensitivity', usb4vc_oled.\n    font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((543, 20, 543, 160), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(543, 52, 543, 124): 'f"""{mouse_sensitivity_list[self.current_mouse_sensitivity_offset_index]}"""', (543, 126, 543, 149): 'usb4vc_oled.font_medium', (543, 151, 543, 153): '(15)', (543, 155, 543, 159): 'draw'}, {}), "(\n    f'{mouse_sensitivity_list[self.current_mouse_sensitivity_offset_index]}',\n    usb4vc_oled.font_medium, 15, draw)", False, 'import usb4vc_oled\n'), ((547, 21, 547, 52), 'luma.core.render.canvas', 'canvas', ({(547, 28, 547, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((548, 20, 548, 101), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(548, 52, 548, 65): '"""Save & Quit"""', (548, 67, 548, 90): 'usb4vc_oled.font_medium', (548, 92, 548, 94): '(10)', (548, 96, 548, 100): 'draw'}, {}), "('Save & Quit', usb4vc_oled.font_medium, 10,\n    draw)", False, 'import usb4vc_oled\n'), ((551, 21, 551, 52), 'luma.core.render.canvas', 'canvas', ({(551, 28, 551, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((552, 20, 552, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(552, 52, 552, 72): '"""Put your device in"""', (552, 74, 552, 98): 'usb4vc_oled.font_regular', (552, 100, 552, 101): '(0)', (552, 103, 552, 107): 'draw'}, {}), "('Put your device in', usb4vc_oled.\n    font_regular, 0, draw)", False, 'import usb4vc_oled\n'), ((553, 20, 553, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(553, 52, 553, 71): '"""pairing mode now."""', (553, 73, 553, 97): 'usb4vc_oled.font_regular', (553, 99, 553, 101): '(10)', (553, 103, 553, 107): 'draw'}, {}), "('pairing mode now.', usb4vc_oled.\n    font_regular, 10, draw)", False, 'import usb4vc_oled\n'), ((554, 20, 554, 111), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(554, 52, 554, 74): '"""Press enter to start"""', (554, 76, 554, 100): 'usb4vc_oled.font_regular', (554, 102, 554, 104): '(20)', (554, 106, 554, 110): 'draw'}, {}), "('Press enter to start', usb4vc_oled.\n    font_regular, 20, draw)", False, 'import usb4vc_oled\n'), ((556, 21, 556, 52), 'luma.core.render.canvas', 'canvas', ({(556, 28, 556, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((557, 20, 557, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(557, 52, 557, 65): '"""Scanning..."""', (557, 67, 557, 90): 'usb4vc_oled.font_medium', (557, 92, 557, 93): '(0)', (557, 95, 557, 99): 'draw'}, {}), "('Scanning...', usb4vc_oled.font_medium, 0, draw\n    )", False, 'import usb4vc_oled\n'), ((558, 20, 558, 101), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(558, 52, 558, 65): '"""Please wait"""', (558, 67, 558, 90): 'usb4vc_oled.font_medium', (558, 92, 558, 94): '(15)', (558, 96, 558, 100): 'draw'}, {}), "('Please wait', usb4vc_oled.font_medium, 15,\n    draw)", False, 'import usb4vc_oled\n'), ((578, 21, 578, 52), 'luma.core.render.canvas', 'canvas', ({(578, 28, 578, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((579, 20, 579, 104), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(579, 52, 579, 69): '"""Pairing result:"""', (579, 71, 579, 94): 'usb4vc_oled.font_medium', (579, 96, 579, 97): '(0)', (579, 99, 579, 103): 'draw'}, {}), "('Pairing result:', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((580, 20, 580, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(580, 52, 580, 71): 'self.pairing_result', (580, 73, 580, 97): 'usb4vc_oled.font_regular', (580, 99, 580, 101): '(20)', (580, 103, 580, 107): 'draw'}, {}), '(self.pairing_result, usb4vc_oled.\n    font_regular, 20, draw)', False, 'import usb4vc_oled\n'), ((582, 21, 582, 52), 'luma.core.render.canvas', 'canvas', ({(582, 28, 582, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((583, 20, 583, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(583, 52, 583, 70): '"""Bluetooth Error!"""', (583, 72, 583, 95): 'usb4vc_oled.font_medium', (583, 97, 583, 98): '(0)', (583, 100, 583, 104): 'draw'}, {}), "('Bluetooth Error!', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((584, 20, 584, 107), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(584, 52, 584, 70): 'self.error_message', (584, 72, 584, 96): 'usb4vc_oled.font_regular', (584, 98, 584, 100): '(20)', (584, 102, 584, 106): 'draw'}, {}), '(self.error_message, usb4vc_oled.\n    font_regular, 20, draw)', False, 'import usb4vc_oled\n'), ((587, 21, 587, 52), 'luma.core.render.canvas', 'canvas', ({(587, 28, 587, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((588, 20, 588, 94), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(588, 52, 588, 58): '"""Exit"""', (588, 60, 588, 83): 'usb4vc_oled.font_medium', (588, 85, 588, 87): '(10)', (588, 89, 588, 93): 'draw'}, {}), "('Exit', usb4vc_oled.font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((590, 21, 590, 52), 'luma.core.render.canvas', 'canvas', ({(590, 28, 590, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((592, 20, 592, 129), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(592, 52, 592, 92): 'f"""{self.bluetooth_device_list[page][1]}"""', (592, 94, 592, 118): 'usb4vc_oled.font_regular', (592, 120, 592, 122): '(10)', (592, 124, 592, 128): 'draw'}, {}), "(f'{self.bluetooth_device_list[page][1]}',\n    usb4vc_oled.font_regular, 10, draw)", False, 'import usb4vc_oled\n'), ((593, 20, 593, 129), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(593, 52, 593, 92): 'f"""{self.bluetooth_device_list[page][0]}"""', (593, 94, 593, 118): 'usb4vc_oled.font_regular', (593, 120, 593, 122): '(20)', (593, 124, 593, 128): 'draw'}, {}), "(f'{self.bluetooth_device_list[page][0]}',\n    usb4vc_oled.font_regular, 20, draw)", False, 'import usb4vc_oled\n'), ((596, 21, 596, 52), 'luma.core.render.canvas', 'canvas', ({(596, 28, 596, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((597, 20, 597, 94), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(597, 52, 597, 58): '"""Exit"""', (597, 60, 597, 83): 'usb4vc_oled.font_medium', (597, 85, 597, 87): '(10)', (597, 89, 597, 93): 'draw'}, {}), "('Exit', usb4vc_oled.font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((599, 21, 599, 52), 'luma.core.render.canvas', 'canvas', ({(599, 28, 599, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((600, 20, 600, 103), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(600, 52, 600, 67): 'f"""Remove this?"""', (600, 69, 600, 93): 'usb4vc_oled.font_regular', (600, 95, 600, 96): '(0)', (600, 98, 600, 102): 'draw'}, {}), "(f'Remove this?', usb4vc_oled.font_regular, \n    0, draw)", False, 'import usb4vc_oled\n'), ((601, 20, 601, 127), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(601, 52, 601, 90): 'f"""{self.paired_devices_list[page][1]}"""', (601, 92, 601, 116): 'usb4vc_oled.font_regular', (601, 118, 601, 120): '(10)', (601, 122, 601, 126): 'draw'}, {}), "(f'{self.paired_devices_list[page][1]}',\n    usb4vc_oled.font_regular, 10, draw)", False, 'import usb4vc_oled\n'), ((602, 20, 602, 127), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(602, 52, 602, 90): 'f"""{self.paired_devices_list[page][0]}"""', (602, 92, 602, 116): 'usb4vc_oled.font_regular', (602, 118, 602, 120): '(20)', (602, 122, 602, 126): 'draw'}, {}), "(f'{self.paired_devices_list[page][0]}',\n    usb4vc_oled.font_regular, 20, draw)", False, 'import usb4vc_oled\n'), ((605, 21, 605, 52), 'luma.core.render.canvas', 'canvas', ({(605, 28, 605, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((606, 20, 606, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(606, 52, 606, 64): '"""Power Down"""', (606, 66, 606, 89): 'usb4vc_oled.font_medium', (606, 91, 606, 93): '(10)', (606, 95, 606, 99): 'draw'}, {}), "('Power Down', usb4vc_oled.font_medium, 10, draw\n    )", False, 'import usb4vc_oled\n'), ((608, 21, 608, 52), 'luma.core.render.canvas', 'canvas', ({(608, 28, 608, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((609, 20, 609, 98), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(609, 52, 609, 62): '"""Relaunch"""', (609, 64, 609, 87): 'usb4vc_oled.font_medium', (609, 89, 609, 91): '(10)', (609, 93, 609, 97): 'draw'}, {}), "('Relaunch', usb4vc_oled.font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((611, 21, 611, 52), 'luma.core.render.canvas', 'canvas', ({(611, 28, 611, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((612, 20, 612, 96), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(612, 52, 612, 60): '"""Reboot"""', (612, 62, 612, 85): 'usb4vc_oled.font_medium', (612, 87, 612, 89): '(10)', (612, 91, 612, 95): 'draw'}, {}), "('Reboot', usb4vc_oled.font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((614, 21, 614, 52), 'luma.core.render.canvas', 'canvas', ({(614, 28, 614, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((615, 20, 615, 103), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(615, 52, 615, 67): '"""Exit to Linux"""', (615, 69, 615, 92): 'usb4vc_oled.font_medium', (615, 94, 615, 96): '(10)', (615, 98, 615, 102): 'draw'}, {}), "('Exit to Linux', usb4vc_oled.font_medium, \n    10, draw)", False, 'import usb4vc_oled\n'), ((617, 21, 617, 52), 'luma.core.render.canvas', 'canvas', ({(617, 28, 617, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((618, 20, 618, 96), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(618, 52, 618, 60): '"""Cancel"""', (618, 62, 618, 85): 'usb4vc_oled.font_medium', (618, 87, 618, 89): '(10)', (618, 91, 618, 95): 'draw'}, {}), "('Cancel', usb4vc_oled.font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((664, 46, 664, 79), 'usb4vc_usb_scan.get_pboard_info', 'usb4vc_usb_scan.get_pboard_info', ({}, {}), '()', False, 'import usb4vc_usb_scan\n'), ((675, 20, 675, 33), 'time.sleep', 'time.sleep', ({(675, 31, 675, 32): '(3)'}, {}), '(3)', False, 'import time\n'), ((682, 20, 682, 33), 'time.sleep', 'time.sleep', ({(682, 31, 682, 32): '(2)'}, {}), '(2)', False, 'import time\n'), ((686, 20, 686, 33), 'time.sleep', 'time.sleep', ({(686, 31, 686, 32): '(2)'}, {}), '(2)', False, 'import time\n'), ((691, 20, 691, 33), 'time.sleep', 'time.sleep', ({(691, 31, 691, 32): '(3)'}, {}), '(3)', False, 'import time\n'), ((692, 20, 692, 51), 'usb4vc_oled.oled_device.clear', 'usb4vc_oled.oled_device.clear', ({}, {}), '()', False, 'import usb4vc_oled\n'), ((693, 20, 693, 31), 'os._exit', 'os._exit', ({(693, 29, 693, 30): '(0)'}, {}), '(0)', False, 'import os\n'), ((698, 24, 698, 84), 'usb4vc_check_update.download_latest_firmware', 'usb4vc_check_update.download_latest_firmware', ({(698, 69, 698, 83): 'this_pboard_id'}, {}), '(this_pboard_id)', False, 'import usb4vc_check_update\n'), ((710, 16, 710, 29), 'time.sleep', 'time.sleep', ({(710, 27, 710, 28): '(3)'}, {}), '(3)', False, 'import time\n'), ((713, 16, 713, 29), 'time.sleep', 'time.sleep', ({(713, 27, 713, 28): '(1)'}, {}), '(1)', False, 'import time\n'), ((714, 32, 714, 73), 'usb4vc_check_update.update', 'usb4vc_check_update.update', ({(714, 59, 714, 72): 'temp_dir_path'}, {}), '(temp_dir_path)', False, 'import usb4vc_check_update\n'), ((723, 16, 723, 29), 'time.sleep', 'time.sleep', ({(723, 27, 723, 28): '(4)'}, {}), '(4)', False, 'import time\n'), ((724, 16, 724, 47), 'usb4vc_oled.oled_device.clear', 'usb4vc_oled.oled_device.clear', ({}, {}), '()', False, 'import usb4vc_oled\n'), ((725, 16, 725, 27), 'os._exit', 'os._exit', ({(725, 25, 725, 26): '(0)'}, {}), '(0)', False, 'import os\n'), ((772, 21, 772, 52), 'luma.core.render.canvas', 'canvas', ({(772, 28, 772, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((773, 20, 773, 99), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(773, 52, 773, 64): '"""Pairing..."""', (773, 66, 773, 89): 'usb4vc_oled.font_medium', (773, 91, 773, 92): '(0)', (773, 94, 773, 98): 'draw'}, {}), "('Pairing...', usb4vc_oled.font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((774, 20, 774, 101), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(774, 52, 774, 65): '"""Please wait"""', (774, 67, 774, 90): 'usb4vc_oled.font_medium', (774, 92, 774, 94): '(15)', (774, 96, 774, 100): 'draw'}, {}), "('Please wait', usb4vc_oled.font_medium, 15,\n    draw)", False, 'import usb4vc_oled\n'), ((780, 20, 780, 125), 'os.system', 'os.system', ({(780, 30, 780, 124): 'f"""timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput trust {bt_mac_addr}"""'}, {}), "(\n    f'timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput trust {bt_mac_addr}'\n    )", False, 'import os\n'), ((781, 20, 781, 127), 'os.system', 'os.system', ({(781, 30, 781, 126): 'f"""timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput connect {bt_mac_addr}"""'}, {}), "(\n    f'timeout {self.bt_scan_timeout_sec} bluetoothctl --agent NoInputNoOutput connect {bt_mac_addr}'\n    )", False, 'import os\n'), ((793, 21, 793, 52), 'luma.core.render.canvas', 'canvas', ({(793, 28, 793, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((794, 20, 794, 105), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(794, 52, 794, 70): '"""Wait Until Green"""', (794, 72, 794, 95): 'usb4vc_oled.font_medium', (794, 97, 794, 98): '(0)', (794, 100, 794, 104): 'draw'}, {}), "('Wait Until Green', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((795, 20, 795, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(795, 52, 795, 72): '"""LED Stops Blinking"""', (795, 74, 795, 97): 'usb4vc_oled.font_medium', (795, 99, 795, 101): '(15)', (795, 103, 795, 107): 'draw'}, {}), "('LED Stops Blinking', usb4vc_oled.\n    font_medium, 15, draw)", False, 'import usb4vc_oled\n'), ((799, 20, 799, 33), 'time.sleep', 'time.sleep', ({(799, 31, 799, 32): '(1)'}, {}), '(1)', False, 'import time\n'), ((804, 21, 804, 52), 'luma.core.render.canvas', 'canvas', ({(804, 28, 804, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((805, 20, 805, 101), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(805, 52, 805, 66): '"""Rebooting..."""', (805, 68, 805, 91): 'usb4vc_oled.font_medium', (805, 93, 805, 94): '(0)', (805, 96, 805, 100): 'draw'}, {}), "('Rebooting...', usb4vc_oled.font_medium, 0,\n    draw)", False, 'import usb4vc_oled\n'), ((806, 20, 806, 111), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(806, 52, 806, 74): '"""Unplug if stuck >10s"""', (806, 76, 806, 100): 'usb4vc_oled.font_regular', (806, 102, 806, 104): '(16)', (806, 106, 806, 110): 'draw'}, {}), "('Unplug if stuck >10s', usb4vc_oled.\n    font_regular, 16, draw)", False, 'import usb4vc_oled\n'), ((809, 20, 809, 33), 'time.sleep', 'time.sleep', ({(809, 31, 809, 32): '(1)'}, {}), '(1)', False, 'import time\n'), ((169, 25, 169, 79), 'subprocess.getoutput', 'subprocess.getoutput', ({(169, 46, 169, 78): 'f"""timeout 2 df -h | grep -i usb"""'}, {}), "(f'timeout 2 df -h | grep -i usb')", False, 'import subprocess\n'), ((672, 25, 672, 56), 'luma.core.render.canvas', 'canvas', ({(672, 32, 672, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((673, 24, 673, 99), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(673, 56, 673, 64): '"""Error:"""', (673, 66, 673, 89): 'usb4vc_oled.font_medium', (673, 91, 673, 92): '(0)', (673, 94, 673, 98): 'draw'}, {}), "('Error:', usb4vc_oled.font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((678, 25, 678, 56), 'luma.core.render.canvas', 'canvas', ({(678, 32, 678, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((679, 24, 679, 100), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(679, 56, 679, 65): '"""Copying"""', (679, 67, 679, 90): 'usb4vc_oled.font_medium', (679, 92, 679, 93): '(0)', (679, 95, 679, 99): 'draw'}, {}), "('Copying', usb4vc_oled.font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((680, 24, 680, 106), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(680, 56, 680, 70): '"""Debug Log..."""', (680, 72, 680, 95): 'usb4vc_oled.font_medium', (680, 97, 680, 99): '(16)', (680, 101, 680, 105): 'draw'}, {}), "('Debug Log...', usb4vc_oled.font_medium, 16,\n    draw)", False, 'import usb4vc_oled\n'), ((683, 25, 683, 56), 'luma.core.render.canvas', 'canvas', ({(683, 32, 683, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((684, 24, 684, 107), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(684, 56, 684, 72): '"""Copying custom"""', (684, 74, 684, 97): 'usb4vc_oled.font_medium', (684, 99, 684, 100): '(0)', (684, 102, 684, 106): 'draw'}, {}), "('Copying custom', usb4vc_oled.font_medium, \n    0, draw)", False, 'import usb4vc_oled\n'), ((685, 24, 685, 104), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(685, 56, 685, 68): '"""mapping..."""', (685, 70, 685, 93): 'usb4vc_oled.font_medium', (685, 95, 685, 97): '(16)', (685, 99, 685, 103): 'draw'}, {}), "('mapping...', usb4vc_oled.font_medium, 16, draw\n    )", False, 'import usb4vc_oled\n'), ((688, 25, 688, 56), 'luma.core.render.canvas', 'canvas', ({(688, 32, 688, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((689, 24, 689, 109), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(689, 56, 689, 74): '"""Update complete!"""', (689, 76, 689, 99): 'usb4vc_oled.font_medium', (689, 101, 689, 102): '(0)', (689, 104, 689, 108): 'draw'}, {}), "('Update complete!', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((690, 24, 690, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(690, 56, 690, 72): '"""Relaunching..."""', (690, 74, 690, 97): 'usb4vc_oled.font_medium', (690, 99, 690, 101): '(16)', (690, 103, 690, 107): 'draw'}, {}), "('Relaunching...', usb4vc_oled.font_medium, \n    16, draw)", False, 'import usb4vc_oled\n'), ((696, 21, 696, 52), 'luma.core.render.canvas', 'canvas', ({(696, 28, 696, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((697, 20, 697, 101), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(697, 52, 697, 65): '"""Updating..."""', (697, 67, 697, 90): 'usb4vc_oled.font_medium', (697, 92, 697, 94): '(10)', (697, 96, 697, 100): 'draw'}, {}), "('Updating...', usb4vc_oled.font_medium, 10,\n    draw)", False, 'import usb4vc_oled\n'), ((711, 21, 711, 52), 'luma.core.render.canvas', 'canvas', ({(711, 28, 711, 51): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((712, 20, 712, 106), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(712, 52, 712, 70): '"""Updating code..."""', (712, 72, 712, 95): 'usb4vc_oled.font_medium', (712, 97, 712, 99): '(10)', (712, 101, 712, 105): 'draw'}, {}), "('Updating code...', usb4vc_oled.font_medium,\n    10, draw)", False, 'import usb4vc_oled\n'), ((700, 25, 700, 56), 'luma.core.render.canvas', 'canvas', ({(700, 32, 700, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((701, 24, 701, 111), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(701, 56, 701, 76): '"""Unable to download"""', (701, 78, 701, 101): 'usb4vc_oled.font_medium', (701, 103, 701, 104): '(0)', (701, 106, 701, 110): 'draw'}, {}), "('Unable to download', usb4vc_oled.\n    font_medium, 0, draw)", False, 'import usb4vc_oled\n'), ((702, 24, 702, 112), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(702, 56, 702, 76): 'f"""firmware: {fffff}"""', (702, 78, 702, 101): 'usb4vc_oled.font_medium', (702, 103, 702, 105): '(16)', (702, 107, 702, 111): 'draw'}, {}), "(f'firmware: {fffff}', usb4vc_oled.\n    font_medium, 16, draw)", False, 'import usb4vc_oled\n'), ((716, 25, 716, 56), 'luma.core.render.canvas', 'canvas', ({(716, 32, 716, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((717, 24, 717, 109), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(717, 56, 717, 74): '"""Update complete!"""', (717, 76, 717, 99): 'usb4vc_oled.font_medium', (717, 101, 717, 102): '(0)', (717, 104, 717, 108): 'draw'}, {}), "('Update complete!', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((718, 24, 718, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(718, 56, 718, 72): '"""Relaunching..."""', (718, 74, 718, 97): 'usb4vc_oled.font_medium', (718, 99, 718, 101): '(16)', (718, 103, 718, 107): 'draw'}, {}), "('Relaunching...', usb4vc_oled.font_medium, \n    16, draw)", False, 'import usb4vc_oled\n'), ((720, 25, 720, 56), 'luma.core.render.canvas', 'canvas', ({(720, 32, 720, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((721, 24, 721, 107), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(721, 56, 721, 72): '"""Update failed:"""', (721, 74, 721, 97): 'usb4vc_oled.font_medium', (721, 99, 721, 100): '(0)', (721, 102, 721, 106): 'draw'}, {}), "('Update failed:', usb4vc_oled.font_medium, \n    0, draw)", False, 'import usb4vc_oled\n'), ((722, 24, 722, 134), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(722, 56, 722, 97): 'f"""{update_result[-1]} {update_result[0]}"""', (722, 99, 722, 123): 'usb4vc_oled.font_regular', (722, 125, 722, 127): '(16)', (722, 129, 722, 133): 'draw'}, {}), "(f'{update_result[-1]} {update_result[0]}',\n    usb4vc_oled.font_regular, 16, draw)", False, 'import usb4vc_oled\n'), ((728, 20, 728, 85), 'usb4vc_show_ev.ev_loop', 'usb4vc_show_ev.ev_loop', ({(728, 43, 728, 84): '[plus_button, minus_button, enter_button]'}, {}), '([plus_button, minus_button, enter_button])', False, 'import usb4vc_show_ev\n'), ((704, 29, 704, 60), 'luma.core.render.canvas', 'canvas', ({(704, 36, 704, 59): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((705, 28, 705, 115), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(705, 60, 705, 79): '"""Firmware updated!"""', (705, 81, 705, 104): 'usb4vc_oled.font_medium', (705, 106, 705, 108): '(10)', (705, 110, 705, 114): 'draw'}, {}), "('Firmware updated!', usb4vc_oled.\n    font_medium, 10, draw)", False, 'import usb4vc_oled\n'), ((707, 25, 707, 56), 'luma.core.render.canvas', 'canvas', ({(707, 32, 707, 55): 'usb4vc_oled.oled_device'}, {}), '(usb4vc_oled.oled_device)', False, 'from luma.core.render import canvas\n'), ((708, 24, 708, 109), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(708, 56, 708, 74): '"""FW update ERR or"""', (708, 76, 708, 99): 'usb4vc_oled.font_medium', (708, 101, 708, 102): '(0)', (708, 104, 708, 108): 'draw'}, {}), "('FW update ERR or', usb4vc_oled.font_medium,\n    0, draw)", False, 'import usb4vc_oled\n'), ((709, 24, 709, 108), 'usb4vc_oled.oled_print_centered', 'usb4vc_oled.oled_print_centered', ({(709, 56, 709, 72): '"""already newest"""', (709, 74, 709, 97): 'usb4vc_oled.font_medium', (709, 99, 709, 101): '(15)', (709, 103, 709, 107): 'draw'}, {}), "('already newest', usb4vc_oled.font_medium, \n    15, draw)", False, 'import usb4vc_oled\n')]