diff --git a/arduino_alvik/__init__.py b/arduino_alvik/__init__.py new file mode 100644 index 0000000..72f6180 --- /dev/null +++ b/arduino_alvik/__init__.py @@ -0,0 +1 @@ +from .arduino_alvik import * diff --git a/arduino_alvik.py b/arduino_alvik/arduino_alvik.py similarity index 79% rename from arduino_alvik.py rename to arduino_alvik/arduino_alvik.py index 8ae435c..506295f 100644 --- a/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -1,24 +1,25 @@ import sys import gc import struct - from machine import I2C -from uart import uart import _thread from time import sleep_ms from ucPack import ucPack -from conversions import * -from pinout_definitions import * -from robot_definitions import * -from constants import * +from .uart import uart +from .conversions import * +from .pinout_definitions import * +from .robot_definitions import * +from .constants import * class ArduinoAlvik: _update_thread_running = False _update_thread_id = None + _touch_events_thread_running = False + _touch_events_thread_id = None def __new__(cls): if not hasattr(cls, '_instance'): @@ -68,6 +69,7 @@ def __init__(self): self._angular_velocity = None self._last_ack = '' self._version = [None, None, None] + self._touch_events = _ArduinoAlvikTouchEvents() @staticmethod def is_on() -> bool: @@ -135,7 +137,7 @@ def _idle(self, delay_=1, check_on_thread=False) -> None: sys.exit() except Exception as e: pass - #print(f'Unable to read SOC: {e}') + # print(f'Unable to read SOC: {e}') finally: LEDR.value(1) LEDG.value(1) @@ -179,6 +181,9 @@ def begin(self) -> int: self._idle(1000) self._begin_update_thread() sleep_ms(100) + if self._touch_events.has_callbacks(): + print('Starting touch events') + self._start_touch_events_thread() self._reset_hw() self._flush_uart() self._snake_robot(1000) @@ -293,9 +298,12 @@ def stop(self): # turn off UI leds self._set_leds(0x00) - # stop the update thrad + # stop the update thread self._stop_update_thread() + # stop touch events thread + self._stop_touch_events_thread() + # delete _instance del self.__class__._instance gc.collect() @@ -953,6 +961,99 @@ def print_status(self): continue print(f'{str(a).upper()} = {getattr(self, str(a))}') + def on_touch_ok_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button OK is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_ok_pressed', callback, args) + + def on_touch_cancel_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button CANCEL is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_cancel_pressed', callback, args) + + def on_touch_center_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button CENTER is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_center_pressed', callback, args) + + def on_touch_up_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button UP is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_up_pressed', callback, args) + + def on_touch_left_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button LEFT is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_left_pressed', callback, args) + + def on_touch_down_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button DOWN is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_down_pressed', callback, args) + + def on_touch_right_pressed(self, callback: callable, args: tuple = ()) -> None: + """ + Register callback when touch button RIGHT is pressed + :param callback: + :param args: + :return: + """ + self._touch_events.register_callback('on_right_pressed', callback, args) + + def _start_touch_events_thread(self) -> None: + """ + Starts the touch events thread + :return: + """ + if not self.__class__._touch_events_thread_running: + self.__class__._touch_events_thread_running = True + self.__class__._touch_events_thread_id = _thread.start_new_thread(self._update_touch_events, (50,)) + + def _update_touch_events(self, delay_: int = 100): + """ + Updates the touch state so that touch events can be generated + :param delay_: + :return: + """ + while True: + if self.is_on() and self._touch_byte is not None: + self._touch_events.update_touch_state(self._touch_byte) + if not ArduinoAlvik._touch_events_thread_running: + break + sleep_ms(delay_) + + @classmethod + def _stop_touch_events_thread(cls): + """ + Stops the touch events thread + :return: + """ + cls._touch_events_thread_running = False + class _ArduinoAlvikWheel: @@ -1065,3 +1166,159 @@ def set_color(self, red: bool, green: bool, blue: bool): self._led_state[0] = led_status self._packeter.packetC1B(ord('L'), led_status & 0xFF) uart.write(self._packeter.msg[0:self._packeter.msg_size]) + + +class _ArduinoAlvikEvents: + """ + This is a generic events class + """ + + def __init__(self): + self._callbacks = dict() + + def register_callback(self, event_name: str, callback: callable, args: tuple = None): + """ + Registers a callback to execute on an event + :param event_name: + :param callback: the callable + :param args: arguments tuple to pass to the callable. remember the comma! (value,) + :return: + """ + self._callbacks[event_name] = (callback, args,) + + def has_callbacks(self) -> bool: + """ + True if the _callbacks dictionary has any callback registered + :return: + """ + return bool(self._callbacks) + + def execute_callback(self, event_name: str): + """ + Executes the callback associated to the event_name + :param event_name: + :return: + """ + if event_name not in self._callbacks.keys(): + return + self._callbacks[event_name][0](*self._callbacks[event_name][1]) + + +class _ArduinoAlvikTouchEvents(_ArduinoAlvikEvents): + """ + This is the event class to handle touch button events + """ + + available_events = ['on_ok_pressed', 'on_cancel_pressed', + 'on_center_pressed', 'on_left_pressed', + 'on_right_pressed', 'on_up_pressed', + 'on_down_pressed'] + + def __init__(self): + self._current_touch_state = 0 + super().__init__() + + @staticmethod + def _is_ok_pressed(current_state, new_state) -> bool: + """ + True if OK was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b00000010) and bool(new_state & 0b00000010) + + @staticmethod + def _is_cancel_pressed(current_state, new_state) -> bool: + """ + True if CANCEL was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b00000100) and bool(new_state & 0b00000100) + + @staticmethod + def _is_center_pressed(current_state, new_state) -> bool: + """ + True if CENTER was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b00001000) and bool(new_state & 0b00001000) + + @staticmethod + def _is_up_pressed(current_state, new_state) -> bool: + """ + True if UP was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b00010000) and bool(new_state & 0b00010000) + + @staticmethod + def _is_left_pressed(current_state, new_state) -> bool: + """ + True if LEFT was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b00100000) and bool(new_state & 0b00100000) + + @staticmethod + def _is_down_pressed(current_state, new_state) -> bool: + """ + True if DOWN was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b01000000) and bool(new_state & 0b01000000) + + @staticmethod + def _is_right_pressed(current_state, new_state) -> bool: + """ + True if RIGHT was pressed + :param current_state: + :param new_state: + :return: + """ + return not bool(current_state & 0b10000000) and bool(new_state & 0b10000000) + + def update_touch_state(self, touch_state: int): + """ + Updates the internal touch state and executes any possible callback + :param touch_state: + :return: + """ + + if self._is_ok_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_ok_pressed') + + if self._is_cancel_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_cancel_pressed') + + if self._is_center_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_center_pressed') + + if self._is_up_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_up_pressed') + + if self._is_left_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_left_pressed') + + if self._is_down_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_down_pressed') + + if self._is_right_pressed(self._current_touch_state, touch_state): + self.execute_callback('on_right_pressed') + + self._current_touch_state = touch_state + + def register_callback(self, event_name: str, callback: callable, args: tuple = None): + if event_name not in self.__class__.available_events: + return + super().register_callback(event_name, callback, args) diff --git a/constants.py b/arduino_alvik/constants.py similarity index 100% rename from constants.py rename to arduino_alvik/constants.py diff --git a/conversions.py b/arduino_alvik/conversions.py similarity index 100% rename from conversions.py rename to arduino_alvik/conversions.py diff --git a/utilities/firmware_updater.py b/arduino_alvik/firmware_updater.py similarity index 100% rename from utilities/firmware_updater.py rename to arduino_alvik/firmware_updater.py diff --git a/pinout_definitions.py b/arduino_alvik/pinout_definitions.py similarity index 100% rename from pinout_definitions.py rename to arduino_alvik/pinout_definitions.py diff --git a/robot_definitions.py b/arduino_alvik/robot_definitions.py similarity index 100% rename from robot_definitions.py rename to arduino_alvik/robot_definitions.py diff --git a/utilities/stm32_flash.py b/arduino_alvik/stm32_flash.py similarity index 100% rename from utilities/stm32_flash.py rename to arduino_alvik/stm32_flash.py diff --git a/uart.py b/arduino_alvik/uart.py similarity index 100% rename from uart.py rename to arduino_alvik/uart.py diff --git a/examples/touch_events.py b/examples/touch_events.py new file mode 100644 index 0000000..db2d64f --- /dev/null +++ b/examples/touch_events.py @@ -0,0 +1,57 @@ +from arduino_alvik import ArduinoAlvik +from time import sleep +import sys + +value = 0 + + +def toggle_left_led(custom_text: str = '') -> None: + global value + value = (value + 1) % 2 + alvik.left_led.set_color(value, 0, 0) + print(f"RED BLINKS! {custom_text}") + + +def simple_print(custom_text: str = '') -> None: + print(custom_text) + +alvik = ArduinoAlvik() +alvik.on_touch_ok_pressed(toggle_left_led, ("OK WAS PRESSED... THAT'S COOL", )) +alvik.on_touch_center_pressed(simple_print, ("CENTER PRESSED",)) +alvik.on_touch_cancel_pressed(simple_print, ("CANCEL PRESSED",)) +alvik.on_touch_up_pressed(simple_print, ("UP PRESSED",)) +alvik.on_touch_left_pressed(simple_print, ("LEFT PRESSED",)) +alvik.on_touch_down_pressed(simple_print, ("DOWN PRESSED",)) +alvik.on_touch_right_pressed(simple_print, ("RIGHT PRESSED",)) + +alvik.begin() + +alvik.left_wheel.reset() +alvik.right_wheel.reset() + +while True: + try: + alvik.left_wheel.set_position(30) + sleep(2) + print(f'Left wheel degs: {alvik.left_wheel.get_position()}') + print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + + alvik.right_wheel.set_position(10) + sleep(2) + print(f'Left wheel degs: {alvik.left_wheel.get_position()}') + print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + + alvik.left_wheel.set_position(180) + sleep(2) + print(f'Left wheel degs: {alvik.left_wheel.get_position()}') + print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + + alvik.right_wheel.set_position(270) + sleep(2) + print(f'Left wheel degs: {alvik.left_wheel.get_position()}') + print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + + except KeyboardInterrupt as e: + print('over') + alvik.stop() + sys.exit() diff --git a/install.bat b/install.bat index 2e81c7c..4e17379 100644 --- a/install.bat +++ b/install.bat @@ -16,19 +16,15 @@ if /i "%1"=="-h" ( ) :install -python -m mpremote %port_string% fs rm :arduino_alvik.py -python -m mpremote %port_string% fs rm :constants.py -python -m mpremote %port_string% fs rm :conversions.py -python -m mpremote %port_string% fs rm :pinout_definitions.py -python -m mpremote %port_string% fs rm :robot_definitions.py -python -m mpremote %port_string% fs rm :uart.py -python -m mpremote %port_string% fs cp arduino_alvik.py :arduino_alvik.py -python -m mpremote %port_string% fs cp constants.py :constants.py -python -m mpremote %port_string% fs cp conversions.py :conversions.py -python -m mpremote %port_string% fs cp pinout_definitions.py :pinout_definitions.py -python -m mpremote %port_string% fs cp robot_definitions.py :robot_definitions.py -python -m mpremote %port_string% fs cp uart.py :uart.py +python -m mpremote %port_string% fs mkdir lib/arduino_alvik +python -m mpremote %port_string% fs cp arduino_alvik/__init__.py :lib/arduino_alvik/__init__.py +python -m mpremote %port_string% fs cp arduino_alvik/arduino_alvik.py :lib/arduino_alvik/arduino_alvik.py +python -m mpremote %port_string% fs cp arduino_alvik/constants.py :lib/arduino_alvik/constants.py +python -m mpremote %port_string% fs cp arduino_alvik/conversions.py :lib/arduino_alvik/conversions.py +python -m mpremote %port_string% fs cp arduino_alvik/pinout_definitions.py :lib/arduino_alvik/pinout_definitions.py +python -m mpremote %port_string% fs cp arduino_alvik/robot_definitions.py :lib/arduino_alvik/robot_definitions.py +python -m mpremote %port_string% fs cp arduino_alvik/uart.py :lib/arduino_alvik/uart.py echo Installing dependencies python -m mpremote %port_string% mip install github:arduino/ucPack-mpy diff --git a/install.sh b/install.sh index c5950d4..736166c 100644 --- a/install.sh +++ b/install.sh @@ -42,19 +42,14 @@ fi # Uncomment the following line on windows machines # python_command="python" -$python_command -m mpremote $connect_string fs rm :arduino_alvik.py -$python_command -m mpremote $connect_string fs rm :constants.py -$python_command -m mpremote $connect_string fs rm :conversions.py -$python_command -m mpremote $connect_string fs rm :pinout_definitions.py -$python_command -m mpremote $connect_string fs rm :robot_definitions.py -$python_command -m mpremote $connect_string fs rm :uart.py - -$python_command -m mpremote $connect_string fs cp arduino_alvik.py :arduino_alvik.py -$python_command -m mpremote $connect_string fs cp constants.py :constants.py -$python_command -m mpremote $connect_string fs cp conversions.py :conversions.py -$python_command -m mpremote $connect_string fs cp pinout_definitions.py :pinout_definitions.py -$python_command -m mpremote $connect_string fs cp robot_definitions.py :robot_definitions.py -$python_command -m mpremote $connect_string fs cp uart.py :uart.py +$python_command -m mpremote $connect_string fs mkdir lib/arduino_alvik +$python_command -m mpremote $connect_string fs cp arduino_alvik/__init__.py :lib/arduino_alvik/__init__.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/arduino_alvik.py :lib/arduino_alvik/arduino_alvik.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/constants.py :lib/arduino_alvik/constants.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/conversions.py :lib/arduino_alvik/conversions.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/pinout_definitions.py :lib/arduino_alvik/pinout_definitions.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/robot_definitions.py :lib/arduino_alvik/robot_definitions.py +$python_command -m mpremote $connect_string fs cp arduino_alvik/uart.py :lib/arduino_alvik/uart.py echo "Installing dependencies" $python_command -m mpremote $connect_string mip install github:arduino/ucPack-mpy diff --git a/package.json b/package.json index 72a44a7..90b6c77 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,17 @@ { "urls": [ + ["arduino_alvik/__init__.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/__init__.py"], + ["arduino_alvik/arduino_alvik.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/arduino_alvik.py"], + ["arduino_alvik/constants.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/constants.py"], + ["arduino_alvik/conversions.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/conversions.py"], + ["arduino_alvik/pinout_definitions.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/pinout_definitions.py"], + ["arduino_alvik/robot_definitions.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/robot_definitions.py"], + ["arduino_alvik/uart.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/uart.py"], + ["arduino_alvik/firmware_updater.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/firmware_updater.py"], + ["arduino_alvik/stm32_flash.py", "github:arduino/arduino-alvik-mpy/arduino_alvik/stm32_flash.py"] ], "deps": [ + ["github:arduino/ucPack-mpy", "0.1.5"] ], - "version": "0.2.0" + "version": "0.3.0" } \ No newline at end of file diff --git a/utilities/flash_firmware.bat b/utilities/flash_firmware.bat index c496dc0..f883fee 100644 --- a/utilities/flash_firmware.bat +++ b/utilities/flash_firmware.bat @@ -26,21 +26,17 @@ if "%1"=="" ( echo Installing flash firmware utilities... -python -m mpremote %port_string% fs rm :firmware_updater.py -python -m mpremote %port_string% fs rm :stm32_flash.py - -python -m mpremote %port_string% fs cp firmware_updater.py :firmware_updater.py -python -m mpremote %port_string% fs cp stm32_flash.py :stm32_flash.py +python -m mpremote %port_string% fs cp ../arduino_alvik/firmware_updater.py :firmware_updater.py +python -m mpremote %port_string% fs cp ../arduino_alvik/stm32_flash.py :stm32_flash.py echo Uploading %filename% -python -m mpremote %port_string% fs rm :firmware.bin python -m mpremote %port_string% fs cp %filename% :firmware.bin set /p userInput=Do you want to flash the firmware right now? (y/N): if /i "%userInput%"=="y" ( - python -m mpremote %port_string% run firmware_updater.py + python -m mpremote %port_string% run ../arduino_alvik/firmware_updater.py ) else ( echo The firmware will not be written to the device. ) diff --git a/utilities/flash_firmware.sh b/utilities/flash_firmware.sh index f4f1b49..c973ad8 100644 --- a/utilities/flash_firmware.sh +++ b/utilities/flash_firmware.sh @@ -53,22 +53,18 @@ fi echo "Installing flash firmware utilities..." -$python_command -m mpremote $connect_string fs rm :firmware_updater.py -$python_command -m mpremote $connect_string fs rm :stm32_flash.py - -$python_command -m mpremote $connect_string fs cp firmware_updater.py :firmware_updater.py -$python_command -m mpremote $connect_string fs cp stm32_flash.py :stm32_flash.py +$python_command -m mpremote $connect_string fs cp ../arduino_alvik/firmware_updater.py :firmware_updater.py +$python_command -m mpremote $connect_string fs cp ../arduino_alvik/stm32_flash.py :stm32_flash.py echo "Uploading $filename..." -$python_command -m mpremote $connect_string fs rm :firmware.bin $python_command -m mpremote $connect_string fs cp $filename :firmware.bin echo "Do you want to flash the firmware right now? (y/N)" read do_flash if [ "$do_flash" == "y" ] || [ "$do_flash" == "Y" ]; then - $python_command -m mpremote $connect_string run firmware_updater.py + $python_command -m mpremote $connect_string run ../arduino_alvik/firmware_updater.py else echo "The firmware will not be written to the device." fi