บทเรียน 2.5 — สแกน Wi-Fi และแสดงรายการเครือข่าย

สแกน WiFi ผ่าน WHD/cy_wcm แล้วแสดงผลเป็น list พร้อม RSSI + security type — เพิ่มหน้า WiFi Scan เข้าไปใน shell ของ EP04

TESAIoT Dev Kit · PSoC Edge E84 · ภาษา C · ModusToolbox

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

เป้าหมาย

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

  1. สแกน Wi-Fi ผ่าน WHD/cy_wcm แล้วแสดงรายการพร้อม RSSI และชนิด security
  2. แยก scan service ออกจากหน้า UI และส่งผลสแกนเข้าหน้าอย่างปลอดภัย
  3. อ่านค่า RSSI และบอกได้ว่าเครือข่ายใดสัญญาณดีพอจะเชื่อมต่อ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ก่อนเริ่ม

  • ผ่านบทเรียนก่อนหน้ามาแล้ว: fw-stack.m02.l04
  • บอร์ด: TESAIoT Dev Kit
  • แพลตฟอร์ม: PSoC Edge E84 · ModusToolbox
  • เวลาโดยประมาณ: เนื้อหา 15 + ฝึกตาม 25 + แล็บ 20 + เช็กความเข้าใจ 5 = 65 นาที
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

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

หน้าจอของ EP05 — WiFi List บน TESAIoT Dev Kit

ก่อนอ่านโค้ด ให้ทายว่าหน้าจอนี้มี object อะไรบ้าง และอะไรเปลี่ยนเมื่อผู้ใช้แตะหรือเมื่อค่าเซนเซอร์เปลี่ยน

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

แนวคิด — สแกน Wi-Fi ผ่าน stack สามชั้น

whd (คุย SDIO กับโมดูลวิทยุ) → cy_wcm (Connection Manager) → callback ของแอป

episode ห่อทั้งสามชั้นไว้ใน service layer — UI เรียกแค่ wifi_scan_service_start() / _process() ไม่ต้องรู้จัก cy_wcm เลย

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

แนวคิด — pre-init: warm up ตั้งแต่ boot

example_main() เรียก wifi_scan_service_preinit() ก่อนสร้าง UI — ทำ SDIO bring-up + cy_wcm_init() ตั้งแต่ boot

ถ้าเรียกตอนกดปุ่มครั้งแรกแทน ผู้ใช้จะเห็น UI ค้าง 1-3 วินาที — pre-init ทำให้ครั้งแรกเร็วเท่าครั้งถัดไป

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

แนวคิด — callback ของ WHD ไม่แตะ LVGL เลย

README ต้นทางบอกว่าใช้ lv_async_call() แต่โค้ดจริงใช้ critical section + poll timer

wifi_scan_callback() (รันบน WCM task) แค่เขียนข้อมูล+ธงใน taskENTER_CRITICAL()/EXIT ไม่เรียก LVGL API เลย

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

แนวคิด — ฝั่ง LVGL poll ธงแทนถูกปลุก

lv_timer_create(ui_wifi_poll_timer_cb, UI_WIFI_POLL_MS=150, NULL) — ทุก 150 ms เรียก wifi_scan_service_process()

อ่าน+เคลียร์ scan_done_pending ใน critical section เดียวกัน ถ้าเสร็จค่อย render ใหม่

ข้อมูลข้าม thread ด้วย critical section, แจ้งเตือนข้าม thread ด้วยการ poll — คนละกลไกกับ lv_async_call() แต่ปลอดภัยเท่ากัน

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

แนวคิด — กันสแกนซ้อนสองชั้น + RSSI

  • wifi_scan_service_start() เช็ค service->scanning ก่อนเสมอ + ปุ่ม UI ก็ LV_STATE_DISABLED ด้วย
  • ผลเรียงจากแรงไปอ่อน (wifi_scan_sort_by_rssi_desc)
  • SSID ที่พิมพ์ไม่ได้ (hidden) แสดงเป็น <hidden>
  • struct wifi_scan_ap_t มีแค่ ssid, rssi, security — ไม่มี bssid
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — ทักษะที่ฝึกในบทเรียนนี้

บทเรียนนี้พัฒนาทักษะต่อไปนี้ (ตามระดับ 1–5 ของหลักสูตร)

  • proto.wifi (ระดับ 2)
  • gui.hmi (ระดับ 2)
  • rtos.basics (ระดับ 1)
  • iot.fundamentals (ระดับ 1)
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — callback ไม่แตะ LVGL

โค้ดจาก tesaiot/developer-hub (Apache-2.0) · commit 9a8e3ed · wifi_scan_service.c

if(status == CY_WCM_SCAN_COMPLETE) {
    taskENTER_CRITICAL();
    wifi_scan_sort_by_rssi_desc(service);
    service->scan_done_pending = true;
    taskEXIT_CRITICAL();
}
bool wifi_scan_service_process(wifi_scan_service_t *service)
{
    taskENTER_CRITICAL();
    bool done = service->scan_done_pending;
    service->scan_done_pending = false;
    taskEXIT_CRITICAL();

    if(done) { service->scanning = false; return true; }
    return false;
}
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — poll timer ฝั่ง LVGL

ui_wifi_list_page.c

static void ui_wifi_poll_timer_cb(lv_timer_t *timer)
{
    uint16_t count = 0U;
    LV_UNUSED(timer);

    if(wifi_scan_service_process(&s_ctx.service)) {
        lv_obj_clear_state(s_ctx.scan_btn, LV_STATE_DISABLED);
        (void)wifi_scan_service_get_list(&s_ctx.service, &count);
        ui_wifi_render_ap_list();
    }
}
/* ... */
s_ctx.poll_timer = lv_timer_create(ui_wifi_poll_timer_cb,
                                   UI_WIFI_POLL_MS, NULL);
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

จุดที่มักพลาด

  • คิดว่าใช้ lv_async_call() ตาม README ต้นทาง — โค้ดจริงใช้ critical section + poll timer
  • เรียก LVGL widget API จาก callback ของ cy_wcm/whd ตรง ๆ → ชนกับ lv_timer_handler()
  • ลืมกันสแกนซ้อนที่ตัว service ไม่ใช่แค่ปุ่ม
  • struct จริงไม่มี bssid ต่างจากที่ README ต้นทางพูดถึง
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — build และ flash

# ในโฟลเดอร์ master template (ดูบทเรียน 1.1)
# 1) ลบไฟล์ของ episode เก่าใน proj_cm55/apps/
# 2) คัดลอกไฟล์ทั้งหมดของ episode นี้ลงใน proj_cm55/apps/
make build
make program     # flash ผ่าน KitProg3

หรือเปิด ตัวอย่างนี้บน Developer Hub แล้ว flash เฟิร์มแวร์สำเร็จรูป

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

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

  1. ทาย ก่อนแก้: เลือกค่าหนึ่งค่าที่ README ของตัวอย่างอธิบายไว้ในส่วน How แล้วเขียนว่าจะเห็นอะไรเปลี่ยนบนจอหรือใน log
  2. แก้และรัน build + flash แล้วเทียบกับที่ทายไว้ ถ้าไม่ตรง ให้หาว่าเข้าใจส่วนไหนผิด
  3. ทำเพิ่ม ต่อยอดหนึ่งอย่างที่ตัวอย่างยังไม่มี แล้วเก็บภาพหรือวิดีโอไว้ใน portfolio
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

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

  • RSSI -45 dBm กับ -85 dBm อันไหนดีกว่า
  • ทำไมไม่ควรสแกน Wi-Fi ใน callback ของปุ่มโดยตรง
  • ชนิด security ในรายการบอกอะไรกับผู้ใช้

คำตอบอยู่ใน README ของตัวอย่างและในโค้ด ถ้าตอบข้อใดไม่ได้ ให้กลับไปอ่านส่วน Why / What / How อีกครั้ง

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

ไปต่อ

  • ทบทวนเป้าหมายทั้ง 3 ข้อของบทเรียนนี้ก่อนไปต่อ
  • ถ้าตอบคำถามหน้าที่แล้วไม่ได้ครบ กลับไปอ่าน README ของตัวอย่างส่วน Why / What / How อีกครั้ง
  • พร้อมแล้วไปเปิดบทเรียนถัดไปในโมดูลเดียวกัน
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แหล่งอ้างอิง

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

เครดิต

"TESAIoT Firmware Stack: เฟิร์มแวร์ภาษา C บน TESAIoT Dev Kit" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ตัวอย่างโค้ดเป็นผลงานของ TESAIoT Firmware Stack โดยสมาคมสมองกลฝังตัวไทย (TESA) ใน tesaiot/developer-hub รายละเอียดการให้เครดิตอยู่ที่ ATTRIBUTION.md

ภาพหน้าจอในสไลด์นี้มาจาก tesaiot/developer-hub (hmi_ep05_wifi_list) ที่ commit 9a8e3ed

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