|
SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (MTB & µPython)
|
กลไกของ handler ฝั่ง CM55 ใช้ได้กับทั้งสอง variant ส่วนฝั่ง ที่ขับ ในบทนี้ — โมดูล MicroPython ui.* และ ui._diag() — เป็น mtb-mpy เท่านั้น บน mtb-only มี handler ตัวเดียวกันอยู่ แต่ไม่มีสิ่งใดในเฟิร์มแวร์ที่ส่งมอบจริงส่งคำสั่งไปหามัน
เข้าใจว่าฟังก์ชัน ui_widget_mgr_* ทั้ง 25 ตัวไม่ใช่ C API สำหรับโค้ด page ที่เขียนเอง ผู้เรียกเพียงรายเดียวคือ switch ของคำสั่ง IPC ใน process_ui_command() ส่วนผู้ใช้ที่แท้จริงคือสคริปต์ MicroPython ที่ข้ามมาทาง IPC เมื่อจบบทนี้จะไล่รอยการเรียก ui.Label(...) จาก REPL ไปจนถึงอ็อบเจ็กต์ LVGL ได้ และรู้ว่า symbol 7 ตัวใดที่ต้อง นิยามเอง แทนที่จะเรียกใช้
ข้อกำหนดการเรียกใช้ในบรรทัดเดียว — ipc_ui.h:7-8: ฝั่ง ISR ทำเพียงใส่คิว ส่วนงาน LVGL เกิดขึ้นบน timer 50 ms ใน GFX-task context ข้อกำหนดในไฟล์ header ui_widget_mgr.h:6 ระบุว่า "Creates, modifies, deletes LVGL widgets in GFX task context"
การ init ipc_ui_init(NULL) เป็นการเรียกลำดับสุดท้ายของการ bring-up ฝั่ง CM55 โดยมี display_ok เป็น gate (ด่านกั้น) (tesaiot_display.c:470-479) และตัวมันเรียก ui_widget_mgr_init() เองอยู่แล้ว (ipc_ui.c:890) — ห้ามเรียกฟังก์ชันนั้นเอง container ทั้งสองรับค่า NULL ได้ (deferred binding — ผูกค่าจริงในภายหลัง):
ผูก container ตอน create และตั้งเป็น NULL ตอน destroy page Playground คือตัวอย่างที่มีอยู่จริงในของที่ส่งมอบ:
การกระจายคำสั่ง process_ui_command() (ipc_ui.c:393 ระบายคิวจาก :875) เป็น switch ครอบ IPC_CMD_UI_* และ 22 ใน 25 ฟังก์ชันพื้นฐานกระจายอยู่ภายในนั้น ตัวอย่างที่เป็นตัวแทน:
การระบาย event — ฝั่งผู้ผลิตคือ ui_widget_mgr_event_push (ui_widget_mgr.c:333 และ :406 ซึ่งอยู่หลัง event mask ของแต่ละ widget) ฝั่งผู้อ่านคือ case POLL_EVENTS:
มี 2 ฟังก์ชันที่ไม่ได้กระจายจาก switch นี้ ได้แก่ ui_widget_mgr_init (อยู่ภายใน ipc_ui_init) และ ui_widget_mgr_set_parent (ผู้เรียกรายเดียวคือ ipc_ui_set_container(), ipc_ui.c:918-921) และอีกหนึ่งตัวคือ ui_widget_mgr_count ซึ่งไม่มีผู้เรียกที่ใดเลย ตัวอย่างของมันจึงเป็นตัวอย่างที่เขียนขึ้นเอง
parent เป็น NULL ได้ call site ทั้ง 5 จุดตรวจ NULL ทุกจุด — ค่าเป็น NULL ในช่วงระหว่าง set_container(NULL) ตอน destroy กับการผูกของ page ถัดไป:
Home → Playground
สิ่งที่ควรสังเกต พาเนลคอนโซล ชั้นคอนโซลกับชั้น widget ใช้พร้อมกันไม่ได้ ตัวสลับเป็นการสลับแบบ ไม่รู้สถานะ จึงมี ipc_lcd_is_panel_visible() เป็นตัวกันเสมอ:
สิ่งที่ควรสังเกต container ของ widget เลิกซ่อนตัวเมื่อเกิด POLL_EVENTS ครั้งแรก และ label ปรากฏขึ้น text() ปรับค่าให้ภายในหนึ่ง tick 50 ms (SET_TEXT ยังปลุกโหมดเร็วด้วย, ipc_ui.c:463) สตริงของ label ถูกตัดที่ 95 ไบต์ในตัว constructor: UI_CREATE_TEXT_MAX มีค่า 96 (ipc_ui_protocol.h:658) และ constructor ตัดเหลือ UI_CREATE_TEXT_MAX - 1 (modui.c:1223)
สิ่งที่ควรสังเกต เวิร์ด 10 ตัวจาก ipc_ui_platform_diag() โดย flush_start_count เพิ่มขึ้นระหว่างการเรียก 2 ครั้ง บน mtb-only ให้เรียก ipc_ui_platform_diag(out, 10) จากโค้ด CM55 ที่เขียนเองแทน
การเริ่มใหม่ของ Playground รื้อ widget ทิ้ง ก่อนคำสั่ง restart ทาง IPC เพื่อไม่ให้ CM33_NS ดันข้อมูลเข้าตารางที่ล้างค้างอยู่ครึ่งเดียว:
สิ่งที่ควรสังเกต widget หายไป แล้ว widget ของสคริปต์ปรากฏขึ้นใหม่ คำสั่ง CLEAR_ALL ยังรีเซ็ตการนำทางอัตโนมัติของ LCD ด้วย (ipc_ui.c:556)
ตรงกับรายการใน dist/ipc_core/overridable.txt พอดี ได้แก่ cm55_controls_snapshot (เขียนทับในเทมเพลตที่ cm55_sensor_poll.c:342), game_sprite_create / game_sprite_set (game_sprite_engine.c:16/:25), game_sprite_lookup (game_sprite_registry.c:52), ipc_ui_ext_dispatch (ipc_ui_ext_chain.c:41 ทำงานใน GFX context และอาจแตะจอแสดงผล, ipc_ui.h:40-41), ipc_ui_ext_clear_all (เป็น W ใน archive), ipc_ui_platform_diag (strong definition เก็บไว้ใน archive ที่ tesaiot_display.c:593-609) หน้าคู่มืออ้างอิงที่บอกให้ "call this" กับตัวใดตัวหนึ่งในนี้คือหน้าที่ผิด
| mtb-mpy | mtb-only | |
|---|---|---|
| ฝั่งที่ขับ | โมดูล ui.* ผ่าน IPC | ไม่มีผู้ส่งในของที่ส่งมอบ แต่มี handler อยู่ |
| การพิสูจน์เฟรม | ui._diag() | ipc_ui_platform_diag() ฝั่ง C |
| กลไกของ page | เหมือนกัน | เหมือนกัน |