> For the complete documentation index, see [llms.txt](https://docs.aic-eec.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aic-eec.com/interfacing-with-infineon-psoc-tm-edge/hmi-development/gpio-to-hmi-display/ux-ui-workshops/led-and-switch/toggle-switch.md).

# Toggle Switch

## Lab 4: Switch Toggle Control

### Week 3 Part I - LVGL Basics

***

### 1. โครงสร้างภาพรวมของ Lab

#### Why? - ทำไมต้องเรียนรู้เรื่องนี้

Switch Widget เป็นตัวควบคุมสถานะ Binary (ON/OFF) ที่ใช้กันมากที่สุดในระบบ Embedded:

* **Industrial Control**: ควบคุมเครื่องจักรในโรงงาน เปิด/ปิด Motor, Valve, Heater
* **Smart Home**: สวิตช์ไฟ พัดลม เครื่องปรับอากาศผ่าน Touch Panel
* **IoT Gateway**: เปิด/ปิด Module ต่าง ๆ เช่น WiFi, Bluetooth, Sensor
* **GPIO Mapping**: Switch Widget บน UI สะท้องสถานะ GPIO pin จริง (HIGH/LOW)

ในงาน HMI (Human-Machine Interface) จริง ๆ switch เป็น widget ที่ operator ใช้บ่อยที่สุด เพราะมองเห็นสถานะชัดเจนทั้งจากรูปร่างและสี ไม่ต้องเดาว่าเปิดหรือปิดอยู่

#### What? - จะได้เรียนรู้อะไร

1. **Switch Widget**: สร้าง toggle switch ด้วย `lv_switch_create()`
2. **State Management**: ตรวจสอบ/เปลี่ยนสถานะด้วย `lv_obj_has_state()`, `lv_obj_add_state()`, `lv_obj_clear_state()`
3. **LV\_EVENT\_VALUE\_CHANGED**: ตอบสนองเมื่อ switch ถูก toggle
4. **LED Synchronization**: ซิงค์สถานะ Switch กับ LED Widget
5. **Switch Styling**: กำหนดสี ON/OFF และรูปแบบ knob
6. **Programmatic Control**: ควบคุม switch จาก code (ไม่ใช่จาก touch)

#### How? - ทำอย่างไร

สร้าง Switch ที่ควบคุม Virtual LED พร้อมแสดงสถานะ GPIO (HIGH/LOW) จากนั้นฝึกสร้าง Device Power Panel สำหรับควบคุมอุปกรณ์หลายตัวพร้อมกัน

<figure><img src="https://1856353139-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MClo3nC-1US0rbK8Qau%2Fuploads%2FjhPqhDWDihJDjveDemB6%2Fweek3_ex4_switch_toggle.gif?alt=media&amp;token=120c19ce-1c0a-4419-bc38-b2e2afb82f74" alt=""><figcaption></figcaption></figure>

***

### 2. หลักการทำงานและ Flowchart

#### 2.1 Switch Widget Architecture

```
┌─────────────────────────────────────────────────────────┐
│                  SWITCH WIDGET                          │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   OFF State:              ON State:                     │
│   ┌─────────────────┐    ┌─────────────────┐            │
│   │  ●          ░░░░│    │░░░░          ●  │            │
│   └─────────────────┘    └─────────────────┘            │
│   LV_STATE_DEFAULT       LV_STATE_CHECKED               │
│                                                         │
│   Properties:                                           │
│   ├── State: CHECKED or DEFAULT (unchecked)             │
│   ├── Disabled: Can be grayed out                       │
│   └── Color: Customizable for both states               │
│                                                         │
│   Event:                                                │
│   └── LV_EVENT_VALUE_CHANGED: When toggled              │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

#### 2.2 State Checking Pattern

```
┌─────────────────────────────────────────────────────────┐
│              STATE CHECKING METHODS                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   Method 1: lv_obj_has_state() ← Recommended            │
│   ─────────────────────────────                         │
│   bool is_on = lv_obj_has_state(sw, LV_STATE_CHECKED);  │
│                                                         │
│   Method 2: lv_obj_get_state()                          │
│   ─────────────────────────────                         │
│   lv_state_t state = lv_obj_get_state(sw);              │
│   bool is_on = (state & LV_STATE_CHECKED);              │
│                                                         │
│   Common States:                                        │
│   ├── LV_STATE_DEFAULT:  ไม่มี state พิเศษ                 │
│   ├── LV_STATE_CHECKED:  ถูกเลือก (ON)                    │
│   ├── LV_STATE_FOCUSED:  มี focus                        │
│   ├── LV_STATE_PRESSED:  กำลังกด                         │
│   └── LV_STATE_DISABLED: ถูก disable                     │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

#### 2.3 GPIO Simulation Concept

```
┌─────────────────────────────────────────────────────────┐
│               GPIO ↔ SWITCH MAPPING                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   UI (Switch)         →    Hardware (GPIO)              │
│   ────────────────────────────────────────────          │
│                                                         │
│   ┌──────────────┐         ┌──────────────┐             │
│   │ Switch OFF   │    ══>  │ GPIO = LOW   │ = 0V        │
│   │ (unchecked)  │         │ LED OFF      │             │
│   └──────────────┘         └──────────────┘             │
│                                                         │
│   ┌──────────────┐         ┌──────────────┐             │
│   │ Switch ON    │    ══>  │ GPIO = HIGH  │ = 3.3V      │
│   │ (checked)    │         │ LED ON       │             │
│   └──────────────┘         └──────────────┘             │
│                                                         │
│   In Real Hardware (Week 3 Part II):                    │
│   cyhal_gpio_write(LED_PIN, is_checked);                │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

#### 2.4 Program Flowchart

```
┌─────────────────────────────────────────────────────────┐
│                  PROGRAM FLOW                           │
├─────────────────────────────────────────────────────────┤
│                                                         │
│                    ┌─────────┐                          │
│                    │  Start  │                          │
│                    └────┬────┘                          │
│                         │                               │
│                         ▼                               │
│              ┌─────────────────────┐                    │
│              │ Create LED          │                    │
│              │ (Initial: OFF)      │                    │
│              └──────────┬──────────┘                    │
│                         │                               │
│                         ▼                               │
│              ┌─────────────────────┐                    │
│              │ Create Switch       │                    │
│              │ (Initial: unchecked)│                    │
│              └──────────┬──────────┘                    │
│                         │                               │
│                         ▼                               │
│              ┌─────────────────────┐                    │
│              │ Create Status Label │                    │
│              │ "GPIO State: LOW"   │                    │
│              └──────────┬──────────┘                    │
│                         │                               │
│                         ▼                               │
│              ┌─────────────────────┐                    │
│              │ LVGL Main Loop      │◄──────────┐        │
│              └──────────┬──────────┘           │        │
│                         │                      │        │
│                    User toggles                │        │
│                    switch                      │        │
│                         │                      │        │
│                         ▼                      │        │
│              ┌─────────────────────┐           │        │
│              │ VALUE_CHANGED Event │           │        │
│              └──────────┬──────────┘           │        │
│                         │                      │        │
│                         ▼                      │        │
│              ┌─────────────────────┐           │        │
│              │ Check state:        │           │        │
│              │ lv_obj_has_state()  │           │        │
│              └──────────┬──────────┘           │        │
│                         │                      │        │
│           ┌─────────────┴─────────────┐        │        │
│           │                           │        │        │
│           ▼                           ▼        │        │
│    ┌────────────┐              ┌────────────┐  │        │
│    │ CHECKED:   │              │ UNCHECKED: │  │        │
│    │ LED ON     │              │ LED OFF    │  │        │
│    │ "HIGH"     │              │ "LOW"      │  │        │
│    └─────┬──────┘              └─────┬──────┘  │        │
│          │                           │         │        │
│          └───────────────────────────┘         │        │
│                         │                      │        │
│                         └──────────────────────┘        │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

***

### 3. ฟังก์ชันสำคัญ (API Reference)

#### 3.1 Switch Creation & Control

<table><thead><tr><th width="364.88067626953125">Function</th><th width="224.469482421875">Description</th><th>Return</th></tr></thead><tbody><tr><td><code>lv_switch_create(parent)</code></td><td>สร้าง Switch widget</td><td><code>lv_obj_t *</code></td></tr><tr><td><code>lv_obj_add_state(sw, LV_STATE_CHECKED)</code></td><td>ตั้งค่าสถานะ ON</td><td>void</td></tr><tr><td><code>lv_obj_clear_state(sw, LV_STATE_CHECKED)</code></td><td>ตั้งค่าสถานะ OFF</td><td>void</td></tr><tr><td><code>lv_obj_has_state(sw, LV_STATE_CHECKED)</code></td><td>ตรวจว่า ON หรือ OFF</td><td><code>bool</code></td></tr><tr><td><code>lv_obj_add_state(sw, LV_STATE_DISABLED)</code></td><td>Disable switch (กดไม่ได้)</td><td>void</td></tr></tbody></table>

#### 3.2 LED Widget Functions

<table><thead><tr><th width="320.5909423828125">Function</th><th>Description</th><th>Parameters</th></tr></thead><tbody><tr><td><code>lv_led_create(parent)</code></td><td>สร้าง LED widget</td><td>parent object</td></tr><tr><td><code>lv_led_on(led)</code></td><td>เปิด LED (สว่างเต็ม)</td><td>led object</td></tr><tr><td><code>lv_led_off(led)</code></td><td>ปิด LED (หรี่สุด)</td><td>led object</td></tr><tr><td><code>lv_led_set_color(led, color)</code></td><td>ตั้งสี LED</td><td>led, <code>lv_color_t</code></td></tr><tr><td><code>lv_led_set_brightness(led, bright)</code></td><td>ตั้งความสว่าง 0-255</td><td>led, uint8_t</td></tr></tbody></table>

#### 3.3 Event Handling

<table><thead><tr><th width="418.90057373046875">Function</th><th width="212.4482421875">Description</th><th>Return</th></tr></thead><tbody><tr><td><code>lv_obj_add_event_cb(obj, cb, event, user_data)</code></td><td>ลงทะเบียน callback</td><td>void</td></tr><tr><td><code>lv_event_get_target(e)</code></td><td>ได้ object ที่ trigger event</td><td><code>lv_obj_t *</code></td></tr><tr><td><code>lv_event_get_user_data(e)</code></td><td>ได้ user_data ที่ส่งมา</td><td><code>void *</code></td></tr></tbody></table>

#### 3.4 Switch vs Button Comparison

<table><thead><tr><th width="147.45526123046875">Feature</th><th width="238.96661376953125">Button</th><th>Switch</th></tr></thead><tbody><tr><td>Action</td><td>Click (momentary)</td><td>Toggle (latching)</td></tr><tr><td>State</td><td>Pressed/Released</td><td>ON/OFF</td></tr><tr><td>Event</td><td><code>LV_EVENT_CLICKED</code></td><td><code>LV_EVENT_VALUE_CHANGED</code></td></tr><tr><td>Use Case</td><td>Action trigger</td><td>Setting toggle</td></tr><tr><td>Visual</td><td>Text label</td><td>Sliding knob</td></tr></tbody></table>

***

### 4. โค้ดตัวอย่าง (Code Examples)

#### 4.1 Complete Code - part1\_ex4\_switch\_toggle()

จากไฟล์ `part1_examples.c`:

```c
/*******************************************************************************
 * Example 4: Switch Widget (ON/OFF Toggle)
 *
 * Learning: lv_switch_create, LV_STATE_CHECKED, LV_EVENT_VALUE_CHANGED
 * Platform: PSoC Edge E84 + LVGL v9.2.0
 ******************************************************************************/

/* Global variables สำหรับ update จาก callback */
static lv_obj_t * ex4_status_label;
static lv_obj_t * ex4_led;

/* Switch callback - เรียกทุกครั้งที่ user toggle switch */
static void ex4_switch_cb(lv_event_t * e)
{
    lv_obj_t * sw = lv_event_get_target(e);
    bool is_checked = lv_obj_has_state(sw, LV_STATE_CHECKED);

    if(is_checked) {
        lv_label_set_text(ex4_status_label, "GPIO State: HIGH (ON)");
        lv_led_on(ex4_led);
        printf("Switch ON - GPIO would be HIGH\r\n");
    } else {
        lv_label_set_text(ex4_status_label, "GPIO State: LOW (OFF)");
        lv_led_off(ex4_led);
        printf("Switch OFF - GPIO would be LOW\r\n");
    }
}

void part1_ex4_switch_toggle(void)
{
    /* [1] Background - สีเข้มสำหรับ dark theme */
    lv_obj_set_style_bg_color(lv_screen_active(),
                              lv_color_hex(0x16213e),
                              LV_PART_MAIN);

    /* [2] Title */
    lv_obj_t * title = lv_label_create(lv_screen_active());
    lv_label_set_text(title, "Part 1 - Example 4: Switch Control");
    lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 20);

    /* [3] LED indicator - เริ่มที่ OFF */
    ex4_led = lv_led_create(lv_screen_active());
    lv_obj_set_size(ex4_led, 60, 60);
    lv_obj_align(ex4_led, LV_ALIGN_CENTER, 0, -60);
    lv_led_set_color(ex4_led, lv_palette_main(LV_PALETTE_YELLOW));
    lv_led_off(ex4_led);

    /* [4] Label ใต้ LED */
    lv_obj_t * led_label = lv_label_create(lv_screen_active());
    lv_label_set_text(led_label, "Virtual LED");
    lv_obj_set_style_text_color(led_label, lv_color_hex(0xFFFFFF), 0);
    lv_obj_align_to(led_label, ex4_led, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

    /* [5] Switch - สร้าง + ลงทะเบียน callback */
    lv_obj_t * sw = lv_switch_create(lv_screen_active());
    lv_obj_set_size(sw, 80, 40);
    lv_obj_align(sw, LV_ALIGN_CENTER, 0, 40);
    lv_obj_add_event_cb(sw, ex4_switch_cb, LV_EVENT_VALUE_CHANGED, NULL);

    /* [6] Status label - แสดง GPIO state */
    ex4_status_label = lv_label_create(lv_screen_active());
    lv_label_set_text(ex4_status_label, "GPIO State: LOW (OFF)");
    lv_obj_set_style_text_color(ex4_status_label, lv_color_hex(0x00FF00), 0);
    lv_obj_align(ex4_status_label, LV_ALIGN_CENTER, 0, 100);

    /* [7] Description */
    lv_obj_t * desc = lv_label_create(lv_screen_active());
    lv_label_set_text(desc, "Learning: lv_switch_create, LV_STATE_CHECKED\n"
                           "This switch would control a real GPIO in actual hardware");
    lv_obj_set_style_text_color(desc, lv_color_hex(0xAAAAAA), 0);
    lv_obj_set_style_text_align(desc, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_align(desc, LV_ALIGN_BOTTOM_MID, 0, -45);
}
```

#### 4.2 Code Breakdown

**Part A: Switch Event Callback**

```c
static void ex4_switch_cb(lv_event_t * e)
{
    /* [1] ดึง object ที่ trigger event */
    lv_obj_t * sw = lv_event_get_target(e);

    /* [2] ตรวจสอบว่า switch ON หรือ OFF */
    bool is_checked = lv_obj_has_state(sw, LV_STATE_CHECKED);

    /* [3] อัพเดท UI ตาม state */
    if(is_checked) {
        lv_label_set_text(ex4_status_label, "GPIO State: HIGH (ON)");
        lv_led_on(ex4_led);                // LED สว่าง
    } else {
        lv_label_set_text(ex4_status_label, "GPIO State: LOW (OFF)");
        lv_led_off(ex4_led);               // LED ดับ
    }
}
```

**Part B: Switch Creation**

```c
/* สร้าง switch พร้อมกำหนดขนาดและตำแหน่ง */
lv_obj_t * sw = lv_switch_create(lv_screen_active());
lv_obj_set_size(sw, 80, 40);                    /* กว้าง 80, สูง 40 */
lv_obj_align(sw, LV_ALIGN_CENTER, 0, 40);       /* กลางจอ เลื่อนลง 40px */

/* ลงทะเบียน callback - เฉพาะ VALUE_CHANGED เท่านั้น */
lv_obj_add_event_cb(sw, ex4_switch_cb, LV_EVENT_VALUE_CHANGED, NULL);
```

***

### 5. องค์ความรู้และเทคนิค

#### 5.1 Switch Styling - กำหนดสี ON/OFF

```c
/* สี ON state (checked) - indicator track */
lv_obj_set_style_bg_color(sw, lv_palette_main(LV_PALETTE_GREEN),
                          LV_PART_INDICATOR | LV_STATE_CHECKED);

/* สี OFF state - indicator track */
lv_obj_set_style_bg_color(sw, lv_color_hex(0x666666),
                          LV_PART_INDICATOR);

/* สี knob (ปุ่มกลม) */
lv_obj_set_style_bg_color(sw, lv_color_hex(0xFFFFFF), LV_PART_KNOB);

/* เพิ่ม padding ให้ knob ใหญ่ขึ้น */
lv_obj_set_style_pad_all(sw, 5, LV_PART_KNOB);
```

#### 5.2 Programmatic State Control

```c
/* เปิด switch จาก code */
lv_obj_add_state(sw, LV_STATE_CHECKED);

/* ปิด switch จาก code */
lv_obj_clear_state(sw, LV_STATE_CHECKED);

/* สลับ (toggle) state */
if(lv_obj_has_state(sw, LV_STATE_CHECKED)) {
    lv_obj_clear_state(sw, LV_STATE_CHECKED);
} else {
    lv_obj_add_state(sw, LV_STATE_CHECKED);
}

/* สำคัญ: การเปลี่ยน state จาก code ไม่ trigger callback!
 * ถ้าต้องการให้ callback ทำงาน ใช้:
 * lv_event_send(sw, LV_EVENT_VALUE_CHANGED, NULL);
 */
```

#### 5.3 Disable/Enable Switch

```c
/* Disable - switch จะเป็นสีจาง กดไม่ได้ */
lv_obj_add_state(sw, LV_STATE_DISABLED);

/* Enable กลับมา */
lv_obj_clear_state(sw, LV_STATE_DISABLED);

/* ใช้ได้กับสถานการณ์:
 * - ต้อง login ก่อน ถึงจะควบคุมอุปกรณ์ได้
 * - อุปกรณ์เสีย ไม่ให้ user เปิด
 * - Interlock safety (ห้ามเปิดพร้อมกัน)
 */
```

#### 5.4 User Data Pattern (สำหรับหลาย Switch)

```c
/* เมื่อมี switch หลายตัว ใช้ user_data แยก */
typedef struct {
    lv_obj_t *led;
    const char *name;
} device_t;

static device_t devices[4];

/* ตอนสร้าง - ส่ง pointer ไปกับ callback */
lv_obj_add_event_cb(sw, device_cb,
                   LV_EVENT_VALUE_CHANGED, &devices[i]);

/* ตอนรับ - ดึง pointer กลับ */
static void device_cb(lv_event_t * e)
{
    device_t * dev = (device_t *)lv_event_get_user_data(e);
    printf("Device: %s toggled\n", dev->name);
}
```

***

### 6. แบบฝึกหัด (Exercises)

#### Exercise 1: Device Power Panel (Intermediate)

สร้าง Smart Home Power Panel ที่มี 4 switches ควบคุมอุปกรณ์ พร้อม LED indicator แต่ละตัว

**Requirements:**

* 4 อุปกรณ์: Fan, Light, AC, Heater
* แต่ละตัวมี Switch + LED + Label แสดงชื่อและสถานะ
* LED เปลี่ยนสีตามอุปกรณ์ (Fan=Blue, Light=Yellow, AC=Cyan, Heater=Red)
* แสดงจำนวนอุปกรณ์ที่เปิดอยู่ "Active: 2/4"

**Expected Output:**

```
+------------------------------------------+
|         Device Power Panel               |
|           Active: 2/4                    |
+------------------------------------------+
|                                          |
|   [O] Fan        [ ==== O ]  OFF         |
|   [*] Light      [ O ==== ]  ON          |
|   [*] AC         [ O ==== ]  ON          |
|   [O] Heater     [ ==== O ]  OFF         |
|                                          |
+------------------------------------------+
```

**Hints:**

* ใช้ struct array เก็บข้อมูลแต่ละอุปกรณ์
* ส่ง pointer ไป callback ด้วย user\_data
* สร้าง function `update_active_count()` แยก

***

#### Exercise 2: Master Switch with Child Switches (Advanced)

สร้าง Master Switch ที่ควบคุม switches ลูกทั้งหมด:

* Master ON --> ลูกทุกตัว ON
* Master OFF --> ลูกทุกตัว OFF
* ลูกแต่ละตัวยังสามารถ toggle เองได้
* แสดงสถานะ "All ON", "All OFF", หรือ "Partial (2/4)"

**Expected Output:**

```
+------------------------------------------+
|       Master Switch Control              |
+------------------------------------------+
|                                          |
|  MASTER:  [ O ==== ]  Status: Partial    |
|  --------------------------------------- |
|  CH1  [O]  [ ==== O ]  OFF               |
|  CH2  [*]  [ O ==== ]  ON                |
|  CH3  [*]  [ O ==== ]  ON                |
|  CH4  [O]  [ ==== O ]  OFF               |
|                                          |
+------------------------------------------+
```

**Hints:**

* Master switch callback ใช้ loop set state ให้ switches ลูกทั้งหมด
* เรียก `lv_obj_invalidate()` หลังเปลี่ยน state จาก code
* อัพเดท master label เมื่อ child switch เปลี่ยน

***

### 7. References

* [LVGL Switch Documentation](https://docs.lvgl.io/9.2/widgets/switch.html)
* [LVGL Switch Example](https://github.com/lvgl/lvgl/blob/release/v9.2/examples/widgets/switch/lv_example_switch_1.c)
* [LVGL State System](https://docs.lvgl.io/9.2/overview/obj.html#states)

***

**Previous Lab:** Lab 3: LED Widget Control **Next Lab:** Lab 5: GPIO Dashboard
