diff --git a/lib/menu.py b/lib/menu.py
new file mode 100644
index 0000000000000000000000000000000000000000..c983b3e2a97b08f6bc4ab17236492dc566f84d84
--- /dev/null
+++ b/lib/menu.py
@@ -0,0 +1,336 @@
+import micropython
+# Allocate exception buffer for interrupt handlers
+micropython.alloc_emergency_exception_buf(100)
+
+import machine
+from lib.robot import Robot
+from lib.menu_display import display_show_startup
+
+# Initialize global robot object
+robot = Robot()
+# machine.WDT_RESET = hard and soft reboot or WDT reboot
+display_show_startup(robot, machine.WDT_RESET == machine.reset_cause())
+
+import time, os, sys, gc
+import os
+import sys
+import gc
+
+import menu_programs
+
+from lib.robot_consts import Button, Port, FW_VERSION
+from lib.menu_display import *
+from lib.utils.utils import log_error
+try:
+    from config import esp_default_name, battery_multiplier
+except:
+    from lib.default_config import esp_default_name, battery_multiplier
+
+robot.battery.set_multiplier(battery_multiplier)
+
+def main():
+    # File and directory constants for browsing user programs
+    FILE = micropython.const(0x8000)
+    DIRECTORY = micropython.const(0x4000)
+    menu_programs_functions = (('NXT Light', menu_programs.nxt_light_run), ('NXT Sound', menu_programs.nxt_sound_run), 
+                               ('NXT Touch', menu_programs.nxt_touch_run), ('NXT Ultrasonic',  menu_programs.nxt_ultra_run),
+                               ('EV3 Color', menu_programs.ev3_color_run), ('EV3 Gyro', menu_programs.ev3_gyro_run),
+                               ('EV3 Infrared', menu_programs.ev3_infra_run), ('EV3 Ultrasonic', menu_programs.ev3_ultra_run),
+                               ('EV3 & OC Touch', menu_programs.ev3_oc_touch_run),
+                               ('OC Color', menu_programs.oc_color_run), ('OC AHRS', menu_programs.oc_gyro_run), 
+                               ('OC Laser', menu_programs.oc_laser_run), ('OC Ultrasonic', menu_programs.oc_ultra_run))
+    MENU_PROGRAM_NXT_UTZ_IDX = 3
+    menu_programs_functions_size = len(menu_programs_functions)
+
+    menu_cube_programs_functions = (('Gyro Acc', menu_programs.cube_gyro_acc_run), ('LED & buzzer', menu_programs.cube_utility_run), 
+                                    ('Wifi webserver', menu_programs.esp_wifi_run), ('I2C Master', menu_programs.i2c_master_run),
+                                    ('I2C Slave', menu_programs.i2c_slave_run))
+    menu_cube_programs_functions_size = len(menu_cube_programs_functions)
+    
+    menu_list = [0, 0, 0, 0, 0, 0, 0]
+    menu_list_size = [0, Port.M_COUNT, menu_programs_functions_size, menu_cube_programs_functions_size, 1, 1, Port.S_COUNT]
+    SENSOR_TEST_MENU_PORT_IDX = 6   
+
+    # Analyze pressed buttons for menu movement 
+    def buttons(robot, button_values, robot_state, menu_move_v, menu_move_h, menu_debounce): 
+        menu_move_v=0
+        menu_move_h=0
+        ok_pressed = 0
+        if menu_debounce == 0:
+            if button_values[Button.OK]:
+                ok_pressed = 1
+            elif robot_state == 0:
+                if button_values[Button.DOWN]:
+                    menu_move_v=1
+                elif button_values[Button.UP]:
+                    menu_move_v=-1
+                elif button_values[Button.RIGHT]:
+                    menu_move_h=1
+                elif button_values[Button.LEFT]:
+                    menu_move_h=-1
+        
+        # Buttons debounce
+        if (not button_values[Button.UP] and not button_values[Button.DOWN] and not button_values[Button.OK] 
+            and not button_values[Button.RIGHT] and not button_values[Button.LEFT]):
+            if robot_state == 0 and menu_debounce == 1:
+                menu_move_v=0
+                menu_move_h=0
+                ok_pressed = 0
+                menu_debounce = 0
+        return menu_move_v, menu_move_h, menu_debounce, ok_pressed
+    
+    # Request ESP32 for BT pair pin
+    def send_esp_req(robot):
+        pin = robot.esp.req_bt_pin()
+        robot.esp.flush()
+        if pin is not None and pin != -1:
+            bt_pair = True
+        else:
+            bt_pair = False
+        if pin == -1:
+            robot.esp.flush()
+            robot.esp.timeout()
+        return bt_pair, pin
+    
+    def run_program(robot, program_name, program_path, globals):
+        print("Running program", program_name)
+        display_show_program(robot)
+        try:
+            # Open user program and execute it           
+            with open(program_path) as f:
+                code = compile(f.read(), program_name, 'exec')
+                robot.buttons.pressed_since()
+                exec(code, globals)
+        except Exception as e:
+            # Print exception for debugging and show error message on display 
+            # if error occurs in user program
+            sys.print_exception(e)
+            log_error(robot.start_time, e, program_name)
+            display_show_error(robot)
+            time.sleep(1.0)
+        finally:
+            # Deinit all sensors, motors and uart if initialized by user program 
+            # after user program ends
+            robot.deinit_all()
+            # Collect unreachable objects (this deinitializes EV3 motors & sensors)
+            gc.collect()
+            robot.esp.esp_running = False
+            print("Program finished\n")
+    time.sleep_ms(200) # wait for all components of the Cube to start
+    
+    # Initialize variables
+    robot_state = 0
+    menu_move_v, menu_move_h = 0, 0
+    menu_debounce = 0
+    current_menu = Menu.PROGRAM
+    sensor_test_menu = Menu.SEN_TEST_PROGRAM
+    sensor_test_menu_port = 0
+    counter = 1
+    rejected_pin = 0
+    bt_pair = False
+    bt_connecting = False
+    button_values = robot.buttons.pressed()
+    esp_reset_failed_counter = 0
+
+    # Get a list of user programs
+    program_list = []
+    try:
+        # Browse programs directory 
+        for entry in os.ilistdir("./programs"):
+            # Add .py user program to program list
+            if entry[1] == FILE and entry[0].endswith(".py"):
+                program_list.append((entry[0], FILE))
+            # Add all directory user program to program list
+            elif entry[1] == DIRECTORY:
+                for entry2 in os.ilistdir("./programs/"+entry[0]):
+                    if entry2[1] == FILE and entry2[0] == "main.py":
+                        program_list.append((entry[0], DIRECTORY))
+        
+    except OSError:
+         # Create program directory if this is a new installation
+        os.mkdir("./programs")
+        print("Program directory created")
+    if len(program_list) == 0:
+        print("Cube is empty, no programs found")
+        menu_list_size[Menu.PROGRAM] = 1
+    else:
+        menu_list_size[Menu.PROGRAM] = len(program_list)
+
+    # Loop that shows display, controls menu and starts user programs
+    while(True):
+        #print(micropython.mem_info())
+        # Connect to and reset ESP32 to BT mode if it is not running
+        
+        if not robot.esp.running() and counter % 10 == 0:
+            s = time.ticks_ms()
+            if not robot.esp.reset(100):
+                esp_reset_failed_counter += 1
+            else:
+                esp_reset_failed_counter = 0
+                esp_reset_counter = counter
+            print("ESP32 reset time: ", time.ticks_ms() - s)
+        if robot.esp.running() and counter - esp_reset_counter == 10:
+            robot.esp.set_name_nonblocking(esp_default_name, 100)
+            print("ESP BT name: ", esp_default_name)
+        
+        bat_voltage = robot.battery.voltage() # Get current battery voltage
+        button_values = robot.buttons.pressed_since() # Get buttons state
+        
+        # Move menu accordingly to pressed buttons
+        menu_move_v, menu_move_h, menu_debounce, ok_pressed = buttons(robot, 
+                                                                        button_values, robot_state,
+                                                                        menu_move_v, menu_move_h, 
+                                                                        menu_debounce)
+        # Check if buttons were pressed and move menu accordingly
+        if not bt_pair:
+            if menu_debounce == 0:
+                if sensor_test_menu == Menu.SEN_TEST_PORT:
+                    if menu_move_v != 0:
+                        sensor_test_menu_port += menu_move_v
+                        sensor_test_menu_port %= menu_list_size[SENSOR_TEST_MENU_PORT_IDX]
+                        menu_debounce = 1
+                    elif menu_move_h == -1:
+                        sensor_test_menu = Menu.SEN_TEST_PROGRAM
+                        sensor_test_menu_port = 0
+                        menu_debounce = 1
+                else:
+                    if menu_move_v != 0:
+                        menu_list[current_menu] += menu_move_v
+                        menu_list[current_menu] %= menu_list_size[current_menu] 
+                        menu_debounce = 1
+                    elif menu_move_h != 0:
+                        menu_list[current_menu] = 0
+                        current_menu += menu_move_h
+                        current_menu %= Menu.COUNT
+                        bt_pair = False
+                        menu_debounce = 1
+
+        if current_menu == Menu.BT:
+            display_fill_bt_menu(robot, esp_default_name, esp_reset_failed_counter)
+            # Request BT pair pin every 10 cycles 
+            if robot.esp.running() and counter % 10 == 0:
+                bt_pair, pin = send_esp_req(robot)
+                if pin != None and pin == rejected_pin:
+                    bt_pair = False
+                if not bt_pair:
+                    bt_connecting = False
+            # Show BT pair pin request on display and send confirm or cancel
+            if bt_pair:
+                display_fill_bt_pin(robot, pin, bt_connecting)
+                if ok_pressed:
+                    robot.esp.send_pair()
+                    bt_connecting = True
+                    menu_debounce = 1
+                elif menu_move_h == -1:
+                    rejected_pin = pin
+                    robot.esp.send_cancel()
+                    menu_debounce = 1
+
+        elif current_menu == Menu.MOT_TEST:
+            chosen_motor_port = menu_list[current_menu]
+            display_fill_mot_test(robot, chosen_motor_port)
+            if ok_pressed:
+                robot_state = 1
+                program_name = f"Motor M{chosen_motor_port+1}"
+                print("Running motor test: ", program_name)
+                try:
+                    robot.buttons.pressed_since()
+                    menu_programs.motor_run(robot, chosen_motor_port)
+                except Exception as e:
+                    sys.print_exception(e)
+                    log_error(robot.start_time, e, program_name)
+                    display_show_error(robot)
+                robot.deinit_all()
+                robot_state = 0
+                menu_debounce = 1
+                continue
+
+        elif current_menu == Menu.SEN_TEST:
+            sensor_test_menu_stype = menu_list[current_menu]
+            display_fill_sen_test(robot, sensor_test_menu_port, sensor_test_menu, 
+                                  sensor_test_menu_stype, 
+                                  menu_programs_functions[sensor_test_menu_stype][0])
+            if ok_pressed:
+                if sensor_test_menu == Menu.SEN_TEST_PROGRAM:
+                    if sensor_test_menu_stype == MENU_PROGRAM_NXT_UTZ_IDX:
+                        robot_state = 1
+                        program_name = menu_programs_functions[sensor_test_menu_stype][0]
+                        print("Running sensor test: ", program_name)
+                        try:
+                            robot.buttons.pressed_since()
+                            menu_programs_functions[sensor_test_menu_stype][1](robot)
+                        except Exception as e:
+                            sys.print_exception(e)
+                            log_error(robot.start_time, e, program_name)
+                            display_show_error(robot)
+                        robot.deinit_all()
+                        robot_state = 0
+                        menu_debounce = 1
+                        continue
+                    else:
+                        sensor_test_menu = Menu.SEN_TEST_PORT
+                        menu_debounce = 1
+                elif sensor_test_menu == Menu.SEN_TEST_PORT:
+                    
+                    robot_state = 1
+                    program_name = menu_programs_functions[sensor_test_menu_stype][0]
+                    print("Running sensor test: ", program_name)
+                    try:
+                        robot.buttons.pressed_since()
+                        menu_programs_functions[sensor_test_menu_stype][1](robot, sensor_test_menu_port)
+                    except Exception as e:
+                        sys.print_exception(e)
+                        log_error(robot.start_time, e, program_name)
+                        display_show_error(robot)
+                    robot.deinit_all()
+                    sensor_test_menu = Menu.SEN_TEST_PROGRAM
+                    sensor_test_menu_port = 0
+                    robot_state = 0
+                    menu_debounce = 1
+                    ok_pressed = 0
+                    continue
+                
+        elif current_menu == Menu.CUBE_TEST:
+            cube_test_menu_program = menu_list[current_menu]
+            cube_test_menu_name = menu_cube_programs_functions[cube_test_menu_program][0]
+            display_fill_cube_test(robot, menu_list[current_menu], cube_test_menu_name)
+            if ok_pressed:
+                robot_state = 1
+                print("Running cube test: ", cube_test_menu_name)
+                try:
+                    robot.buttons.pressed_since()
+                    menu_cube_programs_functions[cube_test_menu_program][1](robot)
+                except Exception as e:
+                    sys.print_exception(e)
+                    log_error(robot.start_time, e, cube_test_menu_name)
+                    display_show_error(robot)
+                    
+                robot.deinit_all()
+                robot_state = 0
+                menu_debounce = 1
+                continue
+
+        elif current_menu == Menu.PROGRAM:
+            current_program = menu_list[current_menu]
+            display_fill_programs(robot, program_list, current_program)
+            # Check if OK button was pressed and start user program
+            if ok_pressed and len(program_list) > 0:
+                robot_state = 1
+                program_name = program_list[current_program][0]
+                program_path = "./programs/" + program_name
+                if program_list[current_program][1] == DIRECTORY:
+                    program_path += "/main.py"
+                run_program(robot, program_name, program_path, {'robot': robot})
+                robot_state = 0
+                menu_debounce = 1
+                continue
+        elif current_menu == Menu.FW_VERSION:
+            if ok_pressed:
+                display_show_boot(robot)
+                machine.bootloader()
+            display_fill_fw_version(robot, FW_VERSION)
+            
+        display_fill_battery(robot, bat_voltage)
+        robot.display.show()
+        counter += 1
+        time.sleep(0.05)
\ No newline at end of file
diff --git a/lib/robot_consts.py b/lib/robot_consts.py
index 1ff807ef8a9df336268f1c081367befd7d3fdea7..8289caae00ca66fa3b1945605cf5ee3de1109a53 100644
--- a/lib/robot_consts.py
+++ b/lib/robot_consts.py
@@ -97,4 +97,6 @@ DISPLAY_WIDTH = const(128)
 DISPLAY_HEIGHT = const(64)
 
 WDT_TIMEOUT = const(4000)      # ms
-WDT_FEED_TIMER_PERIOD = const(3500) # ms
\ No newline at end of file
+WDT_FEED_TIMER_PERIOD = const(3500) # ms
+
+MAX_ERROR_LOG_SIZE = const(10000)
\ No newline at end of file
diff --git a/lib/utils/utils.py b/lib/utils/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd10a1c03ad3488e36464bb2b878b4c09aee6f0e
--- /dev/null
+++ b/lib/utils/utils.py
@@ -0,0 +1,22 @@
+import os, time, sys
+from micropython import const
+
+from lib.robot_consts import MAX_ERROR_LOG_SIZE
+
+FILE_SIZE_IDX = const(6)
+
+def log_error(start_time, e, program_name):
+        # Write error to error log file
+        log_deleted = False
+        if "error_log.txt" in os.listdir(".") and os.stat("error_log.txt")[FILE_SIZE_IDX] > MAX_ERROR_LOG_SIZE:
+            os.remove("error_log.txt")
+            log_deleted = True
+        with open("error_log.txt", "a") as f:
+            if log_deleted:
+                print("Previous log too long, file deleted")
+                f.write("Previous log too long, file deleted\n")
+                f.write("--------------------------------------------------\n")
+            f.write(f"ERROR program: {program_name}, time since reset: {int(time.ticks_diff(time.ticks_ms(),start_time))} ms\n")
+            if e:
+                sys.print_exception(e, f)
+            f.write("--------------------------------------------------\n")
\ No newline at end of file
diff --git a/main/main.py b/main/main.py
index 5007257449ddede7f83cfe4513c036f68c21c35b..df677aa12c77934862fb44e6cabda80849fd63df 100644
--- a/main/main.py
+++ b/main/main.py
@@ -1,358 +1,17 @@
-import micropython
-# Allocate exception buffer for interrupt handlers
-micropython.alloc_emergency_exception_buf(100)
+import machine, sys
 
-import machine
-from lib.robot import Robot
-from lib.menu_display import display_show_startup
+from lib import menu
+from lib.utils.utils import log_error
 
-# Initialize global robot object
-robot = Robot()
-# machine.WDT_RESET = hard and soft reboot or WDT reboot
-display_show_startup(robot, machine.WDT_RESET == machine.reset_cause())
-
-import time
-import os
-import sys
-import gc
-
-import menu_programs
-
-from lib.robot_consts import Button, Port, FW_VERSION
-from lib.menu_display import *
-try:
-    from config import esp_default_name, battery_multiplier
-except:
-    from lib.default_config import esp_default_name, battery_multiplier
-
-robot.battery.set_multiplier(battery_multiplier)
-
-def main():
-    # File and directory constants for browsing user programs
-    FILE = 0x8000
-    DIRECTORY = 0x4000
-    FILE_SIZE_IDX = 6
-    MAX_ERROR_LOG_SIZE = 10000
-    
-    menu_programs_functions = (('NXT Light', menu_programs.nxt_light_run), ('NXT Sound', menu_programs.nxt_sound_run), 
-                               ('NXT Touch', menu_programs.nxt_touch_run), ('NXT Ultrasonic',  menu_programs.nxt_ultra_run),
-                               ('EV3 Color', menu_programs.ev3_color_run), ('EV3 Gyro', menu_programs.ev3_gyro_run),
-                               ('EV3 Infrared', menu_programs.ev3_infra_run), ('EV3 Ultrasonic', menu_programs.ev3_ultra_run),
-                               ('EV3 & OC Touch', menu_programs.ev3_oc_touch_run),
-                               ('OC Color', menu_programs.oc_color_run), ('OC AHRS', menu_programs.oc_gyro_run), 
-                               ('OC Laser', menu_programs.oc_laser_run), ('OC Ultrasonic', menu_programs.oc_ultra_run))
-    MENU_PROGRAM_NXT_UTZ_IDX = 3
-    menu_programs_functions_size = len(menu_programs_functions)
-
-    menu_cube_programs_functions = (('Gyro Acc', menu_programs.cube_gyro_acc_run), ('LED & buzzer', menu_programs.cube_utility_run), 
-                                    ('Wifi webserver', menu_programs.esp_wifi_run), ('I2C Master', menu_programs.i2c_master_run),
-                                    ('I2C Slave', menu_programs.i2c_slave_run))
-    menu_cube_programs_functions_size = len(menu_cube_programs_functions)
-    
-    menu_list = [0, 0, 0, 0, 0, 0, 0]
-    menu_list_size = [0, Port.M_COUNT, menu_programs_functions_size, menu_cube_programs_functions_size, 1, 1, Port.S_COUNT]
-    SENSOR_TEST_MENU_PORT_IDX = 6   
-
-    def log_error(robot, e, program_name):
-        # Write error to error log file
-        log_deleted = False
-        if "error_log.txt" in os.listdir(".") and os.stat("error_log.txt")[FILE_SIZE_IDX] > MAX_ERROR_LOG_SIZE:
-            os.remove("error_log.txt")
-            log_deleted = True
-        with open("error_log.txt", "a") as f:
-            if log_deleted:
-                print("Previous log too long, file deleted")
-                f.write("Previous log too long, file deleted\n")
-                f.write("--------------------------------------------------\n")
-            f.write(f"ERROR program: {program_name}, time since reset: {int(time.ticks_diff(time.ticks_ms(),robot.start_time))} ms\n")
-            if e:
-                sys.print_exception(e, f)
-            f.write("--------------------------------------------------\n")
-
-    # Analyze pressed buttons for menu movement 
-    def buttons(robot, button_values, robot_state, menu_move_v, menu_move_h, menu_debounce): 
-        menu_move_v=0
-        menu_move_h=0
-        ok_pressed = 0
-        if menu_debounce == 0:
-            if button_values[Button.OK]:
-                ok_pressed = 1
-            elif robot_state == 0:
-                if button_values[Button.DOWN]:
-                    menu_move_v=1
-                elif button_values[Button.UP]:
-                    menu_move_v=-1
-                elif button_values[Button.RIGHT]:
-                    menu_move_h=1
-                elif button_values[Button.LEFT]:
-                    menu_move_h=-1
-        
-        # Buttons debounce
-        if (not button_values[Button.UP] and not button_values[Button.DOWN] and not button_values[Button.OK] 
-            and not button_values[Button.RIGHT] and not button_values[Button.LEFT]):
-            if robot_state == 0 and menu_debounce == 1:
-                menu_move_v=0
-                menu_move_h=0
-                ok_pressed = 0
-                menu_debounce = 0
-        return menu_move_v, menu_move_h, menu_debounce, ok_pressed
-    
-    # Request ESP32 for BT pair pin
-    def send_esp_req(robot):
-        pin = robot.esp.req_bt_pin()
-        robot.esp.flush()
-        if pin is not None and pin != -1:
-            bt_pair = True
-        else:
-            bt_pair = False
-        if pin == -1:
-            robot.esp.flush()
-            robot.esp.timeout()
-        return bt_pair, pin
-    
-    def run_program(robot, program_name, program_path, globals):
-        print("Running program", program_name)
-        display_show_program(robot)
+while True:
+    try:
+        menu.main()
+    except Exception as e:
         try:
-            # Open user program and execute it           
-            with open(program_path) as f:
-                code = compile(f.read(), program_name, 'exec')
-                robot.buttons.pressed_since()
-                exec(code, globals)
-        except Exception as e:
-            # Print exception for debugging and show error message on display 
-            # if error occurs in user program
+            print("Fatal Open-Cube error in menu:")
             sys.print_exception(e)
-            log_error(robot, e, program_name)
-            display_show_error(robot)
-            time.sleep(1.0)
-        finally:
-            # Deinit all sensors, motors and uart if initialized by user program 
-            # after user program ends
-            robot.deinit_all()
-            # Collect unreachable objects (this deinitializes EV3 motors & sensors)
-            gc.collect()
-            robot.esp.esp_running = False
-            print("Program finished\n")
-    time.sleep_ms(200) # wait for all components of the Cube to start
-    
-    # Initialize variables
-    robot_state = 0
-    menu_move_v, menu_move_h = 0, 0
-    menu_debounce = 0
-    current_menu = Menu.PROGRAM
-    sensor_test_menu = Menu.SEN_TEST_PROGRAM
-    sensor_test_menu_port = 0
-    counter = 1
-    rejected_pin = 0
-    bt_pair = False
-    bt_connecting = False
-    button_values = robot.buttons.pressed()
-    esp_reset_failed_counter = 0
-
-    # Get a list of user programs
-    program_list = []
-    try:
-        # Browse programs directory 
-        for entry in os.ilistdir("./programs"):
-            # Add .py user program to program list
-            if entry[1] == FILE and entry[0].endswith(".py"):
-                program_list.append((entry[0], FILE))
-            # Add all directory user program to program list
-            elif entry[1] == DIRECTORY:
-                for entry2 in os.ilistdir("./programs/"+entry[0]):
-                    if entry2[1] == FILE and entry2[0] == "main.py":
-                        program_list.append((entry[0], DIRECTORY))
-        
-    except OSError:
-         # Create program directory if this is a new installation
-        os.mkdir("./programs")
-        print("Program directory created")
-    if len(program_list) == 0:
-        print("Cube is empty, no programs found")
-        menu_list_size[Menu.PROGRAM] = 1
-    else:
-        menu_list_size[Menu.PROGRAM] = len(program_list)
-
-    # Loop that shows display, controls menu and starts user programs
-    while(True):
-        #print(micropython.mem_info())
-        # Connect to and reset ESP32 to BT mode if it is not running
-        
-        if not robot.esp.running() and counter % 10 == 0:
-            s = time.ticks_ms()
-            if not robot.esp.reset(100):
-                esp_reset_failed_counter += 1
-            else:
-                esp_reset_failed_counter = 0
-                esp_reset_counter = counter
-            print("ESP32 reset time: ", time.ticks_ms() - s)
-        if robot.esp.running() and counter - esp_reset_counter == 10:
-            robot.esp.set_name_nonblocking(esp_default_name, 100)
-            print("ESP BT name: ", esp_default_name)
-        
-        bat_voltage = robot.battery.voltage() # Get current battery voltage
-        button_values = robot.buttons.pressed_since() # Get buttons state
-        
-        # Move menu accordingly to pressed buttons
-        menu_move_v, menu_move_h, menu_debounce, ok_pressed = buttons(robot, 
-                                                                        button_values, robot_state,
-                                                                        menu_move_v, menu_move_h, 
-                                                                        menu_debounce)
-        # Check if buttons were pressed and move menu accordingly
-        if not bt_pair:
-            if menu_debounce == 0:
-                if sensor_test_menu == Menu.SEN_TEST_PORT:
-                    if menu_move_v != 0:
-                        sensor_test_menu_port += menu_move_v
-                        sensor_test_menu_port %= menu_list_size[SENSOR_TEST_MENU_PORT_IDX]
-                        menu_debounce = 1
-                    elif menu_move_h == -1:
-                        sensor_test_menu = Menu.SEN_TEST_PROGRAM
-                        sensor_test_menu_port = 0
-                        menu_debounce = 1
-                else:
-                    if menu_move_v != 0:
-                        menu_list[current_menu] += menu_move_v
-                        menu_list[current_menu] %= menu_list_size[current_menu] 
-                        menu_debounce = 1
-                    elif menu_move_h != 0:
-                        menu_list[current_menu] = 0
-                        current_menu += menu_move_h
-                        current_menu %= Menu.COUNT
-                        bt_pair = False
-                        menu_debounce = 1
-
-        if current_menu == Menu.BT:
-            display_fill_bt_menu(robot, esp_default_name, esp_reset_failed_counter)
-            # Request BT pair pin every 10 cycles 
-            if robot.esp.running() and counter % 10 == 0:
-                bt_pair, pin = send_esp_req(robot)
-                if pin != None and pin == rejected_pin:
-                    bt_pair = False
-                if not bt_pair:
-                    bt_connecting = False
-            # Show BT pair pin request on display and send confirm or cancel
-            if bt_pair:
-                display_fill_bt_pin(robot, pin, bt_connecting)
-                if ok_pressed:
-                    robot.esp.send_pair()
-                    bt_connecting = True
-                    menu_debounce = 1
-                elif menu_move_h == -1:
-                    rejected_pin = pin
-                    robot.esp.send_cancel()
-                    menu_debounce = 1
-
-        elif current_menu == Menu.MOT_TEST:
-            chosen_motor_port = menu_list[current_menu]
-            display_fill_mot_test(robot, chosen_motor_port)
-            if ok_pressed:
-                robot_state = 1
-                program_name = f"Motor M{chosen_motor_port+1}"
-                print("Running motor test: ", program_name)
-                try:
-                    robot.buttons.pressed_since()
-                    menu_programs.motor_run(robot, chosen_motor_port)
-                except Exception as e:
-                    sys.print_exception(e)
-                    log_error(robot, e, program_name)
-                    display_show_error(robot)
-                robot.deinit_all()
-                robot_state = 0
-                menu_debounce = 1
-                continue
-
-        elif current_menu == Menu.SEN_TEST:
-            sensor_test_menu_stype = menu_list[current_menu]
-            display_fill_sen_test(robot, sensor_test_menu_port, sensor_test_menu, 
-                                  sensor_test_menu_stype, 
-                                  menu_programs_functions[sensor_test_menu_stype][0])
-            if ok_pressed:
-                if sensor_test_menu == Menu.SEN_TEST_PROGRAM:
-                    if sensor_test_menu_stype == MENU_PROGRAM_NXT_UTZ_IDX:
-                        robot_state = 1
-                        program_name = menu_programs_functions[sensor_test_menu_stype][0]
-                        print("Running sensor test: ", program_name)
-                        try:
-                            robot.buttons.pressed_since()
-                            menu_programs_functions[sensor_test_menu_stype][1](robot)
-                        except Exception as e:
-                            sys.print_exception(e)
-                            log_error(robot, e, program_name)
-                            display_show_error(robot)
-                        robot.deinit_all()
-                        robot_state = 0
-                        menu_debounce = 1
-                        continue
-                    else:
-                        sensor_test_menu = Menu.SEN_TEST_PORT
-                        menu_debounce = 1
-                elif sensor_test_menu == Menu.SEN_TEST_PORT:
-                    
-                    robot_state = 1
-                    program_name = menu_programs_functions[sensor_test_menu_stype][0]
-                    print("Running sensor test: ", program_name)
-                    try:
-                        robot.buttons.pressed_since()
-                        menu_programs_functions[sensor_test_menu_stype][1](robot, sensor_test_menu_port)
-                    except Exception as e:
-                        sys.print_exception(e)
-                        log_error(robot, e, program_name)
-                        display_show_error(robot)
-                    robot.deinit_all()
-                    sensor_test_menu = Menu.SEN_TEST_PROGRAM
-                    sensor_test_menu_port = 0
-                    robot_state = 0
-                    menu_debounce = 1
-                    ok_pressed = 0
-                    continue
-                
-        elif current_menu == Menu.CUBE_TEST:
-            cube_test_menu_program = menu_list[current_menu]
-            cube_test_menu_name = menu_cube_programs_functions[cube_test_menu_program][0]
-            display_fill_cube_test(robot, menu_list[current_menu], cube_test_menu_name)
-            if ok_pressed:
-                robot_state = 1
-                print("Running cube test: ", cube_test_menu_name)
-                try:
-                    robot.buttons.pressed_since()
-                    menu_cube_programs_functions[cube_test_menu_program][1](robot)
-                except Exception as e:
-                    sys.print_exception(e)
-                    log_error(robot, e, cube_test_menu_name)
-                    display_show_error(robot)
-                    
-                robot.deinit_all()
-                robot_state = 0
-                menu_debounce = 1
-                continue
-
-        elif current_menu == Menu.PROGRAM:
-            current_program = menu_list[current_menu]
-            display_fill_programs(robot, program_list, current_program)
-            # Check if OK button was pressed and start user program
-            if ok_pressed and len(program_list) > 0:
-                robot_state = 1
-                program_name = program_list[current_program][0]
-                program_path = "./programs/" + program_name
-                if program_list[current_program][1] == DIRECTORY:
-                    program_path += "/main.py"
-                run_program(robot, program_name, program_path, {'robot': robot})
-                robot_state = 0
-                menu_debounce = 1
-                continue
-        elif current_menu == Menu.FW_VERSION:
-            if ok_pressed:
-                display_show_boot(robot)
-                machine.bootloader()
-            display_fill_fw_version(robot, FW_VERSION)
-            
-        display_fill_battery(robot, bat_voltage)
-        robot.display.show()
-        counter += 1
-        time.sleep(0.05)
-
+            log_error(0, e, "Open-Cube menu.py")
+        except:
+            break
 
-if __name__ == '__main__':
-    main()
\ No newline at end of file
+machine.reset()
\ No newline at end of file
diff --git a/micropython/mpy b/micropython/mpy
index af2770e02c1fcd9e6517223ae81c9a0d089a23e1..f1018ee5c2dd0eabcc0cfe7e02c607594e489788 160000
--- a/micropython/mpy
+++ b/micropython/mpy
@@ -1 +1 @@
-Subproject commit af2770e02c1fcd9e6517223ae81c9a0d089a23e1
+Subproject commit f1018ee5c2dd0eabcc0cfe7e02c607594e489788