tirtc-device-builder 0.9.7 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +47 -0
- package/README.md +2 -1
- package/bin/esp32-kit-metadata.js +27 -0
- package/bin/install-esp32-kit.js +50 -19
- package/package.json +1 -1
- package/skills/tirtc-esp32-builder/SKILL.md +8 -3
- package/skills/tirtc-esp32-builder/USAGE.md +18 -0
- package/skills/tirtc-esp32-builder/VERSION +1 -1
- package/skills/tirtc-esp32-builder/knowledge/board-registry.json +62 -0
- package/skills/tirtc-esp32-builder/knowledge/waveshare-esp32-p4-wifi6-touch-lcd-3.5/knowledge.md +9 -0
- package/skills/tirtc-esp32-builder/knowledge/waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md +68 -0
- package/skills/tirtc-esp32-builder/references/display-pipeline.md +61 -0
- package/skills/tirtc-esp32-builder/references/environment.md +13 -4
- package/skills/tirtc-esp32-builder/scripts/doctor.py +38 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
This project follows Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.10.1
|
|
6
|
+
|
|
7
|
+
- Add a knowledge-only Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3-C V1.0 package
|
|
8
|
+
with artifact-bound ST7701 display, GT911 touch and ES7210 TDM/AEC lessons.
|
|
9
|
+
- Add RAM-less DSI display guidance covering safe initial back-buffer selection,
|
|
10
|
+
VSYNC ownership, partial-refresh damage carry-forward, LVGL software rotation,
|
|
11
|
+
RGB565 byte order, touch mapping and runtime display-size scaling.
|
|
12
|
+
- Test exact 4.3-C registry matching while keeping adapter reuse disabled.
|
|
13
|
+
|
|
14
|
+
## 0.10.0
|
|
15
|
+
|
|
16
|
+
- Align the Kit's provisioning and device-binding implementation with the
|
|
17
|
+
reference XiaoTai product firmware (ships in the ESP32-S3 Device Kit
|
|
18
|
+
1.2.0 release, tagged separately):
|
|
19
|
+
- Wi-Fi provisioning: the embedded setup page gains a live scan list
|
|
20
|
+
(`POST /api/scan`, `GET /api/networks`), saved-network history with
|
|
21
|
+
`use_saved` password reuse, portal isolation to the SoftAP interface and
|
|
22
|
+
Origin checks on writes, exponential retry (1/2/4/8/15/30 s) with the
|
|
23
|
+
portal opened alongside retries after 5 consecutive failures, a manual
|
|
24
|
+
`wifi-change` entrance that retains credentials, and a station fallback
|
|
25
|
+
DNS slot (`CONFIG_WIFI_MANAGER_FALLBACK_DNS_IPV4`, default 223.5.5.5).
|
|
26
|
+
- Device binding: fresh-boot SNTP is required before any authentication;
|
|
27
|
+
the verification-code TTS endpoint (`GET /v1/device/tts`) is supported
|
|
28
|
+
behind a prompt callback (NULL by default; headless devices keep the
|
|
29
|
+
serial code); binding failures and rebinds can be retried without a
|
|
30
|
+
reboot (`bind-retry`); an `unbind` signal or a 6006 token response now
|
|
31
|
+
triggers identity reconciliation and a signed rebind that retains the
|
|
32
|
+
stored identity instead of clearing NVS and restarting.
|
|
33
|
+
- Shared components (`wifi_manager`, `platform_client`, `runtime_config`)
|
|
34
|
+
keep dual-target ESP32-S3/ESP32-P4 conditionals so future P4 ports can
|
|
35
|
+
reuse them unchanged.
|
|
36
|
+
- Extend the Kit packing contract and generator tests to cover the new
|
|
37
|
+
portal endpoints, history component, embedded setup page, and portal
|
|
38
|
+
isolation; keep the `XiaoTai-` / open-auth / 192.168.6.1 SoftAP contract.
|
|
39
|
+
- Add the ESP32-P4 Device Kit: TiRTC P4 SDK 2.5.0 (vendor baseline
|
|
40
|
+
`9b4e35c7`, IDF 5.5.4 / 1000 Hz / LWIP_MAX_SOCKETS=10 contract), the
|
|
41
|
+
XiaoTai P4 1.4.0 reference firmware imported as `device-sim-p4` (shared
|
|
42
|
+
transport components resolve from the S3 reference; the P4 `tirtc_sdk`
|
|
43
|
+
wrapper re-pins the archive), generator `--target esp32p4` copy mode,
|
|
44
|
+
per-target pack/metadata/installer plumbing, a `publish-p4` release job
|
|
45
|
+
that fails until the P4 kit is pinned, and P4-aware Doctor SDK resolution
|
|
46
|
+
and contract keys. Managed `setup` stays ESP32-S3-only.
|
|
47
|
+
- Device Kit releases (1.2.0 for S3, 1.0.0 for P4) and checksum pinning
|
|
48
|
+
are deferred to their release workflows; no sha256 is fabricated in this
|
|
49
|
+
changelog. Until the S3 Kit 1.2.0 is tagged, managed setup keeps
|
|
50
|
+
installing the pinned 1.1.7 Kit.
|
|
51
|
+
|
|
5
52
|
## 0.9.7
|
|
6
53
|
|
|
7
54
|
- Pin ESP32-S3 Device Kit 1.1.7 with the `XiaoTai-` SoftAP name and the
|
package/README.md
CHANGED
|
@@ -8,11 +8,12 @@ TiRTC Device Builder 用于把 ESP32-S3/ESP32-P4 开发板接入 TiRTC。输入
|
|
|
8
8
|
|---|---|---|
|
|
9
9
|
| `tirtc-esp32-builder` | ESP32-S3 / ESP32-P4、ESP-IDF 5.5.x | 板型识别、Hardware IR、工程生成/移植、H5/AI/设备互呼/微信 VoIP、AEC 门禁、编译烧录和分层验收 |
|
|
10
10
|
|
|
11
|
-
H5/AI 的 ESP32-S3 托管模板、协议文档和 TiRTC SDK 已打包在独立的 ESP32 Device Kit 中,安装时会自动下载并校验。ESP32 示例源码由本仓库的 `kit-src/` 维护;设备互呼或微信 VoIP 的移植可参考其中的独立示例。ESP32-P4
|
|
11
|
+
H5/AI 的 ESP32-S3 托管模板、协议文档和 TiRTC SDK 已打包在独立的 ESP32 Device Kit 中,安装时会自动下载并校验。ESP32 示例源码由本仓库的 `kit-src/` 维护;设备互呼或微信 VoIP 的移植可参考其中的独立示例。ESP32-P4 使用独立发布的 `tirtc-esp32p4-kit`(小钛 P4 参考固件:hosted C6 Wi-Fi + LVGL UI + 摄像头 + P4 SDK 2.5.0),通过生成器 `--target esp32p4` 复制生成,不能复用 S3 预编译库。
|
|
12
12
|
|
|
13
13
|
- npm 包:[tirtc-device-builder](https://www.npmjs.com/package/tirtc-device-builder)
|
|
14
14
|
- GitHub 仓库:[tangeai/tirtc-device-builder](https://github.com/tangeai/tirtc-device-builder)
|
|
15
15
|
- ESP32 Device Kit:[kit-esp32s3-v1.1.7](https://github.com/tangeai/tirtc-device-builder/releases/tag/kit-esp32s3-v1.1.7)
|
|
16
|
+
- ESP32-P4 Device Kit:`tirtc-esp32p4-kit`(首次发布前以 `kit-esp32p4-v*` tag 发布的 GitHub Release 为准)
|
|
16
17
|
|
|
17
18
|
文档导航:
|
|
18
19
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export const ESP32_KIT = Object.freeze({
|
|
2
|
+
target: "esp32s3",
|
|
3
|
+
platform: "espressif-esp32s3",
|
|
2
4
|
archiveName: "tirtc-esp32s3-kit-1.1.7.tar.gz",
|
|
3
5
|
archiveRoot: "tirtc-esp32s3-kit-1.1.7",
|
|
4
6
|
releaseTag: "kit-esp32s3-v1.1.7",
|
|
@@ -7,4 +9,29 @@ export const ESP32_KIT = Object.freeze({
|
|
|
7
9
|
sourceCommit: "50be0b4b6ad83ca376e010ebb7256db4fb6debcd",
|
|
8
10
|
url: "https://github.com/tangeai/tirtc-device-builder/releases/download/kit-esp32s3-v1.1.7/tirtc-esp32s3-kit-1.1.7.tar.gz",
|
|
9
11
|
version: "1.1.7",
|
|
12
|
+
released: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* The ESP32-P4 Device Kit is pinned by its first release. Until the release
|
|
17
|
+
* workflow publishes and pins it, sha256/sourceCommit/url stay null and the
|
|
18
|
+
* publish-p4 job fails any premature kit-esp32p4-v* tag. Nothing is fabricated.
|
|
19
|
+
*/
|
|
20
|
+
export const ESP32_P4_KIT = Object.freeze({
|
|
21
|
+
target: "esp32p4",
|
|
22
|
+
platform: "espressif-esp32p4",
|
|
23
|
+
archiveName: "tirtc-esp32p4-kit-1.0.0.tar.gz",
|
|
24
|
+
archiveRoot: "tirtc-esp32p4-kit-1.0.0",
|
|
25
|
+
releaseTag: "kit-esp32p4-v1.0.0",
|
|
26
|
+
sha256: null,
|
|
27
|
+
sdkVersion: "2.5.0",
|
|
28
|
+
sourceCommit: null,
|
|
29
|
+
url: null,
|
|
30
|
+
version: "1.0.0",
|
|
31
|
+
released: false,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const ESP32_KITS = Object.freeze({
|
|
35
|
+
esp32s3: ESP32_KIT,
|
|
36
|
+
esp32p4: ESP32_P4_KIT,
|
|
10
37
|
});
|
package/bin/install-esp32-kit.js
CHANGED
|
@@ -16,15 +16,30 @@ import {
|
|
|
16
16
|
import { tmpdir } from "node:os";
|
|
17
17
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
|
-
import { ESP32_KIT } from "./esp32-kit-metadata.js";
|
|
19
|
+
import { ESP32_KIT, ESP32_KITS } from "./esp32-kit-metadata.js";
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const REQUIRED_FILES_BY_TARGET = {
|
|
22
|
+
esp32s3: [
|
|
23
|
+
"manifest.json",
|
|
24
|
+
"device-sim/scripts/create_esp32_project.py",
|
|
25
|
+
"device-sim/templates/esp32-h5-ai/CMakeLists.txt",
|
|
26
|
+
"device-sim/templates/esp32-h5-ai/platform-media-contract.json",
|
|
27
|
+
"device-sim/templates/esp32-h5-ai/tirtc-runtime-contract.json",
|
|
28
|
+
],
|
|
29
|
+
esp32p4: [
|
|
30
|
+
"manifest.json",
|
|
31
|
+
"device-sim/scripts/create_esp32_project.py",
|
|
32
|
+
"device-sim/device-sim-p4/CMakeLists.txt",
|
|
33
|
+
"device-sim/device-sim-p4/sdkconfig.defaults",
|
|
34
|
+
"device-sim/device-sim-p4/dependencies.lock",
|
|
35
|
+
"device-sim/device-sim-esp32/components/wifi_manager/src/wifi_manager.c",
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const SDK_VERSION_PATTERN_BY_TARGET = {
|
|
40
|
+
esp32s3: /^(?:2\.3\.0|2\.5\.0)$/,
|
|
41
|
+
esp32p4: /^2\.5\.0$/,
|
|
42
|
+
};
|
|
28
43
|
|
|
29
44
|
function hashFile(path) {
|
|
30
45
|
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
@@ -77,7 +92,8 @@ function assertNoLinks(root, current = root) {
|
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
function validateExtractedKit(root, metadata) {
|
|
80
|
-
const
|
|
95
|
+
const requiredFiles = REQUIRED_FILES_BY_TARGET[metadata.target] ?? [];
|
|
96
|
+
const missing = requiredFiles.filter((path) => !existsSync(join(root, path)));
|
|
81
97
|
if (missing.length > 0) {
|
|
82
98
|
throw new Error(`Device Kit is incomplete: ${missing.join(", ")}`);
|
|
83
99
|
}
|
|
@@ -95,12 +111,15 @@ function validateExtractedKit(root, metadata) {
|
|
|
95
111
|
`Device Kit version mismatch: expected ${metadata.version}, got ${manifest.kit_version}`,
|
|
96
112
|
);
|
|
97
113
|
}
|
|
98
|
-
|
|
99
|
-
|
|
114
|
+
const sdkPattern = SDK_VERSION_PATTERN_BY_TARGET[metadata.target];
|
|
115
|
+
if (!sdkPattern ||
|
|
116
|
+
manifest.target !== metadata.target ||
|
|
117
|
+
manifest.platform !== metadata.platform ||
|
|
118
|
+
!sdkPattern.test(manifest.tirtc_sdk_version) ||
|
|
100
119
|
(metadata.sdkVersion && manifest.tirtc_sdk_version !== metadata.sdkVersion)) {
|
|
101
120
|
throw new Error("Device Kit target or TiRTC SDK version is incompatible");
|
|
102
121
|
}
|
|
103
|
-
const sdkRoot = `device-sim/sdk
|
|
122
|
+
const sdkRoot = `device-sim/sdk/${metadata.platform}/${manifest.tirtc_sdk_version}`;
|
|
104
123
|
const sdkFiles = [
|
|
105
124
|
`${sdkRoot}/include/tirtc/tiRTC.h`,
|
|
106
125
|
`${sdkRoot}/lib/libTiRTC.a`,
|
|
@@ -170,17 +189,20 @@ async function download(url, destination) {
|
|
|
170
189
|
function parseArgs(args) {
|
|
171
190
|
let archive = null;
|
|
172
191
|
let target = null;
|
|
192
|
+
let kit = "esp32s3";
|
|
173
193
|
for (let index = 0; index < args.length; index += 1) {
|
|
174
194
|
const argument = args[index];
|
|
175
|
-
if (argument === "--archive" || argument === "--target") {
|
|
195
|
+
if (argument === "--archive" || argument === "--target" || argument === "--kit") {
|
|
176
196
|
const value = args[index + 1];
|
|
177
197
|
if (!value || value.startsWith("--")) {
|
|
178
|
-
throw new Error(`${argument} requires a
|
|
198
|
+
throw new Error(`${argument} requires a value`);
|
|
179
199
|
}
|
|
180
200
|
if (argument === "--archive") {
|
|
181
201
|
archive = resolve(value);
|
|
182
|
-
} else {
|
|
202
|
+
} else if (argument === "--target") {
|
|
183
203
|
target = resolve(value);
|
|
204
|
+
} else {
|
|
205
|
+
kit = value;
|
|
184
206
|
}
|
|
185
207
|
index += 1;
|
|
186
208
|
continue;
|
|
@@ -190,20 +212,29 @@ function parseArgs(args) {
|
|
|
190
212
|
if (!target) {
|
|
191
213
|
throw new Error("--target is required");
|
|
192
214
|
}
|
|
193
|
-
|
|
215
|
+
if (!(kit in ESP32_KITS)) {
|
|
216
|
+
throw new Error(`unknown Device Kit target selector: ${kit}`);
|
|
217
|
+
}
|
|
218
|
+
return { archive, target, metadata: ESP32_KITS[kit] };
|
|
194
219
|
}
|
|
195
220
|
|
|
196
221
|
async function main() {
|
|
197
222
|
const options = parseArgs(process.argv.slice(2));
|
|
223
|
+
const metadata = options.metadata;
|
|
198
224
|
let archive = options.archive;
|
|
199
225
|
let downloadDirectory = null;
|
|
200
226
|
try {
|
|
201
227
|
if (!archive) {
|
|
228
|
+
if (!metadata.released) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`Device Kit ${metadata.target} metadata is not yet pinned to a release; pass --archive`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
202
233
|
downloadDirectory = mkdtempSync(join(tmpdir(), "tirtc-kit-download-"));
|
|
203
|
-
archive = join(downloadDirectory,
|
|
204
|
-
await download(
|
|
234
|
+
archive = join(downloadDirectory, metadata.archiveName);
|
|
235
|
+
await download(metadata.url, archive);
|
|
205
236
|
}
|
|
206
|
-
installEsp32KitArchive(archive, options.target);
|
|
237
|
+
installEsp32KitArchive(archive, options.target, metadata);
|
|
207
238
|
} finally {
|
|
208
239
|
if (downloadDirectory) {
|
|
209
240
|
rmSync(downloadDirectory, { force: true, recursive: true });
|
package/package.json
CHANGED
|
@@ -27,9 +27,10 @@ past build as proof for a new artifact.
|
|
|
27
27
|
Clone or download it only when the user authorizes that external write.
|
|
28
28
|
Read the exact business documents routed by `workflow.md`.
|
|
29
29
|
4. Run Doctor for the exact target and SDK package. Managed generation currently
|
|
30
|
-
automates ESP32-S3. ESP32-P4
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
automates ESP32-S3. For ESP32-P4 use the published `tirtc-esp32p4-kit`
|
|
31
|
+
(the XiaoTai P4 reference firmware with hosted C6 Wi-Fi and LVGL UI): copy it
|
|
32
|
+
with `create_esp32_project.py --target esp32p4`, build with the RISC-V
|
|
33
|
+
toolchain on ESP-IDF 5.5.4, and never link the S3 archive into a P4 image.
|
|
33
34
|
|
|
34
35
|
## 2. Identify the board and query knowledge
|
|
35
36
|
|
|
@@ -52,6 +53,10 @@ the user's business baseline separately from the hardware reference.
|
|
|
52
53
|
For video orientation, unexpected cropping, or WeChat display-profile changes,
|
|
53
54
|
read [video-orientation.md](references/video-orientation.md) before changing
|
|
54
55
|
pixel transforms or UI angles.
|
|
56
|
+
For device-panel tearing, flicker, stale regions, wrong colors, display rotation
|
|
57
|
+
or touch-coordinate mismatch, read
|
|
58
|
+
[display-pipeline.md](references/display-pipeline.md) before changing the panel,
|
|
59
|
+
LVGL or framebuffer path.
|
|
55
60
|
|
|
56
61
|
## 3. Prove the business flows before board porting
|
|
57
62
|
|
|
@@ -44,6 +44,24 @@ printf '%s\n' "$TIRTC_THING_CONNECT_ROOT"
|
|
|
44
44
|
|
|
45
45
|
已有完整 ThingConnect 工作区仍可通过 `--thing-connect-root` 显式复用,主要用于维护模板或协议时的开发场景。
|
|
46
46
|
|
|
47
|
+
### ESP32-P4 Device Kit
|
|
48
|
+
|
|
49
|
+
P4 不上 managed 安装(需要独立的 RISC-V 工具链)。从 GitHub Release 下载
|
|
50
|
+
`tirtc-esp32p4-kit`(小钛 P4 参考固件 1.4.0:hosted C6 Wi-Fi + LVGL UI +
|
|
51
|
+
摄像头,含 P4 SDK 2.5.0 与构建契约)并校验 SHA-256 后:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python3 <解包目录>/device-sim/scripts/create_esp32_project.py \
|
|
55
|
+
/absolute/path/my-p4-device my_p4_device --target esp32p4
|
|
56
|
+
cd /absolute/path/my-p4-device
|
|
57
|
+
idf.py set-target esp32p4
|
|
58
|
+
idf.py build # 需要 ESP-IDF 5.5.4 与 riscv32-esp-elf(install.sh esp32p4)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
诊断使用 `--target esp32p4`;P4 永远不得链接 S3 的 `libTiRTC.a`。板级差异
|
|
62
|
+
(屏幕、摄像头、Codec、按键)位于参考固件的板级组件内,共享传输组件
|
|
63
|
+
(platform_client/runtime_config/wifi_manager)与 S3 同源。
|
|
64
|
+
|
|
47
65
|
## 常见输入方式
|
|
48
66
|
|
|
49
67
|
只有板卡型号:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.10.1
|
|
@@ -38,6 +38,68 @@
|
|
|
38
38
|
}
|
|
39
39
|
]
|
|
40
40
|
},
|
|
41
|
+
{
|
|
42
|
+
"package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0",
|
|
43
|
+
"status": "knowledge_only",
|
|
44
|
+
"identity": {
|
|
45
|
+
"vendor": "Waveshare",
|
|
46
|
+
"model": "ESP32-P4-WIFI6-Touch-LCD-4.3-C",
|
|
47
|
+
"aliases": ["Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3-C", "微雪 ESP32-P4-WIFI6-Touch-LCD-4.3-C", "ESP32-P4-WIFI6-Touch-LCD-4.3-C (SKU 33875)"],
|
|
48
|
+
"hardware_revision": "V1.0",
|
|
49
|
+
"target": "esp32p4",
|
|
50
|
+
"module": "ESP32-P4NRW32 + ESP32-C6-MINI-1-N4",
|
|
51
|
+
"flash_mb": 32,
|
|
52
|
+
"psram_mb": 32,
|
|
53
|
+
"components": [
|
|
54
|
+
{"kind": "camera", "model": "OV5647"},
|
|
55
|
+
{"kind": "audio_input", "model": "ES7210"},
|
|
56
|
+
{"kind": "audio_output", "model": "ES8311"},
|
|
57
|
+
{"kind": "display", "model": "ST7701"},
|
|
58
|
+
{"kind": "touch", "model": "GT911"},
|
|
59
|
+
{"kind": "network", "model": "ESP32-C6-MINI-1-N4"}
|
|
60
|
+
],
|
|
61
|
+
"probes": [
|
|
62
|
+
{"kind": "camera_pid", "value": "0x5647", "required_for_exact": true},
|
|
63
|
+
{"kind": "touch_id", "value": "911", "required_for_exact": true},
|
|
64
|
+
{"kind": "es7210_i2c_7bit", "value": "0x40", "required_for_exact": true}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"compatibility": {"idf": "5.5.4", "tirtc_sdk": "2.3.0-P4-validation-rebuild"},
|
|
68
|
+
"artifacts": {},
|
|
69
|
+
"knowledge_refs": ["waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md"],
|
|
70
|
+
"lessons": [
|
|
71
|
+
{
|
|
72
|
+
"id": "waveshare_43c_dsi_partial_double_buffer",
|
|
73
|
+
"scope": "component",
|
|
74
|
+
"subject": "display:ST7701 partial double buffering",
|
|
75
|
+
"guidance": "For a RAM-less DSI panel, synchronize presented damage into the recycled back buffer after VSYNC and select a back buffer that is not initially scanned; allocating two buffers alone does not prevent tearing or stale regions.",
|
|
76
|
+
"action": "require",
|
|
77
|
+
"verification": "hil_verified",
|
|
78
|
+
"applies_to": {"kind": "display", "model": "ST7701"},
|
|
79
|
+
"evidence": [{"board_package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0", "source_ref": "waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md#display-failures-and-resolution", "artifact_sha256": "2fb05d6985401b061ef3778f69b2f2b68a3d43cb6e7af145484d136de1ae2562"}]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "waveshare_43c_display_orientation_color_touch",
|
|
83
|
+
"scope": "board",
|
|
84
|
+
"subject": "LVGL display orientation, RGB565 and touch",
|
|
85
|
+
"guidance": "For the verified V1.0 enclosure use LVGL 8.3 sw_rotate with ROT_90, one RGB565 byte swap when LV_COLOR_16_SWAP is enabled, and native GT911 coordinates so LVGL rotates touch with the display.",
|
|
86
|
+
"action": "prefer",
|
|
87
|
+
"verification": "hil_verified",
|
|
88
|
+
"applies_to": {"package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0"},
|
|
89
|
+
"evidence": [{"board_package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0", "source_ref": "waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md#display-failures-and-resolution", "artifact_sha256": "2fb05d6985401b061ef3778f69b2f2b68a3d43cb6e7af145484d136de1ae2562"}]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "waveshare_43c_es7210_address_slots",
|
|
93
|
+
"scope": "board",
|
|
94
|
+
"subject": "ES7210 address, TDM slots and AEC reference",
|
|
95
|
+
"guidance": "Probe 7-bit address 0x40, convert to the selected codec abstraction's 8-bit address form, and map compact DMA [MIC3 reference, MIC2 microphone] into the AEC microphone/reference contract.",
|
|
96
|
+
"action": "require",
|
|
97
|
+
"verification": "corroborated",
|
|
98
|
+
"applies_to": {"package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0"},
|
|
99
|
+
"evidence": [{"board_package_id": "waveshare_esp32p4_wifi6_touch_lcd_43c_v1_0", "source_ref": "waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md#hardware-facts"}]
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
},
|
|
41
103
|
{"package_id":"lckfb_szpi_esp32s3_v1_0_1","status":"knowledge_only","identity":{"vendor":"深圳嘉立创科技集团股份有限公司(立创开发板)","model":"立创·实战派 ESP32-S3 开发板","aliases":["LCKFB SZPI ESP32-S3"],"hardware_revision":"V1.0.1","target":"esp32s3","module":"ESP32-S3 module","flash_mb":16,"psram_mb":8,"components":[{"kind":"camera","model":"GC2145"},{"kind":"aec_reference","model":"ES7210 MIC3 hardware reference"}],"probes":[]},"compatibility":{"idf":"5.5.4","tirtc_sdk":"2.3.0"},"artifacts":{},"lessons":[]},
|
|
42
104
|
{"package_id":"alientek_atk_dnesp32s3_v1","status":"knowledge_only","identity":{"vendor":"正点原子 (ALIENTEK)","model":"ATK-DNESP32S3","aliases":[],"hardware_revision":"V1.0","target":"esp32s3","module":"ATK-MWS3S","flash_mb":16,"psram_mb":8,"components":[{"kind":"camera","model":"OV5640 PID 0x5640"},{"kind":"audio_codec","model":"ES8388"}],"probes":[]},"compatibility":{"idf":"5.5.4","tirtc_sdk":"2.3.0"},"artifacts":{},"lessons":[]}
|
|
43
105
|
]
|
package/skills/tirtc-esp32-builder/knowledge/waveshare-esp32-p4-wifi6-touch-lcd-3.5/knowledge.md
CHANGED
|
@@ -5,6 +5,15 @@ contains source-correlated observations and targeted regressions, not an
|
|
|
5
5
|
installable adapter or complete Hardware IR. A matching sales name does not
|
|
6
6
|
authorize pin reuse. No credentials, raw call logs or user media are retained.
|
|
7
7
|
|
|
8
|
+
## Current kit status (2026-09-22)
|
|
9
|
+
|
|
10
|
+
The builder repository now ships the XiaoTai P4 reference firmware (product
|
|
11
|
+
1.4.0, source `f33b7d2`) in `kit-src/device-sim/device-sim-p4/` and packs the
|
|
12
|
+
TiRTC ESP32-P4 SDK 2.5.0 vendor baseline (libTiRTC.a sha256
|
|
13
|
+
`9b4e35c7…`) into the `tirtc-esp32p4-kit` release. The historical observations
|
|
14
|
+
below (TiRTC 2.3.0, archive `a7a01ffd…`, IDF 5.5.4-dirty) remain historical
|
|
15
|
+
artifacts and do not describe the current kit baseline.
|
|
16
|
+
|
|
8
17
|
## Read only the needed source
|
|
9
18
|
|
|
10
19
|
| Baseline | Pinned source | Locate next |
|
package/skills/tirtc-esp32-builder/knowledge/waveshare-esp32-p4-wifi6-touch-lcd-4.3-c/knowledge.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3-C V1.0
|
|
2
|
+
|
|
3
|
+
Knowledge only. Exact board declared as Waveshare SKU 33875, PCB V1.0, with
|
|
4
|
+
OV5647 installed. The verified product artifact is XiaoTai `43c-port.10`, built
|
|
5
|
+
with ESP-IDF 5.5.4 and the TiRTC P4 2.3.0 validation archive. This package
|
|
6
|
+
records board and component lessons; it does not ship an adapter or authorize
|
|
7
|
+
reuse on another 4.3-inch revision.
|
|
8
|
+
|
|
9
|
+
## Hardware facts
|
|
10
|
+
|
|
11
|
+
- ESP32-P4NRW32 with 32 MiB PSRAM, 32 MiB flash and ESP32-C6-MINI-1-N4 Hosted
|
|
12
|
+
Wi-Fi over SDIO (CLK18/CMD19/D0..3=14..17/RST54).
|
|
13
|
+
- ST7701 MIPI-DSI, two lanes at 500 Mbps, native portrait 480x800, RGB565,
|
|
14
|
+
DPI 30 MHz, DSI PHY LDO_VO3 at 2.5 V, backlight GPIO26 inverted and reset27.
|
|
15
|
+
- GT911 at I2C 0x5D, native portrait coordinates, RST/INT not connected; polling
|
|
16
|
+
worked. OV5647 CSI two-lane PID 0x5647 shares I2C1 SDA7/SCL8.
|
|
17
|
+
- ES8311 DAC at 7-bit 0x18 and ES7210 ADC at **7-bit 0x40**, PA GPIO53. Both
|
|
18
|
+
share I2S1 MCLK13/BCLK12/WS10/DOUT9/DIN11. The codec abstraction used by this
|
|
19
|
+
port accepts the ES7210 control address in 8-bit form, so pass `0x40 << 1`.
|
|
20
|
+
- ES7210 serial order is CH1/CH3/CH2/CH4. The selected compact DMA pair is
|
|
21
|
+
`[MIC3 playback reference, MIC2 onboard microphone]`; swap it to the AEC
|
|
22
|
+
contract `[microphone, reference]`. ES8311 OUTN is physically fed to MIC3.
|
|
23
|
+
- Product key K2 is GPIO23. K1/POWER GPIO21 participates in the PMIC/power path
|
|
24
|
+
and needs separate short/long-press HIL; BOOT is GPIO35.
|
|
25
|
+
|
|
26
|
+
## Display failures and resolution
|
|
27
|
+
|
|
28
|
+
The ST7701 is a RAM-less video panel. Panel `swap_xy` is unavailable, so the
|
|
29
|
+
working product path exposes physical 480x800 to LVGL 8.3, sets `sw_rotate=1`,
|
|
30
|
+
and selects `LV_DISP_ROT_90` for the tested enclosure. GT911 reports native
|
|
31
|
+
coordinates and LVGL applies the same rotation to touch.
|
|
32
|
+
|
|
33
|
+
Observed traps:
|
|
34
|
+
|
|
35
|
+
| Symptom | Cause | Correction |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| Horizontal tear lines | Dirty rectangles copied into the framebuffer being scanned | Compose only in a safe back buffer and request presentation at the DSI frame boundary |
|
|
38
|
+
| Flicker or local UI corruption after double buffering | Alternating buffers contained different generations because only current dirty regions were updated | After flip completion, copy the presented frame's damage into the recycled back buffer before the next LVGL refresh |
|
|
39
|
+
| Startup tear | Code assumed fb0 was the back buffer while DPI initially scanned fb0 | Initialize equal buffers with the backlight off and compose the first frame in fb1 |
|
|
40
|
+
| Portrait/garbled output | LVGL 8.3 90/270 rotation configured without `sw_rotate=1` | Enable software rotation before setting the display rotation |
|
|
41
|
+
| Dark blue rendered yellow/brown | `LV_COLOR_16_SWAP=y` data reached a natural-endian RGB565 DSI input | Byte-swap each RGB565 word once while composing the panel framebuffer |
|
|
42
|
+
| UI did not fill 800x480 | Shared product helpers scaled a 320x240 design grid using fixed predecessor dimensions | Use runtime logical display width/height in position, zoom, video viewport and pool sizing |
|
|
43
|
+
| Touch opposite to UI | Display rotation changed independently of touch mapping | Keep GT911 native coordinates and let LVGL rotate both display and pointer |
|
|
44
|
+
|
|
45
|
+
`lvgl_port` avoid-tearing did not solve this composition because software
|
|
46
|
+
rotation flushed through temporary non-framebuffer-resident chunks. A PPA
|
|
47
|
+
transpose experiment introduced separate direction/color uncertainty. These
|
|
48
|
+
failed experiments are diagnostic history, not preferred implementations.
|
|
49
|
+
|
|
50
|
+
## Evidence boundary
|
|
51
|
+
|
|
52
|
+
User HIL on 2026-09-23 reported UI and video normal with `43c-port.10` after the
|
|
53
|
+
ROT_90 and damage carry-forward correction. This establishes the board display
|
|
54
|
+
path for that artifact, not AEC double-talk, weak-network recovery, PMIC power
|
|
55
|
+
semantics or 24-hour stability.
|
|
56
|
+
|
|
57
|
+
- Application BIN SHA256:
|
|
58
|
+
`2fb05d6985401b061ef3778f69b2f2b68a3d43cb6e7af145484d136de1ae2562`
|
|
59
|
+
- ELF SHA256:
|
|
60
|
+
`38b1ce6f0a5455fbd658b1c5e5275b89a07f2d5a7561652cfac04a5b3e6368de`
|
|
61
|
+
- Local source evidence at capture time:
|
|
62
|
+
`waveshare-esp32p4-4.3c-xiaotai/`, its Hardware IR, display driver, audio
|
|
63
|
+
contract and `docs/ESP32-P4-WIFI6-Touch-LCD-4.3-C-移植诊断手册.md`.
|
|
64
|
+
|
|
65
|
+
Apply the general display invariants from
|
|
66
|
+
[display-pipeline.md](../../references/display-pipeline.md) to other panels.
|
|
67
|
+
Treat the GPIO, rotation, codec address, TDM slots and AEC wiring above as exact
|
|
68
|
+
board facts only.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Device display pipeline
|
|
2
|
+
|
|
3
|
+
Use this reference for tearing, intermittent flicker, stale UI regions, wrong
|
|
4
|
+
RGB colors, panel orientation, touch-coordinate mismatch, or UI layouts that do
|
|
5
|
+
not fill a new display. Keep panel scan geometry, LVGL logical geometry, pixel
|
|
6
|
+
storage order, framebuffer ownership and touch mapping as separate facts.
|
|
7
|
+
|
|
8
|
+
## RAM-less video panels
|
|
9
|
+
|
|
10
|
+
ST7701 and similar MIPI-DSI video panels continuously scan a framebuffer and
|
|
11
|
+
have no panel RAM that makes a partial write atomic. Identify the buffer being
|
|
12
|
+
scanned before writing. A successful `draw_bitmap` call or two allocated frame
|
|
13
|
+
buffers does not by itself prevent tearing.
|
|
14
|
+
|
|
15
|
+
For a partial-rendering double-buffer path, prove all of these invariants:
|
|
16
|
+
|
|
17
|
+
- LVGL writes only the back buffer; initialization must not assume framebuffer
|
|
18
|
+
zero is free when the controller starts by scanning framebuffer zero.
|
|
19
|
+
- Presentation changes the scan buffer at a frame boundary and the old front
|
|
20
|
+
buffer is recycled only after the corresponding VSYNC/refresh completion.
|
|
21
|
+
- Before the recycled buffer receives the next dirty regions, carry forward
|
|
22
|
+
every region changed in the presented frame. Alternating two buffers while
|
|
23
|
+
updating only the latest dirty rectangles produces different UI generations,
|
|
24
|
+
seen as intermittent flicker, stale widgets or local corruption.
|
|
25
|
+
- A semaphore token must correspond to a refresh after the requested flip.
|
|
26
|
+
Drain earlier periodic VSYNC tokens around the request or use a monotonic
|
|
27
|
+
generation/counter; an already-full binary semaphore is not flip evidence.
|
|
28
|
+
|
|
29
|
+
Valid implementations include damage carry-forward after VSYNC, a canonical
|
|
30
|
+
shadow frame copied into a safe back buffer, or a genuinely full-frame path.
|
|
31
|
+
Choose using measured memory bandwidth and audio/video deadlines. LVGL 8.3
|
|
32
|
+
software rotation cannot be combined with its `direct_mode` or `full_refresh`
|
|
33
|
+
shortcut; inspect the selected LVGL version before choosing a strategy.
|
|
34
|
+
|
|
35
|
+
## Rotation, color and touch
|
|
36
|
+
|
|
37
|
+
- A RAM-less panel's fixed native raster can prevent panel-level `swap_xy`.
|
|
38
|
+
With LVGL 8.3 partial buffers, set `sw_rotate=1` before selecting 90/270
|
|
39
|
+
software rotation. `lv_disp_drv_update()` alone does not enable it.
|
|
40
|
+
- Treat 90 versus 270 as a physical installation fact. Verify with asymmetric
|
|
41
|
+
corner labels on the exact enclosure; a vendor portrait drawing does not
|
|
42
|
+
decide the product's landscape direction.
|
|
43
|
+
- Let one layer own display and touch rotation. When LVGL rotates the display,
|
|
44
|
+
feed the touch driver native panel coordinates and verify all four corners.
|
|
45
|
+
A second manual transform commonly creates a 180-degree mismatch.
|
|
46
|
+
- Derive RGB565 byte order across assets, `LV_COLOR_16_SWAP`, the rotation
|
|
47
|
+
buffer and the panel input. A dark-blue word rendered yellow/brown is a useful
|
|
48
|
+
byte-swap signature. Apply one evidenced swap at the framebuffer boundary.
|
|
49
|
+
|
|
50
|
+
## Layout and video checks
|
|
51
|
+
|
|
52
|
+
Find design-grid scaling that still uses a predecessor board's fixed width or
|
|
53
|
+
height. Scale against the runtime logical display size, including image zoom,
|
|
54
|
+
canvas placement, call-video viewport, decoder pools and presentation depth.
|
|
55
|
+
Keep camera/encoded-pixel orientation separate from device-display rotation;
|
|
56
|
+
read [video-orientation.md](video-orientation.md) for the remote video path.
|
|
57
|
+
|
|
58
|
+
Hardware acceptance requires static and animated UI, rapid page changes,
|
|
59
|
+
subtitles or timers, four-corner touch, solid RGB test colors and sustained
|
|
60
|
+
video. Bind the observation to the exact application BIN hash. Compiler success
|
|
61
|
+
does not verify VSYNC ownership, physical rotation or color order.
|
|
@@ -59,10 +59,19 @@ protocols and non-ESP32 simulators. Cloning is an external write and requires
|
|
|
59
59
|
user authorization. Do not track a moving default branch as build evidence.
|
|
60
60
|
|
|
61
61
|
ESP32-P4 uses a separate `espressif_esp32p4` SDK archive and RISC-V toolchain.
|
|
62
|
-
The managed setup does not install that archive
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
The managed setup does not install that archive; P4 projects come from the
|
|
63
|
+
published `tirtc-esp32p4-kit` (the XiaoTai P4 reference firmware, released
|
|
64
|
+
alongside the S3 Kit). The P4 flow is:
|
|
65
|
+
|
|
66
|
+
1. Download the `tirtc-esp32p4-kit` GitHub release, verify its SHA-256, and
|
|
67
|
+
extract it (or point `--thing-connect-root` at this repository's `kit-src`).
|
|
68
|
+
2. `python3 device-sim/scripts/create_esp32_project.py <out> <name> --target esp32p4`
|
|
69
|
+
(copies the full reference firmware and materializes the shared transport
|
|
70
|
+
components and the P4 SDK under `third_party/tirtc`).
|
|
71
|
+
3. `idf.py set-target esp32p4`, build with the RISC-V toolchain
|
|
72
|
+
(`install.sh esp32p4`; the pinned SDK requires ESP-IDF 5.5.4 exactly).
|
|
73
|
+
4. Run Doctor with `--target esp32p4` and never accept the packaged S3 archive
|
|
74
|
+
as a compatible fallback.
|
|
66
75
|
|
|
67
76
|
SDK resolution is independent after generation: an explicit `--sdk-dir` wins, followed by `<project>/third_party/tirtc`, then the SDK packaged in the resolved Device Kit or legacy workspace. The generated project remains diagnosable after it is moved away from the Kit.
|
|
68
77
|
|
|
@@ -22,10 +22,29 @@ CONTRACT_KEYS = {
|
|
|
22
22
|
"CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS",
|
|
23
23
|
"CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS",
|
|
24
24
|
}
|
|
25
|
+
# The P4 archive additionally pins the socket budget (absent from the S3 contract).
|
|
26
|
+
CONTRACT_KEYS_P4 = CONTRACT_KEYS | {"CONFIG_LWIP_MAX_SOCKETS"}
|
|
25
27
|
THING_CONNECT_ENV = "TIRTC_THING_CONNECT_ROOT"
|
|
26
28
|
GENERATOR_RELATIVE_PATH = Path("device-sim/scripts/create_esp32_project.py")
|
|
27
|
-
SDK_RELATIVE_ROOT = Path("device-sim/sdk/espressif-esp32s3")
|
|
28
29
|
DEVICE_KIT_MANIFEST = "manifest.json"
|
|
30
|
+
SDK_FALLBACK_VERSIONS = {
|
|
31
|
+
"esp32s3": ("2.5.0", "2.3.0"),
|
|
32
|
+
"esp32p4": ("2.5.0",),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def sdk_relative_root(platform: str | None, target: str) -> Path:
|
|
37
|
+
"""SDK root inside the Kit; the manifest platform wins, the target is the
|
|
38
|
+
fallback. A P4 target never resolves the ESP32-S3 SDK archive."""
|
|
39
|
+
if platform == "espressif-esp32p4" or target == "esp32p4":
|
|
40
|
+
return Path("device-sim/sdk/espressif-esp32p4")
|
|
41
|
+
return Path("device-sim/sdk/espressif-esp32s3")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def contract_keys(target: str) -> set[str]:
|
|
45
|
+
if target == "esp32p4":
|
|
46
|
+
return CONTRACT_KEYS_P4
|
|
47
|
+
return CONTRACT_KEYS
|
|
29
48
|
|
|
30
49
|
|
|
31
50
|
def check(name: str, status: str, detail: str, required: bool = True) -> dict[str, Any]:
|
|
@@ -115,10 +134,10 @@ def parse_kconfig(path: Path) -> dict[str, str]:
|
|
|
115
134
|
|
|
116
135
|
|
|
117
136
|
def compare_contract(
|
|
118
|
-
contract: dict[str, str], config: dict[str, str]
|
|
137
|
+
contract: dict[str, str], config: dict[str, str], keys: set[str] | None = None
|
|
119
138
|
) -> list[str]:
|
|
120
139
|
mismatches: list[str] = []
|
|
121
|
-
for key in sorted(CONTRACT_KEYS):
|
|
140
|
+
for key in sorted(keys if keys is not None else CONTRACT_KEYS):
|
|
122
141
|
expected = contract.get(key)
|
|
123
142
|
actual = config.get(key)
|
|
124
143
|
if expected is None:
|
|
@@ -238,6 +257,7 @@ def resolve_sdk_dir(
|
|
|
238
257
|
explicit: Path | None,
|
|
239
258
|
project: Path | None,
|
|
240
259
|
thing_connect_root: Path | None,
|
|
260
|
+
target: str = "esp32s3",
|
|
241
261
|
) -> tuple[Path | None, str]:
|
|
242
262
|
if explicit is not None:
|
|
243
263
|
return explicit.expanduser().resolve(), "explicit --sdk-dir"
|
|
@@ -251,15 +271,22 @@ def resolve_sdk_dir(
|
|
|
251
271
|
try:
|
|
252
272
|
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
253
273
|
version = manifest.get("tirtc_sdk_version")
|
|
274
|
+
platform = manifest.get("platform")
|
|
254
275
|
if isinstance(version, str) and re.fullmatch(r"\d+\.\d+\.\d+", version):
|
|
255
|
-
return
|
|
276
|
+
return (
|
|
277
|
+
thing_connect_root / sdk_relative_root(platform, target) / version,
|
|
278
|
+
"Device Kit",
|
|
279
|
+
)
|
|
256
280
|
except (OSError, json.JSONDecodeError):
|
|
257
281
|
pass
|
|
258
|
-
for version in (
|
|
259
|
-
candidate = thing_connect_root /
|
|
282
|
+
for version in SDK_FALLBACK_VERSIONS.get(target, SDK_FALLBACK_VERSIONS["esp32s3"]):
|
|
283
|
+
candidate = thing_connect_root / sdk_relative_root(None, target) / version
|
|
260
284
|
if candidate.is_dir():
|
|
261
285
|
return candidate, "ESP32 source workspace"
|
|
262
|
-
return
|
|
286
|
+
return (
|
|
287
|
+
thing_connect_root / sdk_relative_root(None, target) / "2.5.0",
|
|
288
|
+
"ESP32 source workspace",
|
|
289
|
+
)
|
|
263
290
|
return None, "not found"
|
|
264
291
|
|
|
265
292
|
|
|
@@ -373,6 +400,7 @@ def diagnose(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
373
400
|
args.sdk_dir,
|
|
374
401
|
args.project,
|
|
375
402
|
thing_connect_root,
|
|
403
|
+
args.target,
|
|
376
404
|
)
|
|
377
405
|
if sdk_dir is None:
|
|
378
406
|
sdk_files: list[Path] = []
|
|
@@ -427,7 +455,9 @@ def diagnose(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
427
455
|
checks.append(check("TiRTC build contract", "FAIL", detail))
|
|
428
456
|
else:
|
|
429
457
|
mismatches = compare_contract(
|
|
430
|
-
parse_env_file(contract_path),
|
|
458
|
+
parse_env_file(contract_path),
|
|
459
|
+
parse_kconfig(config_path),
|
|
460
|
+
contract_keys(args.target),
|
|
431
461
|
)
|
|
432
462
|
checks.append(
|
|
433
463
|
check(
|