Skip to content

Commit cc35ec9

Browse files
committed
smart_panel: T-Panel S3 (H720) firmware + manifest
Adds firmware for LILYGO T-Panel S3 with the CAN FD module (SKU H720). 12 intents, 2 events, ~400 LoC C++ stub ready to flash on arrival. Manifest (examples/smart_panel_manifest.yaml): v0.3 visual + audio (works on any S3 board): set_backlight, set_color, display_text, clear_screen, play_tone, play_score, stop_playback, read_touch v0.4 CAN bus: can_send, can_receive_last + touch/can events v0.5 motor stubs: move_motor, read_motor_position (return denied for now) Firmware highlights: - ST7701S 4" 480x480 RGB-parallel display via Arduino_GFX - CST3240 capacitive touch via TouchLib - ESP32-S3 TWAI classic CAN @ 500kbps via TD501MCANFD transceiver - MML-string melody parser ("C4q E4q G4q C5h" syntax) - Non-blocking score scheduler in loop() so DCP polling is never starved - Buzzer/speaker on user-added GPIO 19 Honest caveats documented in code: - T-Panel does not include a speaker; user must add ~Y10 buzzer - ESP32-S3 TWAI is classic CAN, not CAN FD (despite H720 SKU naming). TD501MCANFD is CAN FD capable on the physical layer but the MCU only generates classic CAN frames. v0.5 plan: port to ESP32-P4 for native CAN FD. - v0.5 motor intents are stubbed; real CANopen/stepper handler comes after the CAN-bus stepper driver is wired up. Validated via dcp inspect: 12 intents + 2 events parse correctly. Firmware will be flashed and round-tripped on hardware arrival.
1 parent f787e93 commit cc35ec9

2 files changed

Lines changed: 583 additions & 0 deletions

File tree

examples/smart_panel_manifest.yaml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Smart Panel manifest — for LILYGO T-Panel S3 (H720 CAN FD variant).
2+
#
3+
# Covers DCP v0.3 (piano + visual) and v0.4 (CAN bus orchestration) demos.
4+
# Intents marked v0.5 are stubbed; firmware will compile but return STATUS_DENIED
5+
# until you flash the v0.5 firmware build.
6+
#
7+
# Hardware mapping (pin_config.h):
8+
# LCD backlight : GPIO 14 (PWM)
9+
# Buzzer/speaker : GPIO 19 (PWM, user-added — solder a piezo or amp+8Ω here)
10+
# Touch INT : GPIO 21
11+
# CAN TX/RX : GPIO 16/15 (TD501MCANFD transceiver)
12+
# I2C : GPIO 17/18 (CST3240 touch + XL9535 GPIO expander)
13+
14+
dcp: 0.3
15+
device:
16+
id: smart-panel-01
17+
model: lilygo_t_panel_s3_h720
18+
vendor: deeplethe
19+
20+
intents:
21+
# ─── v0.3 — visual + audio (no CAN needed) ───────────────────────
22+
23+
- name: set_backlight
24+
params:
25+
level: { type: float, unit: percent, range: [0, 100] }
26+
capability: panel.write
27+
idempotent: true
28+
dry_run: true
29+
30+
- name: set_color
31+
params:
32+
r: { type: int, range: [0, 255] }
33+
g: { type: int, range: [0, 255] }
34+
b: { type: int, range: [0, 255] }
35+
capability: panel.write
36+
idempotent: true
37+
dry_run: true
38+
39+
- name: display_text
40+
params:
41+
text: { type: string } # ≤22 chars (CBOR subset)
42+
line: { type: int, range: [0, 9], default: 0 }
43+
size: { type: int, range: [1, 4], default: 2 }
44+
capability: panel.write
45+
idempotent: true
46+
47+
- name: clear_screen
48+
capability: panel.write
49+
idempotent: true
50+
51+
- name: play_tone
52+
params:
53+
freq: { type: int, unit: hz, range: [50, 5000] }
54+
duration: { type: duration, unit: ms, range: [10, 5000], default: 200 }
55+
capability: panel.write
56+
idempotent: false
57+
dry_run: true
58+
59+
- name: play_score
60+
# Encoded as MML-ish string for compactness:
61+
# "C4q E4q G4q C5h" q=quarter h=half e=eighth s=sixteenth, suffix . dotted
62+
# Bass voice in second field (optional polyphony).
63+
params:
64+
melody: { type: string }
65+
bass: { type: string, default: "" }
66+
tempo: { type: int, unit: bpm, range: [40, 240], default: 120 }
67+
voice: { type: string, default: "square" } # square | triangle | sine
68+
capability: panel.write
69+
idempotent: false
70+
dry_run: true
71+
72+
- name: stop_playback
73+
capability: panel.write
74+
idempotent: true
75+
76+
- name: read_touch
77+
returns: { type: bool }
78+
capability: panel.read
79+
80+
# ─── v0.4 — CAN bus orchestration ────────────────────────────────
81+
82+
- name: can_send
83+
# Send a raw CAN frame on the bus. Used for direct device control
84+
# (e.g. driving a CAN stepper-motor controller).
85+
params:
86+
id: { type: int, range: [0, 536870911] } # 29-bit extended OK
87+
data_hex: { type: string } # up to 16 hex chars = 8 bytes
88+
extended: { type: bool, default: false }
89+
capability: can.write
90+
idempotent: false
91+
dry_run: true
92+
93+
- name: can_receive_last
94+
# Returns the most recently received CAN frame.
95+
returns: { type: string } # "id=0x123 data=01020304"
96+
capability: can.read
97+
98+
# ─── v0.5 — high-level CAN device shortcuts (stepper motor demo) ──
99+
100+
- name: move_motor
101+
params:
102+
angle: { type: float, unit: degree, range: [-3600, 3600] }
103+
speed: { type: int, unit: rpm, range: [1, 300], default: 60 }
104+
motor_id: { type: int, range: [1, 16], default: 1 }
105+
capability: motor.write
106+
idempotent: false
107+
dry_run: true
108+
109+
- name: read_motor_position
110+
params:
111+
motor_id: { type: int, range: [1, 16], default: 1 }
112+
returns: { type: float, unit: degree }
113+
capability: motor.read
114+
115+
events:
116+
- name: touch_pressed
117+
payload:
118+
x: { type: int, range: [0, 480] }
119+
y: { type: int, range: [0, 480] }
120+
region: { type: string } # "top", "bottom-left", "center" etc — semantic zones
121+
capability: panel.read
122+
123+
- name: can_received
124+
# Pushed when a CAN frame arrives. The Bridge fans out to subscribers
125+
# with the right capability.
126+
payload:
127+
id: { type: int, range: [0, 536870911] }
128+
data_hex: { type: string }
129+
capability: can.read

0 commit comments

Comments
 (0)