Skip to content

Commit 9aac99f

Browse files
Forairaaaaalbuque
authored andcommitted
modules/startup/tab5: Add app adc, gpio and i2c.
Signed-off-by: Forairaaaaa <[email protected]>
1 parent 95b8ce4 commit 9aac99f

File tree

11 files changed

+345
-16
lines changed

11 files changed

+345
-16
lines changed
41.8 KB
Loading
38.1 KB
Loading

m5stack/modules/startup/manifest_tab5.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"tab5/launcher/apps/app_ezdata.py",
2121
"tab5/launcher/apps/app_wifi.py",
2222
"tab5/launcher/apps/app_uart.py",
23+
"tab5/launcher/apps/app_gpio.py",
24+
"tab5/launcher/apps/app_adc.py",
2325
"tab5/launcher/hal.py",
2426
"tab5/launcher/components/ezdata_dock.py",
2527
"tab5/launcher/components/status_bar.py",

m5stack/modules/startup/tab5/hal_tab5.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# SPDX-License-Identifier: MIT
44

55
from .launcher import *
6-
from machine import Pin, I2C, UART, reset, unique_id, SoftI2C
6+
from machine import Pin, I2C, UART, reset, unique_id, SoftI2C, ADC
77
import network
88
import esp32
99
import time
@@ -33,6 +33,8 @@ def __init__(self, wifi):
3333
self._load_network_config_from_nvs()
3434

3535
self._pin_485_de = None
36+
self._pin_obj_map = {}
37+
self._adc_obj_map = {}
3638

3739
def _load_network_config_from_nvs(self) -> NetworkConfig:
3840
nvs = esp32.NVS("uiflow")
@@ -240,3 +242,39 @@ def get_ezdata_user_token(self) -> str:
240242
def reset_ezdata_user_token(self):
241243
nvs = esp32.NVS("uiflow")
242244
nvs.set_str("ustoken", "")
245+
246+
def gpio_init(self, pin: int, mode: int):
247+
"""
248+
mode:
249+
0: input
250+
1: output
251+
"""
252+
self._pin_obj_map[pin] = Pin(pin, Pin.OUT if mode == 1 else Pin.IN)
253+
254+
def gpio_set_level(self, pin: int, level: bool):
255+
"""
256+
level:
257+
False: low
258+
True: high
259+
"""
260+
if pin not in self._pin_obj_map:
261+
return
262+
self._pin_obj_map[pin].value(level)
263+
264+
def gpio_deinit(self, pin: int):
265+
if pin not in self._pin_obj_map:
266+
return
267+
del self._pin_obj_map[pin]
268+
269+
def adc_init(self, pin: int):
270+
self._adc_obj_map[pin] = ADC(Pin(pin))
271+
272+
def adc_deinit(self, pin: int):
273+
if pin not in self._adc_obj_map:
274+
return
275+
del self._adc_obj_map[pin]
276+
277+
def adc_read(self, pin: int) -> int:
278+
if pin not in self._adc_obj_map:
279+
return 0
280+
return self._adc_obj_map[pin].read()

m5stack/modules/startup/tab5/launcher/apps/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99
from .app_wifi_scan import AppWifiScan
1010
from .app_i2c_scan import AppI2cScan
1111
from .app_uart import AppUart
12+
from .app_gpio import AppGpio
13+
from .app_adc import AppAdc
1214
from .app_ezdata import AppEzdata, AppEzdataSettings
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
from .app import AppBase
6+
from ..hal import get_hal
7+
import lvgl as lv
8+
import asyncio
9+
10+
11+
class AdcPanel:
12+
class _AdcState:
13+
CLOSED = 0
14+
OPENED = 1
15+
16+
def __init__(self, parent: lv.obj, pos_x: int, pos_y: int, pins: list[int]):
17+
self._state = self._AdcState.CLOSED
18+
self._pins = pins
19+
self._current_pin = 0
20+
21+
panel = lv.obj(parent)
22+
panel.set_size(530, 200)
23+
panel.align(lv.ALIGN.TOP_LEFT, pos_x, pos_y)
24+
panel.set_style_border_width(0, lv.PART.MAIN)
25+
panel.set_style_bg_opa(lv.OPA.TRANSP, lv.PART.MAIN)
26+
panel.set_style_pad_all(0, lv.PART.MAIN)
27+
28+
self._chart = lv.chart(panel)
29+
self._chart.set_size(360, 200)
30+
self._chart.align(lv.ALIGN.LEFT_MID, 0, 0)
31+
self._chart.set_style_bg_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN)
32+
self._chart.set_type(lv.chart.TYPE.LINE)
33+
self._chart.set_div_line_count(13, 22)
34+
self._chart.set_update_mode(lv.chart.UPDATE_MODE.SHIFT)
35+
self._chart.set_point_count(100)
36+
self._chart.set_axis_range(lv.chart.AXIS.PRIMARY_Y, 1800, 4096)
37+
self._chart.set_style_size(0, 0, lv.PART.INDICATOR)
38+
39+
self._chart_series = self._chart.add_series(
40+
lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y
41+
)
42+
43+
self._label_value = lv.label(self._chart)
44+
self._label_value.align(lv.ALIGN.TOP_RIGHT, -5, -5)
45+
self._label_value.set_style_text_font(lv.font_montserrat_18, lv.PART.MAIN)
46+
self._label_value.set_style_text_color(lv.color_hex(0x6A6A6A), lv.PART.MAIN)
47+
self._label_value.set_style_text_align(lv.TEXT_ALIGN.RIGHT, lv.PART.MAIN)
48+
49+
self._btn_open = lv.button(panel)
50+
self._btn_open.set_size(140, 48)
51+
self._btn_open.align(lv.ALIGN.TOP_LEFT, 383, 146)
52+
self._btn_open.set_style_shadow_width(0, lv.PART.MAIN)
53+
self._btn_open.add_event_cb(self._handle_open_btn_clicked, lv.EVENT.CLICKED, None)
54+
55+
self._label_open = lv.label(self._btn_open)
56+
self._label_open.set_align(lv.ALIGN.CENTER)
57+
self._label_open.set_style_text_font(lv.font_montserrat_20, lv.PART.MAIN)
58+
59+
self._dd_pins = lv.dropdown(panel)
60+
self._dd_pins.align(lv.ALIGN.TOP_LEFT, 426, 71)
61+
self._dd_pins.set_size(97, 48)
62+
self._dd_pins.set_style_shadow_width(0, lv.PART.MAIN)
63+
self._dd_pins.set_style_text_font(lv.font_montserrat_20, lv.PART.MAIN)
64+
self._dd_pins.set_style_border_width(0, lv.PART.MAIN)
65+
self._dd_pins.set_options("\n".join([str(b) for b in self._pins]))
66+
67+
label_dd_pins = lv.label(panel)
68+
label_dd_pins.align_to(self._dd_pins, lv.ALIGN.OUT_LEFT_MID, -48, -2)
69+
label_dd_pins.set_text("PIN:")
70+
label_dd_pins.set_style_text_font(lv.font_montserrat_18, lv.PART.MAIN)
71+
72+
self._set_state_to(self._AdcState.CLOSED)
73+
74+
def _handle_open_btn_clicked(self, e: lv.event_t):
75+
get_hal().play_click_sfx()
76+
if self._state == self._AdcState.CLOSED:
77+
self._set_state_to(self._AdcState.OPENED)
78+
else:
79+
self._set_state_to(self._AdcState.CLOSED)
80+
81+
def _set_state_to(self, new_state: _AdcState):
82+
if new_state == self._AdcState.OPENED:
83+
# Update ui
84+
self._btn_open.set_style_bg_color(lv.color_hex(0x1EB561), lv.PART.MAIN)
85+
self._label_open.set_text("CLOSE")
86+
87+
# Init adc
88+
self._current_pin = self._pins[self._dd_pins.get_selected()]
89+
get_hal().adc_init(self._current_pin)
90+
else:
91+
# Update ui
92+
self._btn_open.set_style_bg_color(lv.color_hex(0x2DA4E0), lv.PART.MAIN)
93+
self._label_open.set_text("OPEN")
94+
95+
# Deinit adc
96+
get_hal().adc_deinit(self._current_pin)
97+
98+
self._state = new_state
99+
100+
def update(self):
101+
if self._state == self._AdcState.OPENED:
102+
value = get_hal().adc_read(self._current_pin)
103+
self._label_value.set_text(f"{value}")
104+
self._chart.set_next_value(self._chart_series, value)
105+
self._chart.refresh()
106+
107+
def cleanup(self):
108+
get_hal().adc_deinit(self._current_pin)
109+
110+
self._label_value.delete()
111+
self._label_value = None
112+
self._chart_series = None
113+
self._chart.delete()
114+
self._chart = None
115+
self._label_open.delete()
116+
self._label_open = None
117+
self._btn_open.delete()
118+
self._btn_open = None
119+
self._dd_pins.delete()
120+
self._dd_pins = None
121+
122+
123+
class AppAdc(AppBase):
124+
async def main(self):
125+
self._adc_panels = []
126+
self._adc_panels.append(AdcPanel(self.get_app_panel(), 32, 29, [54]))
127+
self._adc_panels.append(AdcPanel(self.get_app_panel(), 586, 29, [53]))
128+
self._adc_panels.append(AdcPanel(self.get_app_panel(), 32, 270, [50]))
129+
self._adc_panels.append(AdcPanel(self.get_app_panel(), 586, 270, [49]))
130+
131+
while True:
132+
await asyncio.sleep_ms(500)
133+
for panel in self._adc_panels:
134+
panel.update()
135+
136+
def on_cleanup(self):
137+
for panel in self._adc_panels:
138+
panel.cleanup()
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
from .app import AppBase
6+
from ..hal import *
7+
import lvgl as lv
8+
import asyncio
9+
10+
11+
class OutputTestPanel:
12+
def __init__(self, parent: lv.obj, pin: int, pos_x: int, pos_y: int):
13+
self._pin = pin
14+
self._is_on = False
15+
16+
panel = lv.obj(parent)
17+
panel.remove_flag(lv.obj.FLAG.SCROLLABLE)
18+
panel.set_style_bg_color(lv.color_hex(0xE4E3E4), lv.PART.MAIN)
19+
panel.set_style_border_width(0, lv.PART.MAIN)
20+
panel.set_style_radius(10, lv.PART.MAIN)
21+
panel.set_style_pad_all(0, lv.PART.MAIN)
22+
panel.align(lv.ALIGN.TOP_MID, pos_x, pos_y)
23+
panel.set_size(230, 62)
24+
25+
label_io_num = lv.label(panel)
26+
label_io_num.align(lv.ALIGN.CENTER, -67, 0)
27+
label_io_num.set_style_text_font(lv.font_montserrat_24, lv.PART.MAIN)
28+
label_io_num.set_style_text_color(lv.color_hex(0x262626), lv.PART.MAIN)
29+
label_io_num.set_text(f"G{pin}")
30+
31+
self._btn_io_toggle = lv.button(panel)
32+
self._btn_io_toggle.align(lv.ALIGN.CENTER, 47, 0)
33+
self._btn_io_toggle.set_style_radius(6, lv.PART.MAIN)
34+
self._btn_io_toggle.set_style_shadow_width(0, lv.PART.MAIN)
35+
self._btn_io_toggle.set_size(114, 42)
36+
self._btn_io_toggle.add_event_cb(self._handle_toggle, lv.EVENT.CLICKED, None)
37+
38+
self._label_btn = lv.label(self._btn_io_toggle)
39+
self._label_btn.align(lv.ALIGN.CENTER, 0, 0)
40+
self._label_btn.set_style_text_font(lv.font_montserrat_22, lv.PART.MAIN)
41+
42+
self._update_btn_style()
43+
44+
# Setup pin
45+
get_hal().gpio_deinit(self._pin)
46+
get_hal().gpio_init(self._pin, 1)
47+
get_hal().gpio_set_level(self._pin, False)
48+
49+
def _update_btn_style(self):
50+
if self._is_on:
51+
self._btn_io_toggle.set_style_bg_color(lv.color_hex(0xFF5959), lv.PART.MAIN)
52+
self._label_btn.set_text("HIGH")
53+
else:
54+
self._btn_io_toggle.set_style_bg_color(lv.color_hex(0x58B358), lv.PART.MAIN)
55+
self._label_btn.set_text("LOW")
56+
57+
def _handle_toggle(self, e: lv.event_t):
58+
self._is_on = not self._is_on
59+
self._update_btn_style()
60+
get_hal().gpio_set_level(self._pin, self._is_on)
61+
62+
def cleanup(self):
63+
self._btn_io_toggle.delete()
64+
self._btn_io_toggle = None
65+
get_hal().gpio_deinit(self._pin)
66+
67+
68+
class ExtPortPanel:
69+
_PINS = [49, 50, 0, 1, 54, 53]
70+
71+
def __init__(self, parent: lv.obj):
72+
panel = lv.obj(parent)
73+
panel.set_size(273, 460)
74+
panel.align(lv.ALIGN.CENTER, -321, 0)
75+
panel.set_style_border_width(0, lv.PART.MAIN)
76+
panel.set_style_bg_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN)
77+
panel.set_style_radius(10, lv.PART.MAIN)
78+
79+
label_title = lv.label(panel)
80+
label_title.align(lv.ALIGN.TOP_MID, 0, 0)
81+
label_title.set_style_text_font(lv.font_montserrat_18, lv.PART.MAIN)
82+
label_title.set_style_text_color(lv.color_hex(0x000000), lv.PART.MAIN)
83+
label_title.set_text("Ext.Port1")
84+
85+
self._test_panels = []
86+
for i, pin in enumerate(self._PINS):
87+
self._test_panels.append(OutputTestPanel(panel, pin, 0, 40 + 81 * i))
88+
89+
def cleanup(self):
90+
for panel in self._test_panels:
91+
panel.cleanup()
92+
self._test_panels = []
93+
94+
95+
class MbusPanel:
96+
_PINS = [18, 19, 5, 38, 7, 3, 2, 47, 16, 17, 45, 52, 37, 6, 4, 48, 35, 51]
97+
98+
def __init__(self, parent: lv.obj):
99+
panel = lv.obj(parent)
100+
panel.set_size(520, 460)
101+
panel.align(lv.ALIGN.CENTER, 230, 0)
102+
panel.set_style_border_width(0, lv.PART.MAIN)
103+
panel.set_style_bg_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN)
104+
panel.set_style_radius(10, lv.PART.MAIN)
105+
106+
label_title = lv.label(panel)
107+
label_title.align(lv.ALIGN.TOP_MID, 0, 0)
108+
label_title.set_style_text_font(lv.font_montserrat_18, lv.PART.MAIN)
109+
label_title.set_style_text_color(lv.color_hex(0x000000), lv.PART.MAIN)
110+
label_title.set_text("MBUS")
111+
112+
self._test_panels = []
113+
for i, pin in enumerate(self._PINS):
114+
self._test_panels.append(
115+
OutputTestPanel(panel, pin, 124 if i > 8 else -124, 40 + 81 * (i % 9))
116+
)
117+
118+
def cleanup(self):
119+
for panel in self._test_panels:
120+
panel.cleanup()
121+
self._test_panels = []
122+
123+
124+
class AppGpio(AppBase):
125+
async def main(self):
126+
self._panel_ext = ExtPortPanel(self.get_app_panel())
127+
self._panel_mbus = MbusPanel(self.get_app_panel())
128+
129+
def on_cleanup(self):
130+
self._panel_ext.cleanup()
131+
self._panel_mbus.cleanup()

m5stack/modules/startup/tab5/launcher/apps/app_i2c_scan.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
# SPDX-License-Identifier: MIT
44

55
from .app import AppBase
6-
from ..hal import *
7-
from ..common import *
6+
from ..hal import get_hal
87
import lvgl as lv
98
import asyncio
109

@@ -14,13 +13,11 @@ async def main(self):
1413
get_hal().i2c_init()
1514

1615
img_panel_port_a = lv.image(self.get_app_panel())
17-
img_panel_port_a.set_src(get_hal().get_asset_path("utils/i2c_panel_port_a" + IMAGE_SUFFIX))
16+
img_panel_port_a.set_src(get_hal().get_asset_path("utils/i2c_panel_port_a.png"))
1817
img_panel_port_a.align(lv.ALIGN.CENTER, -279, 34)
1918

2019
img_panel_internal = lv.image(self.get_app_panel())
21-
img_panel_internal.set_src(
22-
get_hal().get_asset_path("utils/i2c_panel_internal" + IMAGE_SUFFIX)
23-
)
20+
img_panel_internal.set_src(get_hal().get_asset_path("utils/i2c_panel_internal.png"))
2421
img_panel_internal.align(lv.ALIGN.CENTER, 279, 34)
2522

2623
btn_scan_port_a = lv.button(self.get_app_panel())

m5stack/modules/startup/tab5/launcher/components/app_dock.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010

1111
class AppIcon:
12-
_TODO_LIST = ["ADC", "GPIO", "UART", "I2CScan"]
13-
1412
def __init__(self, pos_x: int, pos_y: int, app_name: str, icon_name: str):
1513
self._app_name = app_name
1614
self._icon_pos_x = pos_x
@@ -21,10 +19,6 @@ def __init__(self, pos_x: int, pos_y: int, app_name: str, icon_name: str):
2119
img.add_flag(lv.obj.FLAG.CLICKABLE)
2220
img.add_event_cb(self._on_clicked, lv.EVENT.CLICKED, None)
2321

24-
if app_name in self._TODO_LIST:
25-
img.remove_flag(lv.obj.FLAG.CLICKABLE)
26-
img.set_style_image_recolor_opa(123, lv.PART.MAIN)
27-
2822
def _on_clicked(self, e: lv.event_t):
2923
get_hal().play_click_sfx()
3024
IconIndicator.create_indicator(e.get_target_obj())

0 commit comments

Comments
 (0)