# 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="/files/ZAq1v6anp7CxYBII2jni" 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET 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?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
