From 82b116969f5ffa38f3120577c36d44fc9c4c781f Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Fri, 13 Feb 2026 15:29:25 +0100 Subject: [PATCH] [UNTESTED] rework odroid into generic esp32 target --- c_mpos/micropython.cmake | 6 +- .../display/ili9341/_ili9341_init_type1.py | 114 +++++++ .../display/ili9341/_ili9341_init_type2.py | 117 +++++++ .../lib/drivers/display/ili9341/ili9341.py | 15 + .../drivers/display/st7789/_st7789_init.py | 173 ++++++++++ .../lib/drivers/display/st7789/st7789.py | 80 +++++ .../drivers => drivers/imu_sensor}/qmi8658.py | 0 .../imu_sensor}/wsen_isds.py | 0 .../lib/drivers/indev/cst816s.py | 307 ++++++++++++++++++ .../lib/{mpos => drivers}/indev/gt911.py | 0 .../indev/sdl_keyboard.py} | 0 .../lib/mpos/board/fri3d_2024.py | 5 +- .../lib/mpos/board/fri3d_2026.py | 5 +- internal_filesystem/lib/mpos/board/linux.py | 5 +- ...esp32_s3_spi_ips_2_8_with_camera_ov3660.py | 2 +- .../lib/mpos/board/odroid_go.py | 4 +- .../board/waveshare_esp32_s3_touch_lcd_2.py | 5 +- .../lib/mpos/hardware/drivers/__init__.py | 1 - .../lib/mpos/sensor_manager.py | 8 +- .../lib/mpos/ui/camera_settings.py | 2 +- scripts/build_mpos.sh | 54 +-- 21 files changed, 848 insertions(+), 55 deletions(-) create mode 100644 internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type1.py create mode 100644 internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type2.py create mode 100644 internal_filesystem/lib/drivers/display/ili9341/ili9341.py create mode 100644 internal_filesystem/lib/drivers/display/st7789/_st7789_init.py create mode 100644 internal_filesystem/lib/drivers/display/st7789/st7789.py rename internal_filesystem/lib/{mpos/hardware/drivers => drivers/imu_sensor}/qmi8658.py (100%) rename internal_filesystem/lib/{mpos/hardware/drivers => drivers/imu_sensor}/wsen_isds.py (100%) create mode 100644 internal_filesystem/lib/drivers/indev/cst816s.py rename internal_filesystem/lib/{mpos => drivers}/indev/gt911.py (100%) rename internal_filesystem/lib/{mpos/indev/mpos_sdl_keyboard.py => drivers/indev/sdl_keyboard.py} (100%) delete mode 100644 internal_filesystem/lib/mpos/hardware/drivers/__init__.py diff --git a/c_mpos/micropython.cmake b/c_mpos/micropython.cmake index 900a9f78..9f517303 100644 --- a/c_mpos/micropython.cmake +++ b/c_mpos/micropython.cmake @@ -4,9 +4,13 @@ add_library(usermod_c_mpos INTERFACE) -set(MPOS_C_INCLUDES) +set(MPOS_C_INCLUDES + ${CMAKE_CURRENT_LIST_DIR}/../lvgl_micropython/lib/micropython/ports/esp32/managed_components/espressif__esp_codec_dev/include/ + ${CMAKE_CURRENT_LIST_DIR}/../lvgl_micropython/lib/micropython/ports/esp32/managed_components/espressif__esp_codec_dev/interface/ +) set(MPOS_C_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/adc_mic.c ${CMAKE_CURRENT_LIST_DIR}/src/quirc_decode.c ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/identify.c ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/version_db.c diff --git a/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type1.py b/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type1.py new file mode 100644 index 00000000..7b973dbe --- /dev/null +++ b/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type1.py @@ -0,0 +1,114 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +import time +from micropython import const # NOQA +import lvgl as lv # NOQA + + +_PWR1 = const(0xC0) +_PWR2 = const(0xC1) +_VCOMCTL1 = const(0xC5) +_VCOMCTL2 = const(0xC7) +_MADCTL = const(0x36) +_COLMOD = const(0x3A) +_FRMCTR1 = const(0xB1) +_DFUNCTRL = const(0xB6) +_GAMSET = const(0x26) +_PGC = const(0xE0) +_NGC = const(0xE1) +_SLPOUT = const(0x11) +_DISPON = const(0x29) +_RASET = const(0x2B) +_CASET = const(0x2A) +_PWRCTRLB = const(0xCF) +_PWRONSQCTRL = const(0xED) +_DRVTIMCTRLA1 = const(0xE8) +_PWRCTRLA = const(0xCB) +_PUMPRATIOCTRL = const(0xF7) +_DRVTIMCTRLB = const(0xEA) +_ENA3GAMMA = const(0xF2) + + +def init(self): + param_buf = bytearray(15) + param_mv = memoryview(param_buf) + + param_buf[:3] = bytearray([0x03, 0x80, 0x02]) + self.set_params(0xEF, param_mv[:3]) + + param_buf[:3] = bytearray([0x00, 0XC1, 0X30]) + self.set_params(_PWRCTRLB, param_mv[:3]) + + param_buf[:4] = bytearray([0x64, 0x03, 0X12, 0X81]) + self.set_params(_PWRONSQCTRL, param_mv[:4]) + + param_buf[:3] = bytearray([0x85, 0x00, 0x78]) + self.set_params(_DRVTIMCTRLA1, param_mv[:3]) + + param_buf[:5] = bytearray([0x39, 0x2C, 0x00, 0x34, 0x02]) + self.set_params(_PWRCTRLA, param_mv[:5]) + + param_buf[0] = 0x20 + self.set_params(_PUMPRATIOCTRL, param_mv[:1]) + + param_buf[:2] = bytearray([0x00, 0x00]) + self.set_params(_DRVTIMCTRLB, param_mv[:2]) + + param_buf[0] = 0x23 + self.set_params(_PWR1, param_mv[:1]) + + param_buf[0] = 0x10 + self.set_params(_PWR2, param_mv[:1]) + + param_buf[:2] = bytearray([0x3e, 0x28]) + self.set_params(_VCOMCTL1, param_mv[:2]) + + param_buf[0] = 0x86 + self.set_params(_VCOMCTL2, param_mv[:1]) + + param_buf[0] = ( + self._madctl( + self._color_byte_order, + self._ORIENTATION_TABLE # NOQA + ) + ) + self.set_params(_MADCTL, param_mv[:1]) + + color_size = lv.color_format_get_size(self._color_space) + if color_size == 2: # NOQA + pixel_format = 0x55 + else: + raise RuntimeError( + f'{self.__class__.__name__} IC only supports ' + 'lv.COLOR_FORMAT.RGB565' + ) + + param_buf[0] = pixel_format + self.set_params(_COLMOD, param_mv[:1]) + + param_buf[:2] = bytearray([0x00, 0x13]) # 0x18 ?? + self.set_params(_FRMCTR1, param_mv[:2]) + + param_buf[:3] = bytearray([0x08, 0x82, 0x27]) + self.set_params(_DFUNCTRL, param_mv[:3]) + + param_buf[0] = 0x00 + self.set_params(_ENA3GAMMA, param_mv[:1]) + + param_buf[0] = 0x01 + self.set_params(_GAMSET, param_mv[:1]) + + param_buf[:15] = bytearray([ + 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, + 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00]) + self.set_params(_PGC, param_mv[:15]) + + param_buf[:15] = bytearray([ + 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, + 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F]) + self.set_params(_NGC, param_mv[:15]) + + self.set_params(_SLPOUT) + time.sleep_ms(120) # NOQA + self.set_params(_DISPON) + time.sleep_ms(20) # NOQA diff --git a/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type2.py b/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type2.py new file mode 100644 index 00000000..769aea31 --- /dev/null +++ b/internal_filesystem/lib/drivers/display/ili9341/_ili9341_init_type2.py @@ -0,0 +1,117 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +import time +from micropython import const # NOQA +import lvgl as lv # NOQA + + +_PWR1 = const(0xC0) +_PWR2 = const(0xC1) +_VCOMCTL1 = const(0xC5) +_VCOMCTL2 = const(0xC7) +_MADCTL = const(0x36) +_COLMOD = const(0x3A) +_FRMCTR1 = const(0xB1) +_DFUNCTRL = const(0xB6) +_GAMSET = const(0x26) +_PGC = const(0xE0) +_NGC = const(0xE1) +_SLPOUT = const(0x11) +_DISPON = const(0x29) +_RASET = const(0x2B) +_CASET = const(0x2A) +_PWRCTRLB = const(0xCF) +_PWRONSQCTRL = const(0xED) +_DRVTIMCTRLA1 = const(0xE8) +_PWRCTRLA = const(0xCB) +_PUMPRATIOCTRL = const(0xF7) +_DRVTIMCTRLB = const(0xEA) +_ENA3GAMMA = const(0xF2) + + +def init(self): + param_buf = bytearray(15) + param_mv = memoryview(param_buf) + + param_buf[:3] = bytearray([0x00, 0XC1, 0X30]) + self.set_params(_PWRCTRLB, param_mv[:3]) + + param_buf[:4] = bytearray([0x64, 0x03, 0X12, 0X81]) + self.set_params(_PWRONSQCTRL, param_mv[:4]) + + param_buf[:3] = bytearray([0x85, 0x00, 0x78]) + self.set_params(_DRVTIMCTRLA1, param_mv[:3]) + + param_buf[:5] = bytearray([0x39, 0x2C, 0x00, 0x34, 0x02]) + self.set_params(_PWRCTRLA, param_mv[:5]) + + param_buf[0] = 0x20 + self.set_params(_PUMPRATIOCTRL, param_mv[:1]) + + param_buf[:2] = bytearray([0x00, 0x00]) + self.set_params(_DRVTIMCTRLB, param_mv[:2]) + + param_buf[0] = 0x10 + self.set_params(_PWR1, param_mv[:1]) + + param_buf[0] = 0x00 + self.set_params(_PWR2, param_mv[:1]) + + param_buf[:2] = bytearray([0x30, 0x30]) + self.set_params(_VCOMCTL1, param_mv[:2]) + + param_buf[0] = 0xB7 + self.set_params(_VCOMCTL2, param_mv[:1]) + + param_buf[0] = ( + self._madctl( + self._color_byte_order, + self._ORIENTATION_TABLE # NOQA + ) + ) + self.set_params(_MADCTL, param_mv[:1]) + + color_size = lv.color_format_get_size(self._color_space) + if color_size == 2: # NOQA + pixel_format = 0x55 + else: + raise RuntimeError( + f'{self.__class__.__name__} IC only supports ' + 'lv.COLOR_FORMAT.RGB565' + ) + + param_buf[0] = pixel_format + self.set_params(_COLMOD, param_mv[:1]) + + param_buf[:2] = bytearray([0x00, 0x1A]) + self.set_params(_FRMCTR1, param_mv[:2]) + + param_buf[:3] = bytearray([0x08, 0x82, 0x27]) + self.set_params(_DFUNCTRL, param_mv[:3]) + + param_buf[0] = 0x00 + self.set_params(_ENA3GAMMA, param_mv[:1]) + + param_buf[0] = 0x01 + self.set_params(_GAMSET, param_mv[:1]) + + param_buf[:15] = bytearray([ + 0x0F, 0x2A, 0x28, 0x08, 0x0E, 0x08, 0x54, 0xA9, + 0x43, 0x0A, 0x0F, 0x00, 0x00, 0x00, 0x00]) + self.set_params(_PGC, param_mv[:15]) + + param_buf[:15] = bytearray([ + 0x00, 0x15, 0x17, 0x07, 0x11, 0x06, 0x2B, 0x56, + 0x3C, 0x05, 0x10, 0x0F, 0x3F, 0x3F, 0x0F]) + self.set_params(_NGC, param_mv[:15]) + + param_buf[:4] = bytearray([0x00, 0x00, 0x01, 0x3f]) + self.set_params(_RASET, param_mv[:4]) + + param_buf[:4] = bytearray([0x00, 0x00, 0x00, 0xef]) + self.set_params(_CASET, param_mv[:4]) + + self.set_params(_SLPOUT) + time.sleep_ms(120) # NOQA + self.set_params(_DISPON) + time.sleep_ms(20) # NOQA diff --git a/internal_filesystem/lib/drivers/display/ili9341/ili9341.py b/internal_filesystem/lib/drivers/display/ili9341/ili9341.py new file mode 100644 index 00000000..e4ac2c32 --- /dev/null +++ b/internal_filesystem/lib/drivers/display/ili9341/ili9341.py @@ -0,0 +1,15 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +import display_driver_framework + + +STATE_HIGH = display_driver_framework.STATE_HIGH +STATE_LOW = display_driver_framework.STATE_LOW +STATE_PWM = display_driver_framework.STATE_PWM + +BYTE_ORDER_RGB = display_driver_framework.BYTE_ORDER_RGB +BYTE_ORDER_BGR = display_driver_framework.BYTE_ORDER_BGR + + +class ILI9341(display_driver_framework.DisplayDriver): + pass diff --git a/internal_filesystem/lib/drivers/display/st7789/_st7789_init.py b/internal_filesystem/lib/drivers/display/st7789/_st7789_init.py new file mode 100644 index 00000000..42a21135 --- /dev/null +++ b/internal_filesystem/lib/drivers/display/st7789/_st7789_init.py @@ -0,0 +1,173 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +import time +from micropython import const # NOQA + +import lvgl as lv # NOQA +import lcd_bus + + +_SWRESET = const(0x01) +_SLPOUT = const(0x11) +_MADCTL = const(0x36) +_COLMOD = const(0x3A) +_PORCTRL = const(0xB2) +_GCTRL = const(0xB7) +_VCOMS = const(0xBB) +_LCMCTRL = const(0xC0) +_VDVVRHEN = const(0xC2) +_VRHS = const(0xC3) +_VDVSET = const(0xC4) +_FRCTR2 = const(0xC6) +_PWCTRL1 = const(0xD0) +_INVON = const(0x21) +_CASET = const(0x2A) +_RASET = const(0x2B) +_PGC = const(0xE0) +_NGC = const(0xE1) +_DISPON = const(0x29) +_NORON = const(0x13) + +_RAMCTRL = const(0xB0) +_RGB565SWAP = const(0x08) + + +def init(self): + param_buf = bytearray(14) + param_mv = memoryview(param_buf) + + self.set_params(_SWRESET) + + time.sleep_ms(120) # NOQA + + self.set_params(_SLPOUT) + + time.sleep_ms(120) # NOQA + + self.set_params(_NORON) + + param_buf[0] = ( + self._madctl( + self._color_byte_order, + self._ORIENTATION_TABLE # NOQA + ) + ) + self.set_params(_MADCTL, param_mv[:1]) + + param_buf[0] = 0x0A + param_buf[1] = 0x82 + self.set_params(0xB6, param_mv[:2]) + + # sets swapping the bytes at the hardware level. + + if ( + self._rgb565_byte_swap and + isinstance(self._data_bus, lcd_bus.I80Bus) and + self._data_bus.get_lane_count() == 8 + ): + param_buf[0] = 0x00 + param_buf[1] = 0xF0 | _RGB565SWAP + self.set_params(_RAMCTRL, param_mv[:2]) + + color_size = lv.color_format_get_size(self._color_space) + if color_size == 2: # NOQA + pixel_format = 0x55 + elif color_size == 3: + pixel_format = 0x77 + else: + raise RuntimeError( + f'{self.__class__.__name__} IC only supports ' + 'lv.COLOR_FORMAT.RGB565 or lv.COLOR_FORMAT.RGB888' + ) + + param_buf[0] = pixel_format + self.set_params(_COLMOD, param_mv[:1]) + + time.sleep_ms(10) # NOQA + + param_buf[0] = 0x0C + param_buf[1] = 0x0C + param_buf[2] = 0x00 + param_buf[3] = 0x33 + param_buf[4] = 0x33 + self.set_params(_PORCTRL, param_mv[:5]) + + param_buf[0] = 0x35 + self.set_params(_GCTRL, param_mv[:1]) + + param_buf[0] = 0x28 + self.set_params(_VCOMS, param_mv[:1]) + + param_buf[0] = 0x0C + self.set_params(_LCMCTRL, param_mv[:1]) + + param_buf[0] = 0x01 + self.set_params(_VDVVRHEN, param_mv[:1]) + + param_buf[0] = 0x13 + self.set_params(_VRHS, param_mv[:1]) + + param_buf[0] = 0x20 + self.set_params(_VDVSET, param_mv[:1]) + + param_buf[0] = 0x0F + self.set_params(_FRCTR2, param_mv[:1]) + + param_buf[0] = 0xA4 + param_buf[1] = 0xA1 + self.set_params(_PWCTRL1, param_mv[:2]) + + param_buf[0] = 0xD0 + param_buf[1] = 0x00 + param_buf[2] = 0x02 + param_buf[3] = 0x07 + param_buf[4] = 0x0A + param_buf[5] = 0x28 + param_buf[6] = 0x32 + param_buf[7] = 0x44 + param_buf[8] = 0x42 + param_buf[9] = 0x06 + param_buf[10] = 0x0E + param_buf[11] = 0x12 + param_buf[12] = 0x14 + param_buf[13] = 0x17 + self.set_params(_PGC, param_mv[:14]) + + param_buf[0] = 0xD0 + param_buf[1] = 0x00 + param_buf[2] = 0x02 + param_buf[3] = 0x07 + param_buf[4] = 0x0A + param_buf[5] = 0x28 + param_buf[6] = 0x31 + param_buf[7] = 0x54 + param_buf[8] = 0x47 + param_buf[9] = 0x0E + param_buf[10] = 0x1C + param_buf[11] = 0x17 + param_buf[12] = 0x1B + param_buf[13] = 0x1E + self.set_params(_NGC, param_mv[:14]) + + self.set_params(_INVON) + + param_buf[0] = 0x00 + param_buf[1] = 0x00 + param_buf[2] = (self.display_width >> 8) & 0xFF + param_buf[3] = self.display_width & 0xFF + + self.set_params(_CASET, param_mv[:4]) + + # Page addresses + param_buf[0] = 0x00 + param_buf[1] = 0x00 + param_buf[2] = (self.display_height >> 8) & 0xFF + param_buf[3] = self.display_height & 0xFF + + self.set_params(_RASET, param_mv[:4]) + + self.set_params(_DISPON) + time.sleep_ms(120) # NOQA + + self.set_params(_SLPOUT) + time.sleep_ms(120) # NOQA diff --git a/internal_filesystem/lib/drivers/display/st7789/st7789.py b/internal_filesystem/lib/drivers/display/st7789/st7789.py new file mode 100644 index 00000000..26b9b3a5 --- /dev/null +++ b/internal_filesystem/lib/drivers/display/st7789/st7789.py @@ -0,0 +1,80 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +from micropython import const # NOQA +import display_driver_framework +import lcd_bus +import lvgl as lv + + +STATE_HIGH = display_driver_framework.STATE_HIGH +STATE_LOW = display_driver_framework.STATE_LOW +STATE_PWM = display_driver_framework.STATE_PWM + +BYTE_ORDER_RGB = display_driver_framework.BYTE_ORDER_RGB +BYTE_ORDER_BGR = display_driver_framework.BYTE_ORDER_BGR + +_MADCTL_MV = const(0x20) # 0=Normal, 1=Row/column exchange +_MADCTL_MX = const(0x40) # 0=Left to Right, 1=Right to Left +_MADCTL_MY = const(0x80) # 0=Top to Bottom, 1=Bottom to Top + + +class ST7789(display_driver_framework.DisplayDriver): + _ORIENTATION_TABLE = ( + 0x0, + _MADCTL_MV | _MADCTL_MX, + _MADCTL_MY | _MADCTL_MX, + _MADCTL_MV | _MADCTL_MY + ) + + def __init__( + self, + data_bus, + display_width, + display_height, + frame_buffer1=None, + frame_buffer2=None, + reset_pin=None, + reset_state=STATE_HIGH, + power_pin=None, + power_on_state=STATE_HIGH, + backlight_pin=None, + backlight_on_state=STATE_HIGH, + offset_x=0, + offset_y=0, + color_byte_order=BYTE_ORDER_RGB, + color_space=lv.COLOR_FORMAT.RGB888, # NOQA + rgb565_byte_swap=False, + ): + + if color_space != lv.COLOR_FORMAT.RGB565: # NOQA + rgb565_byte_swap = False + + self._rgb565_byte_swap = rgb565_byte_swap + + if ( + isinstance(data_bus, lcd_bus.I80Bus) and + data_bus.get_lane_count() == 8 + ): + rgb565_byte_swap = False + + super().__init__( + data_bus=data_bus, + display_width=display_width, + display_height=display_height, + frame_buffer1=frame_buffer1, + frame_buffer2=frame_buffer2, + reset_pin=reset_pin, + reset_state=reset_state, + power_pin=power_pin, + power_on_state=power_on_state, + backlight_pin=backlight_pin, + backlight_on_state=backlight_on_state, + offset_x=offset_x, + offset_y=offset_y, + color_byte_order=color_byte_order, + color_space=color_space, # NOQA + rgb565_byte_swap=rgb565_byte_swap, + _cmd_bits=8, + _param_bits=8, + _init_bus=True + ) diff --git a/internal_filesystem/lib/mpos/hardware/drivers/qmi8658.py b/internal_filesystem/lib/drivers/imu_sensor/qmi8658.py similarity index 100% rename from internal_filesystem/lib/mpos/hardware/drivers/qmi8658.py rename to internal_filesystem/lib/drivers/imu_sensor/qmi8658.py diff --git a/internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py b/internal_filesystem/lib/drivers/imu_sensor/wsen_isds.py similarity index 100% rename from internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py rename to internal_filesystem/lib/drivers/imu_sensor/wsen_isds.py diff --git a/internal_filesystem/lib/drivers/indev/cst816s.py b/internal_filesystem/lib/drivers/indev/cst816s.py new file mode 100644 index 00000000..64255ac8 --- /dev/null +++ b/internal_filesystem/lib/drivers/indev/cst816s.py @@ -0,0 +1,307 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +from micropython import const # NOQA +import pointer_framework +import time +import machine # NOQA + + +I2C_ADDR = 0x15 +BITS = 8 + +# 0x00: No gesture +# 0x01: Swipe up +# 0x02: Swipe down +# 0x03: Swipe left +# 0x04: Swipe right +# 0x05: Single click +# 0x0B: Double click +# 0x0C: Long press +_GestureID = const(0x01) + +# 0: No finger +# 1: 1 finger +_FingerNum = const(0x02) + +# & 0xF << 8 +_XposH = const(0x03) +_XposL = const(0x04) + +# & 0xF << 8 +_YposH = const(0x05) +_YposL = const(0x06) + +_RegisterVersion = const(0x15) + +_BPC0H = const(0xB0) +_BPC0L = const(0xB1) + +_BPC1H = const(0xB2) +_BPC1L = const(0xB3) + +_ChipID = const(0xA7) +_ChipIDValue = const(0xB5) +_ChipIDValue2 = const(0xB6) + +_ProjID = const(0xA8) +_FwVersion = const(0xA9) + + +# =============================== +_MotionMask = const(0xEC) + +# Enables continuous left and right sliding +_EnConLR = const(0x04) +# Enables continuous up and down sliding +_EnConUD = const(0x02) +# Enable double-click action +_EnDClick = const(0x01) +# =============================== + +# Interrupt low pulse output width. +# Unit 0.1ms, optional value: 1~200. The default value is 10. +_IrqPluseWidth = const(0xED) + +# Normal fast detection cycle. +# This value affects LpAutoWakeTime and AutoSleepTime. +# Unit 10ms, optional value: 1~30. The default value is 1. +_NorScanPer = const(0xEE) + +# Gesture detection sliding partition angle control. Angle=tan(c)*10 +# c is the angle based on the positive direction of the x-axis. +_MotionSlAngle = const(0xEF) + +_LpScanRaw1H = const(0xF0) +_LpScanRaw1L = const(0xF1) +_LpScanRaw2H = const(0xF2) +_LpScanRaw2L = const(0xF3) + +# Automatic recalibration period in low power consumption. +# Unit: 1 minute, optional value: 1 to 5. The default value is 5. +_LpAutoWakeTime = const(0xF4) + + +# Low power scan wake-up threshold. The smaller the value, +# the more sensitive it is. +# Optional values: 1 to 255. The default value is 48. +_LpScanTH = const(0xF5) + +# Low power scan range. The larger the value, the more sensitive it is, +# and the higher the power consumption is. +# Optional values: 0, 1, 2, 3. The default value is 3. +_LpScanWin = const(0xF6) + +# Low power scan frequency. The smaller the value, the more sensitive it is. +# Optional values: 1 to 255. The default value is 7. +_LpScanFreq = const(0xF7) + +# Low power scan current. The smaller the value, the more sensitive it is. +# Optional values: 1 to 255. +_LpScanIdac = const(0xF8) + + +# Automatically enters low power mode when there is no touch within x seconds. +# Unit: 1S, default value: 2S. +_AutoSleepTime = const(0xF9) + +# =============================== +_IrqCtl = const(0xFA) +# Interrupt pin test, automatically sends low pulses periodically after enabling +_EnTest = const(0x80) +# Sends low pulses periodically when touch is detected. +_EnTouch = const(0x40) +# Sends low pulses when touch state changes are detected. +_EnChange = const(0x20) +# Sends low pulses when gestures are detected. +_EnMotion = const(0x10) +# Long press gesture only sends one low pulse signal. +_OnceWLP = const(0x01) +# =============================== + + +# Automatically reset when there is touch but no valid gesture within x seconds. +# Unit: 1S. This function is not enabled when it is 0. The default value is 5. +_AutoReset = const(0xFB) + +# Automatically reset after long pressing for x seconds. +# Unit: 1S. This function is not enabled when it is 0. The default value is 10. +_LongPressTime = const(0xFC) + +# =============================== +_IOCtl = const(0xFD) + +# The master controller realizes the soft reset function +# of the touch screen by pulling down the IRQ pin. +# 0: Disable soft reset. +# 1: Enable soft reset. +_SOFT_RST = const(0x04) + +# IIC pin drive mode, the default is resistor pull-up. +# 0: Resistor pull-up +# 1: OD +_IIC_OD = const(0x02) + +# IIC and IRQ pin level selection, the default is VDD level. +# 0: VDD +# 1: 1.8V +_En1v8 = const(0x01) +# =============================== + +# The default value is 0, enabling automatic entry into low power mode. +# When the value is non-zero, automatic entry into low power mode is disabled. +# 0: enabled +# 1: disabled +_DisAutoSleep = const(0xFE) + + +class CST816S(pointer_framework.PointerDriver): + + def _read_reg(self, reg): + self._tx_buf[0] = reg + self._rx_buf[0] = 0x00 + + self._device.write_readinto(self._tx_mv[:1], self._rx_mv[:1]) + + def _write_reg(self, reg, value): + self._tx_buf[0] = reg + self._tx_buf[1] = value + self._device.write(self._tx_mv[:2]) + + def __init__( + self, + device, + reset_pin=None, + touch_cal=None, + startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._0, # NOQA + debug=False + ): + self._tx_buf = bytearray(2) + self._tx_mv = memoryview(self._tx_buf) + self._rx_buf = bytearray(1) + self._rx_mv = memoryview(self._rx_buf) + + self._device = device + + if not isinstance(reset_pin, int): + self._reset_pin = reset_pin + else: + self._reset_pin = machine.Pin(reset_pin, machine.Pin.OUT) + + if self._reset_pin: + self._reset_pin.value(1) + + self.hw_reset() + self.auto_sleep = False + + self._read_reg(_ChipID) + print('Chip ID:', hex(self._rx_buf[0])) + chip_id = self._rx_buf[0] + + self._read_reg(_RegisterVersion) + print('Touch version:', self._rx_buf[0]) + + self._read_reg(_ProjID) + print('Proj ID:', hex(self._rx_buf[0])) + + self._read_reg(_FwVersion) + print('FW Version:', hex(self._rx_buf[0])) + + if chip_id not in (_ChipIDValue, _ChipIDValue2): + raise RuntimeError(f'Incorrect chip id ({hex(_ChipIDValue)})') + + self._write_reg(_IrqCtl, _EnTouch | _EnChange) + + super().__init__( + touch_cal=touch_cal, startup_rotation=startup_rotation, debug=debug + ) + + @property + def wake_up_threshold(self): + self._read_reg(_LpScanTH) + return 256 - self._rx_buf[0] + + @wake_up_threshold.setter + def wake_up_threshold(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_LpScanTH, 256 - value) + + @property + def wake_up_scan_frequency(self): + self._read_reg(_LpScanFreq) + return 256 - self._rx_buf[0] + + @wake_up_scan_frequency.setter + def wake_up_scan_frequency(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_LpScanFreq, 256 - value) + + @property + def auto_sleep_timeout(self): + self._read_reg(_AutoSleepTime) + return self._rx_buf[0] + + @auto_sleep_timeout.setter + def auto_sleep_timeout(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_AutoSleepTime, value) + + def wake_up(self): + auto_sleep = self.auto_sleep + + self._write_reg(_DisAutoSleep, 0x00) + time.sleep_ms(10) # NOQA + self._write_reg(_DisAutoSleep, 0xFE) + time.sleep_ms(50) # NOQA + self._write_reg(_DisAutoSleep, 0xFE) + time.sleep_ms(50) # NOQA + self._write_reg(_DisAutoSleep, int(not auto_sleep)) + + @property + def auto_sleep(self): + self._read_reg(_DisAutoSleep) + return self._rx_buf[0] == 0x00 + + @auto_sleep.setter + def auto_sleep(self, en): + if en: + self._write_reg(_DisAutoSleep, 0x00) + else: + self._write_reg(_DisAutoSleep, 0xFE) + + def hw_reset(self): + if self._reset_pin is None: + return + + self._reset_pin(0) + time.sleep_ms(1) # NOQA + self._reset_pin(1) + time.sleep_ms(50) # NOQA + + def _get_coords(self): + self._read_reg(_FingerNum) + if self._rx_buf[0] == 0: + return None + + self._read_reg(_XposH) + x = (self._rx_buf[0] & 0x0F) << 8 + self._read_reg(_XposL) + x |= self._rx_buf[0] + + self._read_reg(_YposH) + y = (self._rx_buf[0] & 0x0F) << 8 + self._read_reg(_YposL) + y |= self._rx_buf[0] + + return self.PRESSED, x, y diff --git a/internal_filesystem/lib/mpos/indev/gt911.py b/internal_filesystem/lib/drivers/indev/gt911.py similarity index 100% rename from internal_filesystem/lib/mpos/indev/gt911.py rename to internal_filesystem/lib/drivers/indev/gt911.py diff --git a/internal_filesystem/lib/mpos/indev/mpos_sdl_keyboard.py b/internal_filesystem/lib/drivers/indev/sdl_keyboard.py similarity index 100% rename from internal_filesystem/lib/mpos/indev/mpos_sdl_keyboard.py rename to internal_filesystem/lib/drivers/indev/sdl_keyboard.py diff --git a/internal_filesystem/lib/mpos/board/fri3d_2024.py b/internal_filesystem/lib/mpos/board/fri3d_2024.py index 4285d8fc..38ededa0 100644 --- a/internal_filesystem/lib/mpos/board/fri3d_2024.py +++ b/internal_filesystem/lib/mpos/board/fri3d_2024.py @@ -1,9 +1,7 @@ # Hardware initialization for Fri3d Camp 2024 Badge from machine import Pin, SPI, SDCard -import st7789 import lcd_bus import machine -import cst816s import i2c import math @@ -13,6 +11,9 @@ import gc import lvgl as lv import task_handler +import drivers.display.st7789 as st7789 +import drivers.indev.cst816s as cst816s + import mpos.ui import mpos.ui.focus_direction from mpos import InputManager diff --git a/internal_filesystem/lib/mpos/board/fri3d_2026.py b/internal_filesystem/lib/mpos/board/fri3d_2026.py index 3c10f77e..e5c0935c 100644 --- a/internal_filesystem/lib/mpos/board/fri3d_2026.py +++ b/internal_filesystem/lib/mpos/board/fri3d_2026.py @@ -14,10 +14,8 @@ # - test it on the Waveshare to make sure no syntax / variable errors from machine import Pin, SPI, SDCard -import st7789 import lcd_bus import machine -import cst816s import i2c import math @@ -27,6 +25,9 @@ import gc import lvgl as lv import task_handler +import drivers.display.st7789 as st7789 +import drivers.indev.cst816s as cst816s + import mpos.ui import mpos.ui.focus_direction from mpos import InputManager diff --git a/internal_filesystem/lib/mpos/board/linux.py b/internal_filesystem/lib/mpos/board/linux.py index 2705ca8e..b8cf1495 100644 --- a/internal_filesystem/lib/mpos/board/linux.py +++ b/internal_filesystem/lib/mpos/board/linux.py @@ -3,8 +3,9 @@ import lcd_bus import lvgl as lv import sdl_display +from drivers.indev.sdl_keyboard import MposSDLKeyboard + import mpos.clipboard -import mpos.indev.mpos_sdl_keyboard import mpos.ui import mpos.ui.focus_direction from mpos import InputManager @@ -76,7 +77,7 @@ def catch_escape_key(indev, indev_data): sdlkeyboard._read(indev, indev_data) -sdlkeyboard = mpos.indev.mpos_sdl_keyboard.MposSDLKeyboard() +sdlkeyboard = MposSDLKeyboard() sdlkeyboard._indev_drv.set_read_cb(catch_escape_key) # check for escape InputManager.register_indev(sdlkeyboard) try: diff --git a/internal_filesystem/lib/mpos/board/matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660.py b/internal_filesystem/lib/mpos/board/matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660.py index f88ed859..9e2a6eea 100644 --- a/internal_filesystem/lib/mpos/board/matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660.py +++ b/internal_filesystem/lib/mpos/board/matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660.py @@ -82,7 +82,7 @@ def init_touch(): try: import i2c i2c_bus = i2c.I2C.Bus(host=0, scl=38, sda=39, freq=I2C_FREQ, use_locks=False) - import mpos.indev.gt911 as gt911 + import drivers.indev.gt911 as gt911 touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=gt911.I2C_ADDR, reg_bits=gt911.BITS) indev = gt911.GT911(touch_dev, reset_pin=1, interrupt_pin=40, debug=False) # debug makes it slower from mpos import InputManager diff --git a/internal_filesystem/lib/mpos/board/odroid_go.py b/internal_filesystem/lib/mpos/board/odroid_go.py index 81bf92a2..0a08cc8b 100644 --- a/internal_filesystem/lib/mpos/board/odroid_go.py +++ b/internal_filesystem/lib/mpos/board/odroid_go.py @@ -6,7 +6,7 @@ print("odroid_go.py initialization") import time -import ili9341 +import drivers.display.ili9341 as ili9341 import lcd_bus import lvgl as lv import machine @@ -157,7 +157,7 @@ class Crossbar: return crossbar_pressed -# see: internal_filesystem/lib/mpos/indev/mpos_sdl_keyboard.py +# see: internal_filesystem/lib/drivers/indev/sdl_keyboard.py # lv.KEY.UP # lv.KEY.LEFT - lv.KEY.RIGHT # lv.KEY.DOWN diff --git a/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py b/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py index e75b97bc..15a10229 100644 --- a/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py +++ b/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py @@ -2,15 +2,16 @@ print("waveshare_esp32_s3_touch_lcd_2.py initialization") # Hardware initialization for ESP32-S3-Touch-LCD-2 # Manufacturer's website at https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-2 -import st7789 import lcd_bus import machine -import cst816s import i2c import lvgl as lv import task_handler +import drivers.display.st7789 as st7789 +import drivers.indev.cst816s as cst816s + import mpos.ui # Pin configuration diff --git a/internal_filesystem/lib/mpos/hardware/drivers/__init__.py b/internal_filesystem/lib/mpos/hardware/drivers/__init__.py deleted file mode 100644 index 119fb43d..00000000 --- a/internal_filesystem/lib/mpos/hardware/drivers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# IMU and sensor drivers for MicroPythonOS diff --git a/internal_filesystem/lib/mpos/sensor_manager.py b/internal_filesystem/lib/mpos/sensor_manager.py index 96f147bc..fa5eab57 100644 --- a/internal_filesystem/lib/mpos/sensor_manager.py +++ b/internal_filesystem/lib/mpos/sensor_manager.py @@ -162,7 +162,7 @@ class SensorManager: # Try QMI8658 first (Waveshare board) if self._i2c_bus: try: - from mpos.hardware.drivers.qmi8658 import QMI8658 + from drivers.imu_sensor.qmi8658 import QMI8658 chip_id = self._i2c_bus.readfrom_mem(self._i2c_address, 0x00, 1)[0] # PARTID register if chip_id == 0x05: # QMI8685_PARTID self._imu_driver = _QMI8658Driver(self._i2c_bus, self._i2c_address) @@ -174,7 +174,7 @@ class SensorManager: # Try WSEN_ISDS (fri3d_2024) or LSM6DSO (fri3d_2026) try: - from mpos.hardware.drivers.wsen_isds import Wsen_Isds + from drivers.imu_sensor.wsen_isds import Wsen_Isds chip_id = self._i2c_bus.readfrom_mem(self._i2c_address, 0x0F, 1)[0] # WHO_AM_I register - could also use Wsen_Isds.get_chip_id() if chip_id == 0x6A or chip_id == 0x6C: # WSEN_ISDS WHO_AM_I 0x6A (Fri3d 2024) or 0x6C (Fri3d 2026) self._imu_driver = _WsenISDSDriver(self._i2c_bus, self._i2c_address) @@ -721,7 +721,7 @@ class _QMI8658Driver(_IMUDriver): """Wrapper for QMI8658 IMU (Waveshare board).""" def __init__(self, i2c_bus, address): - from mpos.hardware.drivers.qmi8658 import QMI8658 + from drivers.imu_sensor.qmi8658 import QMI8658 # QMI8658 scale constants (can't import const() values) _ACCELSCALE_RANGE_8G = 0b10 _GYROSCALE_RANGE_256DPS = 0b100 @@ -817,7 +817,7 @@ class _WsenISDSDriver(_IMUDriver): """Wrapper for WSEN_ISDS IMU (Fri3d badge).""" def __init__(self, i2c_bus, address): - from mpos.hardware.drivers.wsen_isds import Wsen_Isds + from drivers.imu_sensor.wsen_isds import Wsen_Isds self.sensor = Wsen_Isds( i2c_bus, address=address, diff --git a/internal_filesystem/lib/mpos/ui/camera_settings.py b/internal_filesystem/lib/mpos/ui/camera_settings.py index 46cd8f34..6931d79b 100644 --- a/internal_filesystem/lib/mpos/ui/camera_settings.py +++ b/internal_filesystem/lib/mpos/ui/camera_settings.py @@ -224,7 +224,7 @@ class CameraSettingsActivity(Activity): textarea.align(lv.ALIGN.TOP_RIGHT, 0, 0) # Initialize keyboard (hidden initially) - from ..indev.mpos_sdl_keyboard import MposKeyboard + from mpos.ui.keyboard import MposKeyboard keyboard = MposKeyboard(parent) keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) keyboard.add_flag(lv.obj.FLAG.HIDDEN) diff --git a/scripts/build_mpos.sh b/scripts/build_mpos.sh index b20ae9be..8edd4902 100755 --- a/scripts/build_mpos.sh +++ b/scripts/build_mpos.sh @@ -6,7 +6,6 @@ codebasedir=$(readlink -f "$mydir"/..) # build process needs absolute paths target="$1" buildtype="$2" -subtarget="$3" if [ -z "$target" ]; then echo "Usage: $0 target" @@ -14,11 +13,10 @@ if [ -z "$target" ]; then echo "Example: $0 unix" echo "Example: $0 macOS" echo "Example: $0 esp32" - echo "Example: $0 odroid_go" + echo "Example: $0 esp32s3" exit 1 fi - # This assumes all the git submodules have been checked out recursively echo "Fetch tags for lib/SDL, otherwise lvgl_micropython's make.py script can't checkout a specific tag..." @@ -79,13 +77,21 @@ ln -sf ../../c_mpos "$codebasedir"/lvgl_micropython/ext_mod/c_mpos echo "Refreshing freezefs..." "$codebasedir"/scripts/freezefs_mount_builtin.sh -manifest="" -if [ "$target" == "esp32" ]; then +if [ "$target" == "esp32" -o "$target" == "esp32s3" ]; then + if [ "$target" == "esp32" ]; then + BOARD=ESP32_GENERIC + BOARD_VARIANT=SPIRAM + else # esp32s3 + BOARD=ESP32_GENERIC_S3 + BOARD_VARIANT=SPIRAM_OCT + fi manifest=$(readlink -f "$codebasedir"/manifests/manifest.py) frozenmanifest="FROZEN_MANIFEST=$manifest" echo "Note that you can also prevent the builtin filesystem from being mounted by umounting it and creating a builtin/ folder." - # Build for https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-2. - # See https://github.com/lvgl-micropython/lvgl_micropython + pushd "$codebasedir"/lvgl_micropython/ + rm -rf lib/micropython/ports/esp32/build-$BOARD-$BOARD_VARIANT + + # For more info on the options, see https://github.com/lvgl-micropython/lvgl_micropython # --ota: support Over-The-Air updates # --partition size: both OTA partitions are 4MB # --flash-size: total flash size is 16MB @@ -97,19 +103,8 @@ if [ "$target" == "esp32" ]; then # CONFIG_FREERTOS_USE_TRACE_FACILITY=y # CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y - pushd "$codebasedir"/lvgl_micropython/ - rm -rf lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/ - python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789 INDEV=cst816s USER_C_MODULE="$codebasedir"/micropython-camera-API/src/micropython.cmake USER_C_MODULE="$codebasedir"/secp256k1-embedded-ecdh/micropython.cmake USER_C_MODULE="$codebasedir"/c_mpos/micropython.cmake CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y "$frozenmanifest" - popd -elif [ "$target" == "odroid_go" ]; then - manifest=$(readlink -f "$codebasedir"/manifests/manifest.py) - frozenmanifest="FROZEN_MANIFEST=$manifest" - echo "Note that you can also prevent the builtin filesystem from being mounted by umounting it and creating a builtin/ folder." - # Build for https://wiki.odroid.com/odroid_go/odroid_go - pushd "$codebasedir"/lvgl_micropython/ - rm -rf lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/ - python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 \ - BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM DISPLAY=ili9341 \ + + python3 make.py --ota --partition-size=4194304 --flash-size=16 esp32 BOARD=$BOARD BOARD_VARIANT=$BOARD_VARIANT \ USER_C_MODULE="$codebasedir"/micropython-camera-API/src/micropython.cmake \ USER_C_MODULE="$codebasedir"/secp256k1-embedded-ecdh/micropython.cmake \ USER_C_MODULE="$codebasedir"/c_mpos/micropython.cmake \ @@ -117,6 +112,7 @@ elif [ "$target" == "odroid_go" ]; then CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y \ CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y \ "$frozenmanifest" + popd elif [ "$target" == "unix" -o "$target" == "macOS" ]; then manifest=$(readlink -f "$codebasedir"/manifests/manifest.py) @@ -128,31 +124,15 @@ elif [ "$target" == "unix" -o "$target" == "macOS" ]; then stream_wav_file="$codebasedir"/internal_filesystem/lib/mpos/audio/stream_wav.py sed -i.backup 's/^@micropython\.viper$/#@micropython.viper/' "$stream_wav_file" - #if [ "$target" == "unix" ]; then - if false; then - # only on unix, because on macos, homebrew install rlottie fails so the compilation runs into: fatal error: 'rlottie_capi.h' file not found on macos" - # and on esp32, rlottie_create_from_raw() crashes the system - sed -i.backup 's/#define MICROPY_RLOTTIE 0/#define MICROPY_RLOTTIE 1/' "$codebasedir"/lvgl_micropython/lib/lv_conf.h - echo "After enabling MICROPY_RLOTTIE:" - cat "$codebasedir"/lvgl_micropython/lib/lv_conf.h - fi - # If it's still running, kill it, otherwise "text file busy" pkill -9 -f /lvgl_micropy_unix # LV_CFLAGS are passed to USER_C_MODULES (compiler flags only, no linker flags) # STRIP= makes it so that debug symbols are kept pushd "$codebasedir"/lvgl_micropython/ # USER_C_MODULE doesn't seem to work properly so there are symlinks in lvgl_micropython/extmod/ - python3 make.py "$target" LV_CFLAGS="-g -O0 -ggdb" STRIP= DISPLAY=sdl_display INDEV=sdl_pointer INDEV=sdl_keyboard "$frozenmanifest" + python3 make.py "$target" LV_CFLAGS="-g -O0 -ggdb" STRIP= DISPLAY=sdl_display INDEV=sdl_pointer "$frozenmanifest" popd - # Restore RLOTTIE: - if [ "$target" == "unix" ]; then - sed -i.backup 's/#define MICROPY_RLOTTIE 1/#define MICROPY_RLOTTIE 0/' "$codebasedir"/lvgl_micropython/lib/lv_conf.h - #echo "After disabling MICROPY_RLOTTIE:" - #cat "$codebasedir"/lvgl_micropython/lib/lv_conf.h - fi - # Restore @micropython.viper decorator after build echo "Restoring @micropython.viper decorator..." sed -i.backup 's/^#@micropython\.viper$/@micropython.viper/' "$stream_wav_file"