Skip to content

Commit d8cb242

Browse files
committed
libs/module: Add PLUS module.
Signed-off-by: Tinyu <[email protected]>
1 parent 932e266 commit d8cb242

File tree

8 files changed

+322
-8
lines changed

8 files changed

+322
-8
lines changed

docs/en/module/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ Module
88
display.rst
99
dualkmeter.rst
1010
hmi.rst
11+
plus.rst
1112
pps.rst
1213
rca.rst

docs/en/module/plus.rst

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
2+
PLUS Module
3+
=========
4+
5+
.. include:: ../refs/module.plus.ref
6+
7+
Support the following products:
8+
9+
|PLUS Module|
10+
11+
Micropython Example::
12+
13+
import os, sys, io
14+
import M5
15+
from M5 import *
16+
from module import PLUSModule
17+
18+
19+
20+
title0 = None
21+
label2 = None
22+
label0 = None
23+
label1 = None
24+
plus_0 = None
25+
26+
27+
btn_state = None
28+
last_btn_state = None
29+
30+
31+
def setup():
32+
global title0, label2, label0, label1, plus_0, btn_state, last_btn_state
33+
34+
M5.begin()
35+
Widgets.fillScreen(0x222222)
36+
title0 = Widgets.Title("PLUS Core2 Test", 3, 0xffffff, 0x0000FF, Widgets.FONTS.DejaVu18)
37+
label2 = Widgets.Label("Btn rotray:", 1, 166, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
38+
label0 = Widgets.Label("Rotary:", 1, 60, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
39+
label1 = Widgets.Label("Rotary Inc:", 1, 111, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
40+
41+
plus_0 = PLUSModule(address=0x62)
42+
plus_0.set_rotary_value(0)
43+
44+
45+
def loop():
46+
global title0, label2, label0, label1, plus_0, btn_state, last_btn_state
47+
M5.update()
48+
btn_state = plus_0.get_button_status()
49+
label0.setText(str((str('Rotary:') + str((plus_0.get_rotary_value())))))
50+
label2.setText(str((str('Btn rotray:') + str(btn_state))))
51+
if btn_state and btn_state != last_btn_state:
52+
label1.setText(str((str('Rotary Inc:') + str((plus_0.get_rotary_increments())))))
53+
last_btn_state = btn_state
54+
55+
56+
if __name__ == '__main__':
57+
try:
58+
setup()
59+
while True:
60+
loop()
61+
except (Exception, KeyboardInterrupt) as e:
62+
try:
63+
from utility import print_error_msg
64+
print_error_msg(e)
65+
except ImportError:
66+
print("please update to latest firmware")
67+
68+
UIFLOW2 Example:
69+
70+
|example.png|
71+
72+
.. only:: builder_html
73+
74+
|plus_core2_example.m5f2|
75+
76+
class PLUSModule
77+
---------------
78+
79+
Constructors
80+
------------
81+
82+
.. class:: PLUSModule(address)
83+
84+
Init I2C Module PLUS I2C Address.
85+
86+
:param int|list|tuple address: I2C address of the PLUSModule.
87+
88+
UIFLOW2:
89+
90+
|init.png|
91+
92+
Methods
93+
-------
94+
95+
.. method:: PLUSModule.get_rotary_value() -> int
96+
97+
Get the current value of the rotary.
98+
99+
:return: The value of the rotary relative to the zero point.
100+
101+
UIFLOW2:
102+
103+
|get_rotary_value.png|
104+
105+
.. method:: PLUSModule.set_rotary_value(value)
106+
107+
Set the rotary value.
108+
109+
:param int value: rotary value.
110+
111+
UIFLOW2:
112+
113+
|set_rotary_value.png|
114+
115+
.. method:: PLUSModule.reset_rotary_value()
116+
117+
Reset the rotary value.
118+
119+
UIFLOW2:
120+
121+
|reset_rotary_value.png|
122+
123+
.. method:: PLUSModule.set_rotary_value(value)
124+
125+
Set the rotary value.
126+
127+
:param int value: rotary value.
128+
129+
UIFLOW2:
130+
131+
|set_rotary_value.png|
132+
133+
.. method:: PLUSModule.get_rotary_increments() -> int
134+
135+
Get the increments of the rotary value since the last call of this function.
136+
137+
:return: The increment value of the rotary.
138+
139+
UIFLOW2:
140+
141+
|get_rotary_increments.png|
142+
143+
.. method:: HMIModule.get_button_status() -> int
144+
145+
Get the state of a specific button.
146+
147+
UIFLOW2:
148+
149+
|get_button_status.png|
150+

docs/en/refs/module.plus.ref

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.. |PLUS Module| image:: https://static-cdn.m5stack.com/resource/docs/products/module/plus/plus_01.webp
2+
:target: https://docs.m5stack.com/en/module/plus
3+
:height: 200px
4+
:width: 200px
5+
6+
.. |init.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/init.png
7+
.. |get_rotary_value.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/get_encoder_value.png
8+
.. |set_rotary_value.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/set_encoder_value.png
9+
.. |reset_rotary_value.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/reset_encoder.png
10+
.. |get_button_status.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/get_button_state.png
11+
.. |get_rotary_increments.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/get_rotary_increments.png
12+
.. |example.png| image:: https://static-cdn.m5stack.com/mpy_docs/module/plus/example.png
13+
14+
15+
.. |plus_core2_example.m5f2| raw:: html
16+
17+
<a
18+
href="https://uiflow2.m5stack.com/?example=https://raw.githubusercontent.com/m5stack/uiflow-micropython/develop/examples/module/tmos/plus_core2_example.m5f2"
19+
target="_blank"
20+
>
21+
plus_core2_example.m5f2
22+
</a>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":"V2.0","versionNumber":"V2.1.2","type":"core2","components":[{"name":"screen","type":"screen","layer":0,"screenId":"builtin","screenName":"","id":"__core2_screen","createTime":1722824950443,"x":0,"y":0,"width":320,"height":240,"backgroundColor":"#222222","size":0,"isSelected":true},{"name":"title0","type":"title","layer":1,"screenId":"builtin","screenName":"","id":"u&#9^s3=e+JFdXqa","createTime":1722824959179,"x":0,"y":0,"color":"#ffffff","backgroundColor":"#0000FF","text":"PLUS Core2 Test","textOffset":3,"font":"Widgets.FONTS.DejaVu18","isSelected":false},{"name":"label2","type":"label","layer":2,"screenId":"builtin","screenName":"","id":"k0CYIBWhjPYMY46w","createTime":1722824988901,"x":1,"y":166,"color":"#ffffff","backgroundColor":"#222222","text":"Btn rotray:","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false},{"name":"label0","type":"label","layer":6,"screenId":"builtin","screenName":"","id":"wF1oE5pQjSBv-M!=","createTime":1722825034891,"x":1,"y":60,"color":"#ffffff","backgroundColor":"#222222","text":"Rotary:","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false},{"name":"label1","type":"label","layer":8,"screenId":"builtin","screenName":"","id":"gA+45INUXpy91CFQ","createTime":1722825166720,"x":1,"y":111,"color":"#ffffff","backgroundColor":"#222222","text":"Rotary Inc:","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false}],"resources":[{"hardware":["hardware_button","hardware_pin_button","imu","speaker","touch","mic","i2c"]},{"module":["module_plus"]}],"units":[],"hats":[],"bases":[],"i2cs":[{"id":"i2c0","portType":"A","userPort":[22,21],"freq":"100000","blockId":"uVbuK_(!IX6AeiPjU},("}],"blockly":"<variables><variable id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</variable><variable id=\"O~~RZMn6TCH~OjP_Q$zw\">last_btn_state</variable></variables><block type=\"basic_on_setup\" id=\"setup_block\" deletable=\"false\" x=\"-110\" y=\"-269\"><mutation isBegin=\"true\"></mutation><field name=\"UPDATEOP\">true</field><statement name=\"FUNC\"><block type=\"system_m5_begin\" id=\"system_m5_begin\"><next><block type=\"module_plus_init\" id=\"iC8BxS?]hdKqEtAP5h(5\"><field name=\"NAME\">plus_0</field><value name=\"ADDR\"><shadow type=\"module_plus_addr_option\" id=\"X}}/T76jozY4p]-s.*Z)\"><field name=\"VALUE\">0x62</field></shadow></value><next><block type=\"module_plus_set_encoder_value\" id=\"`pUeP,%jb#ApKaaDv5_U\"><field name=\"NAME\">plus_0</field><value name=\"VALUE\"><shadow type=\"math_number\" id=\"T}RD$Lxwt`$m{tF@0o{E\"><mutation max=\"Infinity\" min=\"-Infinity\" precision=\"0\"></mutation><field name=\"NUM\">0</field></shadow></value></block></next></block></next></block></statement></block><block type=\"basic_on_loop\" id=\"loop_block\" deletable=\"false\" x=\"-110\" y=\"-70\"><mutation isUpdate=\"true\"></mutation><field name=\"UPDATEOP\">true</field><statement name=\"FUNC\"><block type=\"system_m5_update\" id=\"system_m5_update\"><next><block type=\"variables_set\" id=\"f]#+6j:6Hcqj9-JENe`j\"><field name=\"VAR\" id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</field><value name=\"VALUE\"><block type=\"module_plus_get_button_state\" id=\"c:N{2/-}B?[o5@U(Xl%V\"><field name=\"NAME\">plus_0</field></block></value><next><block type=\"label_set_text\" id=\"%N0HrPuq{JSTr.o-amDh\"><field name=\"NAME\">label0</field><value name=\"TEXT\"><shadow type=\"text\" id=\"Ns8_)dH%+3h^D{i+.2L+\"><field name=\"TEXT\">Label</field></shadow><block type=\"text_add_str\" id=\"W3_%62t5UlD!u88hGg{9\"><value name=\"VALUE1\"><shadow type=\"text\" id=\"rYO%/q0kpsyh$cUj,]qf\"><field name=\"TEXT\">Rotary:</field></shadow></value><value name=\"VALUE2\"><block type=\"module_plus_get_encoder_value\" id=\"dnT_E}HxCR44B.{%YU6j\"><field name=\"NAME\">plus_0</field></block></value></block></value><next><block type=\"label_set_text\" id=\"t#BXsEBZ!Q^]}PR(oAqZ\"><field name=\"NAME\">label2</field><value name=\"TEXT\"><shadow type=\"text\" id=\"Ns8_)dH%+3h^D{i+.2L+\"><field name=\"TEXT\">Label</field></shadow><block type=\"text_add_str\" id=\"{=f;]NtV:fWbV??F*hLN\"><value name=\"VALUE1\"><shadow type=\"text\" id=\"(.3atg:xjV;6O@])2NA:\"><field name=\"TEXT\">Btn rotray:</field></shadow></value><value name=\"VALUE2\"><block type=\"variables_get\" id=\"aC;iaZ_]:`%KTCnfHkMa\"><field name=\"VAR\" id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</field></block></value></block></value><next><block type=\"controls_if\" id=\"qR,B~qk-uXV9ai]_Vgy-\"><value name=\"IF0\"><block type=\"logic_operation\" id=\"eEL%%(Y{T%%_iWOmOBe?\"><field name=\"OP\">AND</field><value name=\"A\"><block type=\"variables_get\" id=\"_{MIP@pZ#JR-fMk`0^_]\"><field name=\"VAR\" id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</field></block></value><value name=\"B\"><block type=\"logic_compare\" id=\"H(Bxt/dDej03U6[E8*]P\"><field name=\"OP\">NEQ</field><value name=\"A\"><block type=\"variables_get\" id=\"xBpOG}nJSm+Ry_6}S*}O\"><field name=\"VAR\" id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</field></block></value><value name=\"B\"><block type=\"variables_get\" id=\":G8/+HKmvUZ8_/Mn84fl\"><field name=\"VAR\" id=\"O~~RZMn6TCH~OjP_Q$zw\">last_btn_state</field></block></value></block></value></block></value><statement name=\"DO0\"><block type=\"label_set_text\" id=\"QCP]Xf2KVs-/hKH3Tx@T\"><field name=\"NAME\">label1</field><value name=\"TEXT\"><shadow type=\"text\" id=\"Ns8_)dH%+3h^D{i+.2L+\"><field name=\"TEXT\">Label</field></shadow><block type=\"text_add_str\" id=\"Hq`O=#EfcNil=wxI4nk|\"><value name=\"VALUE1\"><shadow type=\"text\" id=\"NZxeTzhO11~4G=#{Q@(1\"><field name=\"TEXT\">Rotary Inc:</field></shadow></value><value name=\"VALUE2\"><block type=\"module_plus_get_increment_value\" id=\"-y0M~KVcsvsr(({85H0{\"><field name=\"NAME\">plus_0</field></block></value></block></value></block></statement><next><block type=\"variables_set\" id=\"~R_.(}cM,BKG.qfw,C/`\"><field name=\"VAR\" id=\"O~~RZMn6TCH~OjP_Q$zw\">last_btn_state</field><value name=\"VALUE\"><block type=\"variables_get\" id=\"*/xoR*A.*.dMsk@KgT2U\"><field name=\"VAR\" id=\"IAlSRb,6:]Hd?ORuzRVf\">btn_state</field></block></value></block></next></block></next></block></next></block></next></block></next></block></statement></block>","screen":[{"simulationName":"Built-in","type":"builtin","width":320,"height":240,"scale":0.78,"screenName":"","blockId":"","screenColorType":0,"id":"builtin","createTime":1722824950441}],"logicWhenNum":0,"customList":[]}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import os, sys, io
6+
import M5
7+
from M5 import *
8+
from module import PLUSModule
9+
10+
11+
title0 = None
12+
label2 = None
13+
label0 = None
14+
label1 = None
15+
plus_0 = None
16+
17+
18+
btn_state = None
19+
last_btn_state = None
20+
21+
22+
def setup():
23+
global title0, label2, label0, label1, plus_0, btn_state, last_btn_state
24+
25+
M5.begin()
26+
Widgets.fillScreen(0x222222)
27+
title0 = Widgets.Title("PLUS Core2 Test", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu18)
28+
label2 = Widgets.Label("Btn rotray:", 1, 166, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
29+
label0 = Widgets.Label("Rotary:", 1, 60, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
30+
label1 = Widgets.Label("Rotary Inc:", 1, 111, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
31+
32+
plus_0 = PLUSModule(address=0x62)
33+
plus_0.set_rotary_value(0)
34+
35+
36+
def loop():
37+
global title0, label2, label0, label1, plus_0, btn_state, last_btn_state
38+
M5.update()
39+
btn_state = plus_0.get_button_status()
40+
label0.setText(str((str("Rotary:") + str((plus_0.get_rotary_value())))))
41+
label2.setText(str((str("Btn rotray:") + str(btn_state))))
42+
if btn_state and btn_state != last_btn_state:
43+
label1.setText(str((str("Rotary Inc:") + str((plus_0.get_rotary_increments())))))
44+
last_btn_state = btn_state
45+
46+
47+
if __name__ == "__main__":
48+
try:
49+
setup()
50+
while True:
51+
loop()
52+
except (Exception, KeyboardInterrupt) as e:
53+
try:
54+
from utility import print_error_msg
55+
56+
print_error_msg(e)
57+
except ImportError:
58+
print("please update to latest firmware")

m5stack/libs/module/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
_attrs = {
88
"AIN4Module": "ain4",
9+
"DisplayModule": "display",
910
"DualKmeterModule": "dual_kmeter",
10-
"Relay4Module": "relay_4",
1111
"Encoder4MotorModule": "encoder4_motor",
1212
"HMIModule": "hmi",
13-
"PPSModule": "pps",
1413
"IotBaseCatmModule": "iot_base_catm",
14+
"PLUSModule": "plus",
15+
"PPSModule": "pps",
1516
"RCAModule": "rca",
16-
"DisplayModule": "display",
17+
"Relay4Module": "relay_4",
1718
}
1819

1920
# Lazy loader, effectively does:

m5stack/libs/module/manifest.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77
(
88
"__init__.py",
99
"ain4.py",
10+
"display.py",
1011
"dual_kmeter.py",
11-
"mbus.py",
12-
"relay_4.py",
13-
"module_helper.py",
1412
"encoder4_motor.py",
1513
"hmi.py",
16-
"pps.py",
1714
"iot_base_catm.py",
15+
"mbus.py",
16+
"module_helper.py",
17+
"plus.py",
18+
"pps.py",
1819
"rca.py",
19-
"display.py",
20+
"relay_4.py",
2021
),
2122
base_path="..",
2223
opt=0,

m5stack/libs/module/plus.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
from .mbus import i2c1
6+
7+
8+
class PLUSModule:
9+
"""! PLUS is a enhanced M5 module comes with lithium polymer battery(500mAh), gear potentiometer, IR transmitter, extend PORT B(GPIO Port), PORT C(UART Port) from M5 core and a Microphone soldering pad.
10+
11+
@en Module PLUS 英文介绍
12+
@cn Module PLUS 中文介绍
13+
14+
@color #0FE6D7
15+
@link https://docs.m5stack.com/en/module/plus
16+
@image https://static-cdn.m5stack.com/resource/docs/products/module/plus/plus_01.webp
17+
@category module
18+
"""
19+
20+
_PLUS_ADDR = 0x62
21+
22+
def __init__(self, address: int | list | tuple = _PLUS_ADDR) -> None:
23+
"""! Init I2C Module PLUS I2C Address.
24+
25+
@param address I2C address of the PLUSModule.
26+
"""
27+
self._i2c = i2c1
28+
self._i2c_addr = address
29+
if self._i2c_addr not in self._i2c.scan():
30+
raise Exception("PLUS Module not found in Base")
31+
self._encode_value = 0
32+
self._zero_value = 0
33+
self._last_value = self.get_rotary_value()
34+
self._last_increment_value = self._last_value
35+
self._zero_value = self._last_value
36+
37+
def get_rotary_value(self) -> int:
38+
"""Get the current value of the rotary.
39+
40+
@return: The value of the rotary relative to the zero point.
41+
"""
42+
buf = self._i2c.readfrom_mem(self._i2c_addr, self._PLUS_ADDR, 2)
43+
byte_value = buf[0]
44+
45+
if byte_value & 0x80:
46+
byte_value -= 256
47+
self._encode_value += byte_value
48+
49+
current_value = self._encode_value - self._zero_value
50+
self._last_value = self._encode_value
51+
return current_value
52+
53+
def reset_rotary_value(self) -> None:
54+
self._zero_value = self.get_rotary_value()
55+
56+
def set_rotary_value(self, value: int) -> None:
57+
"""! Set the rotary value.
58+
59+
@param value: rotary value.
60+
"""
61+
self._encode_value = value
62+
63+
def get_rotary_increments(self) -> int:
64+
"""Get the increments of the rotary value since the last call of this function.
65+
66+
@return: The increment value of the rotary.
67+
"""
68+
current_value = self.get_rotary_value()
69+
increments = current_value - self._last_increment_value
70+
if increments != 0:
71+
self._last_increment_value = current_value
72+
return increments
73+
74+
def get_button_status(self) -> bool:
75+
"""! Get the state of a specific button.
76+
77+
@return: The state of the button.
78+
"""
79+
data = self._i2c.readfrom(self._PLUS_ADDR, 2)
80+
return bool(data[1] != 0xFF)

0 commit comments

Comments
 (0)