บทเรียน 5.2 — หน้าจอลงทะเบียนบนอุปกรณ์

ส่งงานที่ใช้เวลาหลายวินาทีให้หน้าจอที่คอยถามสถานะ และปิดหน้าจอเก่าก่อนเปิดใหม่เสมอ

โมดูล 5 — การลงทะเบียนอุปกรณ์อย่างปลอดภัย

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เป้าหมาย

เมื่อจบบทเรียนนี้ คุณจะ

  1. อธิบายว่าทำไมหน้าจอลงทะเบียนต้องถามสถานะเป็นระยะแทนการรอผลของชิป
  2. เรียงลำดับการปิดหน้าจอเก่าและเปิดหน้าจอลงทะเบียนตามตัวอย่างของ SDK ได้ถูกต้อง
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ก่อนเริ่ม

  • เรียนมาก่อน: บทเรียน 5.1 และแนวคิดข้อ 3 ของ บทเรียน 2.2
  • บอร์ด: แม่แบบ build ด้วย ENABLE_PAGE_EXAMPLES=1 — แล็บนี้ ถอดข้อมูลรับรองของแพลตฟอร์มออกจากไฟล์ตั้งค่าก่อน เพื่อให้การลงทะเบียนหยุดตั้งแต่ขั้นเชื่อมต่อ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ดูของจริงก่อน

ถ้ารอผลของชิปแบบ inline จอจะค้าง และ ui_busy_modal_service() ก็วาดหน้าต่างอธิบายไม่ได้ — จอจึง "dead AND silent"

อีกเรื่อง: ถ้าหน้าต่างของรอบก่อนยังเปิดอยู่ การเปิดอีกหน้าต่างจะถูกปฏิเสธแบบเงียบ ๆ เพราะ shell_open() คืนทันทีเมื่อมีหน้าต่างอยู่แล้ว

ทายก่อน สำหรับคนที่ถือบอร์ด "จอค้างและเงียบ" กับ "แตะแล้วไม่มีอะไรเกิดขึ้น" ต่างกันไหม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด (1) — ทำไมต้องถามสถานะ ไม่ใช่รอ

งานเบื้องหลังหน้าจอ Enrol ใช้เวลานาน: ขอประตูเข้าชิปรอได้ถึง 10 วินาที, สร้างคู่กุญแจ+ลงนาม CSR เป็นธุรกรรมยาว, รอแพลตฟอร์มได้ถึง 60 วินาที

 CM55 (จอ)                              CM33_NS
 ปุ่ม Enrol → hsm_enrol_open()
   ส่ง IPC_CMD_HSM_PROVISION ──▶ handle_hsm_provision()
   ◀── คืนทันที ──                ถ้ามีงานวิ่งอยู่ ปฏิเสธ REJECTED_BUSY
   lv_timer ถาม op=POLL ──▶      prov_task ตรวจทุก 50 ms
   ◀── state, step, ข้อความ ──   prov_say(state, step, "ข้อความสำหรับคนอ่าน")

จอไม่ต้องรู้เลยว่าชิปทำอะไรอยู่ — แค่ถามว่า "ตอนนี้ถึงไหน" แล้ววาด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด (2) — ปิดของเก่าก่อนเสมอ

hsm_provision_ui_teardown() ปิดหน้าต่างที่ค้างอยู่และ ยกเลิก timer ที่ถามสถานะ — เรียกซ้ำได้และปลอดภัยแม้ไม่มีอะไรเปิดอยู่ กันปัญหาสองแบบ

  • แตะแล้วเงียบ ถ้าไม่ปิดของเก่า การเปิดใหม่ถูกปฏิเสธเงียบ ๆ
  • timer ค้างเขียนใส่หน้าจอที่ถูกสร้างใหม่ timer ของรอบก่อนยังยิงอยู่ อ้างวัตถุ LVGL ที่ถูกลบไปแล้ว

หน้าของ HSM เรียก hsm_provision_ui_teardown() เป็น คำสั่งสุดท้าย ของ callback ตอนหน้าถูกทำลาย (หลังลบ timer ของหน้าเองแล้ว)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด (3) — หน้าจอที่พูดความจริง

  • หน้า Protect แสดงชุดการเปลี่ยนแปลงที่จะเกิด ก่อน ทำ และไม่เขียนอะไรจนกว่าจะกดยืนยัน
  • หน้า Enrol ที่เจอช่องซึ่งถูกล็อก บอกว่า "This slot takes signed manifests only ... Nothing was changed." ก่อนสร้างกุญแจ
  • ผลตัดสินสุดท้ายแยกสามกรณี: "can prove it holds the key" / "does not belong to this chip's key" / "the pair check could not run" — ต่างกันเพราะต้องการการตอบสนองต่างกัน (เหมือนหลักของ 02_model_signature_hook.c ที่ไม่รวม "ไม่มีลายเซ็น" กับ "ตรวจไม่ได้" เป็นค่าเดียว)
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — ปิดของเก่า → เปิดของใหม่ → คืนว่า "เริ่มแล้ว"

/* Idempotent, and first. If an earlier run's overlay is still up, opening
 * another would be refused silently -- shell_open() returns when one
 * already exists -- and the tap would look like it did nothing. */
hsm_provision_ui_teardown();

if (s_open_protect_next) {
    s_open_protect_next = false;
    hsm_protect_open();
} else {
    s_open_protect_next = true;
    hsm_enrol_open();
}
/* The screen is up and its own poll timer owns the work from here.
 * That is asynchronous progress, not a completed job. */
return SDK_EX_STARTED;

ค่า SDK_EX_STARTED บอกตรง ๆ ว่างานยังวิ่งอยู่ เจ้าของงานตั้งแต่นี้คือ timer ของหน้าจอ ไม่ใช่ฟังก์ชันนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ฝึกเติม / แล็บ

ฝึกเติม เติมช่องว่างของปุ่ม "ลงทะเบียน": (1) hsm_provision_ui_teardown() ก่อนเปิดอะไรทุกครั้ง (2) hsm_enrol_open() เปิดหน้าต่าง (3) lv_timer_delete(s_clock_timer) ลบ timer ของหน้าเอง (4) hsm_provision_ui_teardown() อยู่ท้ายสุดของ destroy()

แล็บ build+flash 01_hsm_screens (ต้องถอด credential ออกจากไฟล์ตั้งค่าก่อน) — จดข้อความตามลำดับพร้อมเวลา ลองแตะ Back ระหว่างรอ จดว่าจอตอบสนองช่วงไหน (มองหา touch-hold reason) — กด Back แล้ว Run ซ้ำดูหน้า Protect ก่อนยืนยัน แล้วกด Back โดยไม่ยืนยัน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เช็กความเข้าใจ

  1. ถ้าหน้าจอ Enrol รอผลของชิปแบบ inline ใน task ของ LVGL ผลที่คนถือบอร์ดเห็นคืออะไร

    • ก) จอแสดงความคืบหน้าทีละขั้นตามปกติ · ข) จอค้างทั้งจอ และหน้าต่างที่อธิบายว่าทำไมค้างก็วาดไม่ได้ จอจึงทั้งตายและเงียบ · ค) ชิปทำงานเร็วขึ้น · ง) การลงทะเบียนถูกยกเลิกอัตโนมัติ
  2. ลำดับใดถูกต้องเมื่อผู้ใช้แตะปุ่มเปิดหน้าจอลงทะเบียน

    • ก) hsm_enrol_open() แล้วค่อย hsm_provision_ui_teardown() · ข) hsm_provision_ui_teardown() แล้ว hsm_enrol_open() แล้วคืนค่าว่าเริ่มแล้ว · ค) hsm_enrol_open() แล้วรอจนเสร็จ · ง) ไม่ต้องปิดของเก่า
  3. ทำไม hsm_provision_ui_teardown() ต้องเป็นคำสั่งสุดท้ายใน callback ที่ทำลายหน้า

    • ก) เพื่อให้ timer ที่ถามสถานะถูกยกเลิก ไม่ยิงใส่วัตถุ LVGL ที่ถูกคืนหน่วยความจำแล้ว · ข) เพราะมันช้าที่สุด · ค) เพื่อให้การลงทะเบียนเริ่มใหม่ · ง) เพราะมันล้าง correlation id
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ไปต่อ

ตอนนี้เรามีครบทุกชิ้นแล้ว threat model ช่องทาง mTLS ห่วงโซ่การบูต Protected Update การลงทะเบียน และหน้าจอที่พูดความจริง บทสุดท้ายรวมทั้งหมดเป็นอุปกรณ์หนึ่งชิ้น พร้อมหลักฐานว่ามันทำงานจริง

บทเรียนถัดไป: บทเรียน 5.3: งานปลายทาง อุปกรณ์ที่ปลอดภัยหนึ่งชิ้น

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แหล่งที่มาและเครดิต

"Secure IoT กับ OPTIGA™ Trust M" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย
(Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program
สัญญาอนุญาต CC BY-NC 4.0

โค้ดที่ยกในสไลด์นี้จาก TESAIoT PSE84 Dev Kit SDK (Apache-2.0) — ลิงก์และสัญญาอนุญาตอยู่ใน README ของบทเรียน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0