# Sensor Dashboard

## Lab 8: Real Sensor Dashboard

### Part 2 - Sensor Visualization

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

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

* **Multi-Sensor Integration**: ในระบบ IoT จริง มี sensor หลายตัวที่ต้องอ่านค่าและแสดงผลพร้อมกัน
* **Real APIs**: ใช้ `aic_adc_read()` + `imu_shared_read_accel()` ร่วมกัน
* **TabView Organization**: จัดการข้อมูลจากหลาย sensor ด้วย tabs
* **Single Timer Pattern**: อัพเดทข้อมูลจากหลาย sensor ใน callback เดียว

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

1. **Multiple Sensor APIs**: อ่านค่าจาก ADC (potentiometer) และ IMU (accelerometer) พร้อมกัน
2. **TabView + Real Data**: รวม Lab 5 (TabView) กับ Lab 7 (Real IMU) เข้าด้วยกัน
3. **Data Mapping**: แปลงค่า sensor แต่ละตัวให้เหมาะกับ widget ที่แสดงผล
4. **Hardware Polling**: อ่านค่าจากหลาย sensor ใน timer เดียว
5. **Graceful Degradation**: จัดการเมื่อ sensor บางตัวไม่พร้อม

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

1. เรียก `aic_sensors_init()` ก่อนสร้าง UI
2. สร้าง TabView 2 tabs: IMU Charts + ADC Gauge
3. Timer callback อ่านค่าจากทุก sensor API
4. Tab 1: แสดง ADC ด้วย Bar + Value label
5. Tab 2: แสดง accelerometer X/Y/Z ด้วย Line Chart
6. Tab 3: แสดง Gyro ด้วย Arc gauge + Value label

<figure><img src="/files/4tJ3J48pK6OlEDumA6m6" alt=""><figcaption></figcaption></figure>

***

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

#### 2.1 Dashboard Architecture

```
┌─────────────────────────────────────────────────────────────┐
│             SENSOR DASHBOARD ARCHITECTURE                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌──────────────────────────────────────────────────────┐  │
│   │                  SENSOR LAYER                        │  │
│   │   ┌─────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│   │   │   ADC   │  │Accelerometer│  │  Gyroscope  │      │  │
│   │   │ (POTEN) │  │  (BMI270)   │  │  (BMI270)   │      │  │
│   │   └────┬────┘  └──────┬──────┘  └──────┬──────┘      │  │
│   └────────┼──────────────┼─────────────────┼────────────┘  │
│            │              │                 │               │
│            ▼              ▼                 ▼               │
│   ┌──────────────────────────────────────────────────────┐  │
│   │                  API LAYER                           │  │
│   │aic_adc_read() aic_imu_read_accel() aic_imu_read_gyro()  │
│   └────────┬──────────────┬─────────────────┬───────────┘   │
│            │              │                 │               │
│            ▼              ▼                 ▼               │
│   ┌──────────────────────────────────────────────────────┐  │
│   │             TIMER CALLBACK (100ms)                   │  │
│   │   - Read all sensors                                 │  │
│   │   - Scale data for widgets                           │  │
│   │   - Update UI elements                               │  │
│   └──────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

#### 2.2 TabView Layout

```
┌─────────────────────────────────────────────────────────────┐
│  [  ADC  ] [  Accel  ] [  Gyro  ]    ← Tab Bar (80px)       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ╔═══════════════════════════════════════════════════════╗ │
│   ║                    Tab Content                        ║ │
│   ║                    480 x 240                          ║ │
│   ║                                                       ║ │
│   ║   ADC Tab:                                            ║ │
│   ║     [=========BAR (450x60)==========]                 ║ │
│   ║            "ADC: 2048 (1.65V)"                        ║ │
│   ║                                                       ║ │
│   ║   Accel Tab:                                          ║ │
│   ║     [CHART 400x210]  X: +0.5                          ║ │
│   ║                      Y: -0.3                          ║ │
│   ║                      Z: +9.8                          ║ │
│   ║                                                       ║ │
│   ║   Gyro Tab:                                           ║ │
│   ║     (Arc)    (Arc)    (Arc)                           ║ │
│   ║     Roll     Pitch    Yaw                             ║ │
│   ║     0.00     0.00     0.00                            ║ │
│   ╚═══════════════════════════════════════════════════════╝ │
└─────────────────────────────────────────────────────────────┘
```

#### 2.3 Data Mapping

```
┌─────────────────────────────────────────────────────────────┐
│                 DATA MAPPING                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ADC (0-4095):                                             │
│     pct = (adc * 100) / 4095     → Bar (0-100%)             │
│     volt = (adc / 4095) * 3.3V   → Label                    │
│                                                             │
│   Accelerometer (float m/s²):                               │
│     scaled = (int32_t)(ax * 100) → Chart (-1500 to 1500)    │
│                                                             │
│   Gyroscope (float rad/s, ±1.0):                            │
│     pct = (int32_t)((gx + 1.0) * 50) → Arc (0-100%)         │
│         -1.0 rad/s → 0%                                     │
│          0.0 rad/s → 50%                                    │
│         +1.0 rad/s → 100%                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

***

### 3. ฟังก์ชันสำคัญ

#### 3.1 Sensor APIs ที่ใช้ใน Lab นี้

<table><thead><tr><th width="343.31463623046875">Function</th><th width="100.86358642578125">Return</th><th>Description</th></tr></thead><tbody><tr><td><code>aic_sensors_init()</code></td><td>void</td><td>Initialize ทุก sensor (เรียกครั้งเดียว)</td></tr><tr><td><code>aic_adc_read(AIC_ADC_CH0)</code></td><td>uint16_t</td><td>อ่าน ADC channel 0 (0-4095)</td></tr><tr><td><code>imu_shared_read_accel(&#x26;ax, &#x26;ay, &#x26;az)</code></td><td>bool</td><td>อ่าน accelerometer (m/s2)</td></tr></tbody></table>

#### 3.2 ADC API Detail

```c
/* ADC อ่านค่า potentiometer ที่ต่ออยู่กับ channel 0 */
/* Return: 0-4095 (12-bit resolution) */
/* 0    = 0V (GND) */
/* 4095 = 3.3V (VCC) */
uint16_t adc_value = aic_adc_read(AIC_ADC_CH0);
```

#### 3.3 Widget Functions ที่ใช้

<table><thead><tr><th width="87.14990234375">Tab</th><th width="156.38848876953125">Widget</th><th>Key Functions</th></tr></thead><tbody><tr><td>IMU</td><td>lv_chart (LINE)</td><td><code>lv_chart_set_next_value()</code></td></tr><tr><td>ADC</td><td>lv_bar</td><td><code>lv_bar_set_value()</code>, <code>lv_bar_set_range()</code></td></tr><tr><td>ADC</td><td>lv_arc</td><td><code>lv_arc_set_value()</code>, <code>lv_arc_set_range()</code></td></tr><tr><td>Both</td><td>lv_label</td><td><code>lv_label_set_text_fmt()</code></td></tr></tbody></table>

#### 3.4 Include Files

```c
#include "lvgl.h"
#include <math.h>
#include <stdio.h>

#ifdef CYBSP_ENABLED
#include "aic-eec/aic-eec.h"
#include "aic-eec/sensors.h"
#include "../../shared/imu_shared.h"
#endif
```

***

### 4. โค้ดตัวอย่าง

#### 4.1 Global Variables

```c
#define ADC_MAX         4095
#define CHART_POINTS    50

/* IMU Tab widgets */
static lv_obj_t * ex8_accel_chart;
static lv_chart_series_t * ex8_accel_ser[3];
static lv_obj_t * ex8_accel_labels[3];

/* ADC Tab widgets */
static lv_obj_t * ex8_adc_arc;
static lv_obj_t * ex8_adc_bar;
static lv_obj_t * ex8_adc_label;
static lv_obj_t * ex8_adc_pct_label;

/* Timer */
static lv_timer_t * ex8_timer;
```

#### 4.2 Simulation Helpers (PC Simulator)

```c
#ifndef CYBSP_ENABLED
static uint16_t simulate_adc_read(void)
{
    static float phase = 0.0f;
    phase += 0.02f;
    return (uint16_t)(2048 + 1800 * sinf(phase));
}

static bool simulate_imu_accel(float *ax, float *ay, float *az)
{
    static float t = 0.0f;
    t += 0.05f;
    *ax = 0.5f * sinf(t);
    *ay = 0.3f * cosf(t * 0.7f);
    *az = 9.81f + 0.2f * sinf(t * 2.0f);
    return true;
}
#endif
```

#### 4.3 Timer Callback - อ่านค่าจากทุก Sensor

```c
static void ex8_timer_cb(lv_timer_t * timer)
{
    (void)timer;

    /* ===== ADC (Potentiometer) ===== */
    uint16_t adc;
#ifdef CYBSP_ENABLED
    adc = aic_adc_read(AIC_ADC_CH0);
#else
    adc = simulate_adc_read();
#endif

    int32_t pct = (adc * 100) / ADC_MAX;
    float volt = ((float)adc / ADC_MAX) * 3.3f;

    lv_arc_set_value(ex8_adc_arc, pct);
    lv_bar_set_value(ex8_adc_bar, pct, LV_ANIM_ON);
    lv_label_set_text_fmt(ex8_adc_label,
        "ADC: %d (%.2fV)", adc, (double)volt);
    lv_label_set_text_fmt(ex8_adc_pct_label, "%d%%", (int)pct);

    /* ===== ACCELEROMETER (BMI270) ===== */
    float ax, ay, az;
    bool imu_ok;
#ifdef CYBSP_ENABLED
    imu_ok = imu_shared_read_accel(&ax, &ay, &az);
#else
    imu_ok = simulate_imu_accel(&ax, &ay, &az);
#endif

    if(imu_ok) {
        /* Scale & update chart */
        lv_chart_set_next_value(ex8_accel_chart, ex8_accel_ser[0],
                                (int32_t)(ax * 100));
        lv_chart_set_next_value(ex8_accel_chart, ex8_accel_ser[1],
                                (int32_t)(ay * 100));
        lv_chart_set_next_value(ex8_accel_chart, ex8_accel_ser[2],
                                (int32_t)(az * 100));

        /* Update labels */
        lv_label_set_text_fmt(ex8_accel_labels[0], "X:%+.1f", (double)ax);
        lv_label_set_text_fmt(ex8_accel_labels[1], "Y:%+.1f", (double)ay);
        lv_label_set_text_fmt(ex8_accel_labels[2], "Z:%+.1f", (double)az);
    }

    /* ===== Debug Print (throttled) ===== */
    static uint32_t count = 0;
    count++;
    if(count % 10 == 0) {
        printf("[DASH] ADC:%d (%.2fV) IMU:%s X:%+.2f Y:%+.2f Z:%+.2f\r\n",
               adc, (double)volt,
               imu_ok ? "OK" : "N/A",
               (double)ax, (double)ay, (double)az);
    }
}
```

#### 4.4 สร้าง IMU Tab

```c
static void ex8_create_imu_tab(lv_obj_t * parent)
{
    /* Title */
    lv_obj_t * title = lv_label_create(parent);
    lv_label_set_text(title, "Accelerometer - REAL BMI270");
    lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 5);

    /* Chart */
    ex8_accel_chart = lv_chart_create(parent);
    lv_obj_set_size(ex8_accel_chart, 380, 180);
    lv_obj_align(ex8_accel_chart, LV_ALIGN_CENTER, -30, 10);
    lv_chart_set_type(ex8_accel_chart, LV_CHART_TYPE_LINE);
    lv_chart_set_point_count(ex8_accel_chart, CHART_POINTS);
    lv_chart_set_range(ex8_accel_chart,
        LV_CHART_AXIS_PRIMARY_Y, -1500, 1500);

    /* ซ่อน point indicator */
    lv_obj_set_style_size(ex8_accel_chart, 0, 0, LV_PART_INDICATOR);
    lv_obj_set_style_line_width(ex8_accel_chart, 2, LV_PART_ITEMS);
    lv_chart_set_div_line_count(ex8_accel_chart, 5, 8);

    /* 3 Series: X(Red), Y(Green), Z(Blue) */
    lv_color_t colors[] = {
        lv_palette_main(LV_PALETTE_RED),
        lv_palette_main(LV_PALETTE_GREEN),
        lv_palette_main(LV_PALETTE_BLUE)
    };

    for(int i = 0; i < 3; i++) {
        ex8_accel_ser[i] = lv_chart_add_series(ex8_accel_chart,
            colors[i], LV_CHART_AXIS_PRIMARY_Y);

        ex8_accel_labels[i] = lv_label_create(parent);
        lv_label_set_text(ex8_accel_labels[i], "0.0");
        lv_obj_set_style_text_color(ex8_accel_labels[i], colors[i], 0);
        lv_obj_set_style_text_font(ex8_accel_labels[i],
            &lv_font_montserrat_16, 0);
        lv_obj_align(ex8_accel_labels[i], LV_ALIGN_RIGHT_MID,
            -5, -40 + i * 40);
    }
}
```

#### 4.5 สร้าง ADC Tab (Arc + Bar)

```c
static void ex8_create_adc_tab(lv_obj_t * parent)
{
    /* Title */
    lv_obj_t * title = lv_label_create(parent);
    lv_label_set_text(title, "ADC Monitor - REAL Potentiometer");
    lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 5);

    /* Arc Gauge */
    ex8_adc_arc = lv_arc_create(parent);
    lv_obj_set_size(ex8_adc_arc, 140, 140);
    lv_obj_align(ex8_adc_arc, LV_ALIGN_CENTER, 0, -20);
    lv_arc_set_range(ex8_adc_arc, 0, 100);
    lv_arc_set_value(ex8_adc_arc, 0);
    lv_arc_set_bg_angles(ex8_adc_arc, 135, 45);
    lv_obj_set_style_arc_color(ex8_adc_arc,
        lv_palette_main(LV_PALETTE_BLUE), LV_PART_INDICATOR);
    lv_obj_set_style_arc_width(ex8_adc_arc, 15, LV_PART_MAIN);
    lv_obj_set_style_arc_width(ex8_adc_arc, 15, LV_PART_INDICATOR);
    lv_obj_remove_style(ex8_adc_arc, NULL, LV_PART_KNOB);

    /* Percentage label ตรงกลาง arc */
    ex8_adc_pct_label = lv_label_create(parent);
    lv_label_set_text(ex8_adc_pct_label, "0%");
    lv_obj_set_style_text_font(ex8_adc_pct_label,
        &lv_font_montserrat_24, 0);
    lv_obj_center(ex8_adc_pct_label);
    lv_obj_align(ex8_adc_pct_label, LV_ALIGN_CENTER, 0, -20);

    /* Bar (ใต้ arc) */
    ex8_adc_bar = lv_bar_create(parent);
    lv_obj_set_size(ex8_adc_bar, 350, 30);
    lv_obj_align(ex8_adc_bar, LV_ALIGN_CENTER, 0, 60);
    lv_bar_set_range(ex8_adc_bar, 0, 100);
    lv_obj_set_style_bg_color(ex8_adc_bar,
        lv_palette_main(LV_PALETTE_BLUE), LV_PART_INDICATOR);

    /* Value label */
    ex8_adc_label = lv_label_create(parent);
    lv_label_set_text(ex8_adc_label, "ADC: 0 (0.00V)");
    lv_obj_set_style_text_font(ex8_adc_label,
        &lv_font_montserrat_18, 0);
    lv_obj_align(ex8_adc_label, LV_ALIGN_CENTER, 0, 95);
}
```

#### 4.6 Main Function

```c
void part2_ex8_real_sensor_dashboard(void)
{
    /* ===== HARDWARE INITIALIZATION ===== */
#ifdef CYBSP_ENABLED
    aic_sensors_init();
#endif

    /* ===== CREATE TABVIEW ===== */
    lv_obj_t * tabview = lv_tabview_create(lv_screen_active());
    lv_tabview_set_tab_bar_position(tabview, LV_DIR_TOP);
    lv_tabview_set_tab_bar_size(tabview, 80);

    /* Style Tab Bar */
    lv_obj_t * tab_btns = lv_tabview_get_tab_bar(tabview);
    lv_obj_set_style_bg_color(tab_btns,
        lv_palette_darken(LV_PALETTE_GREY, 3), 0);
    lv_obj_set_style_text_color(tab_btns,
        lv_palette_lighten(LV_PALETTE_GREY, 5), 0);

    /* ===== CREATE TABS ===== */
    lv_obj_t * tab_imu = lv_tabview_add_tab(tabview, "IMU");
    lv_obj_t * tab_adc = lv_tabview_add_tab(tabview, "ADC");

    /* Style Tab Content */
    lv_obj_set_style_bg_color(tab_imu, lv_color_hex(0xFFFFFF), 0);
    lv_obj_set_style_bg_opa(tab_imu, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(tab_adc, lv_color_hex(0xFFFFFF), 0);
    lv_obj_set_style_bg_opa(tab_adc, LV_OPA_COVER, 0);

    /* ===== POPULATE TABS ===== */
    ex8_create_imu_tab(tab_imu);
    ex8_create_adc_tab(tab_adc);

    /* ===== CRITICAL: ปิด scrolling ===== */
    lv_obj_remove_flag(lv_tabview_get_content(tabview),
                       LV_OBJ_FLAG_SCROLLABLE);

    /* ===== TIMER: อัพเดทข้อมูลทุก 100ms ===== */
    ex8_timer = lv_timer_create(ex8_timer_cb, 100, NULL);
}
```

***

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

#### 5.1 Single Timer สำหรับ Multiple Sensors

```c
/* ข้อดีของการใช้ timer เดียวอ่านทุก sensor: */

/* 1. Synchronized data - ทุก sensor อ่านค่าพร้อมกัน */
/* 2. Consistent UI update - ทุก widget อัพเดทพร้อมกัน */
/* 3. Less memory - timer object เดียว */
/* 4. Easier to manage - ลบ timer เดียว cleanup หมด */

static void single_timer_cb(lv_timer_t * timer)
{
    /* อ่านทุก sensor ใน callback เดียว */
    read_and_update_adc();
    read_and_update_imu();
    read_and_update_gyro();
}
```

#### 5.2 Graceful Degradation

```c
/* เมื่อ sensor บางตัวไม่พร้อม ให้ UI ยังทำงานต่อได้ */

static void robust_timer_cb(lv_timer_t * timer)
{
    /* ADC มักพร้อมเสมอ */
    uint16_t adc = aic_adc_read(AIC_ADC_CH0);
    update_adc_widgets(adc);  /* อัพเดทได้เลย */

    /* IMU อาจไม่พร้อมตอนเริ่มต้น */
    float ax, ay, az;
    if(imu_shared_read_accel(&ax, &ay, &az)) {
        update_imu_widgets(ax, ay, az);  /* อัพเดทเมื่อพร้อม */
    }
    /* ถ้า IMU ไม่พร้อม → Chart + Labels ยังแสดงค่าเดิม */
}
```

#### 5.3 ADC Arc Color Change ตามค่า

```c
/* เปลี่ยนสี arc ตาม % value - visual feedback */
static void update_adc_color(int32_t pct)
{
    lv_color_t color;
    if(pct < 30) {
        color = lv_palette_main(LV_PALETTE_GREEN);
    } else if(pct < 70) {
        color = lv_palette_main(LV_PALETTE_YELLOW);
    } else {
        color = lv_palette_main(LV_PALETTE_RED);
    }
    lv_obj_set_style_arc_color(ex8_adc_arc, color, LV_PART_INDICATOR);
    lv_obj_set_style_bg_color(ex8_adc_bar, color, LV_PART_INDICATOR);
}
```

#### 5.4 Active Tab Optimization

```c
/* Performance: อัพเดทเฉพาะ tab ที่มองเห็น */
static lv_obj_t * tabview_ref;

static void optimized_timer_cb(lv_timer_t * timer)
{
    uint32_t active = lv_tabview_get_tab_active(tabview_ref);

    switch(active) {
        case 0:  /* IMU Tab */
            /* อ่าน IMU อย่างเดียว */
            read_and_update_imu();
            break;
        case 1:  /* ADC Tab */
            /* อ่าน ADC อย่างเดียว */
            read_and_update_adc();
            break;
    }

    /* ข้อเสีย: ข้อมูล tab ที่ซ่อนอยู่จะหยุดอัพเดท */
    /* ข้อดี: ลด CPU load 50% (อ่าน sensor 1 ตัวแทน 2 ตัว) */
}
```

#### 5.5 Tab Content Styling Tips

```c
/* ตั้งสีพื้นหลัง tab content เป็นสีขาว */
lv_obj_set_style_bg_color(tab, lv_color_hex(0xFFFFFF), 0);
lv_obj_set_style_bg_opa(tab, LV_OPA_COVER, 0);

/* ปิด scrolling - สำคัญมาก! */
lv_obj_remove_flag(lv_tabview_get_content(tabview),
                   LV_OBJ_FLAG_SCROLLABLE);

/* ถ้าต้องการปิด scroll เฉพาะ tab: */
lv_obj_remove_flag(tab_imu, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_remove_flag(tab_adc, LV_OBJ_FLAG_SCROLLABLE);
```

***

### 6. แบบฝึกหัด

#### Exercise 1: Min/Max Tracking

**โจทย์:** เพิ่มระบบ Min/Max Tracking สำหรับแต่ละ sensor:

**Requirements:**

* สำหรับ ADC: แสดง Min voltage, Max voltage, Current voltage
* สำหรับ IMU: แสดง Min/Max ของแต่ละแกน (X, Y, Z)
* เพิ่มปุ่ม "Reset" เพื่อ clear ค่า min/max
* แสดงเป็น label ใต้ widget หลัก

**Layout:**

```bash
ADC Tab:
  [Arc Gauge]
  [Bar]
  Current: 1.65V  |  Min: 0.12V  |  Max: 3.28V
  [RESET]

IMU Tab:
  [Chart]
  X: +0.50 | Min:-0.82 | Max:+0.91
  Y: -0.30 | Min:-0.65 | Max:+0.48
  Z: +9.81 | Min:+9.52 | Max:+10.12
```

**การประยุกต์ใช้งานจริง:**

* Quality Control: ตรวจสอบว่าค่า sensor อยู่ในช่วงที่กำหนด
* Predictive Maintenance: ติดตาม peak values เพื่อวิเคราะห์สภาพเครื่องจักร
* Environmental Monitoring: บันทึกค่าสูงสุด/ต่ำสุดของอุณหภูมิ

**Hint:**

* ใช้ `static float min_x = FLT_MAX, max_x = -FLT_MAX;`
* ปุ่ม Reset: `lv_btn_create()` + event callback

***

#### Exercise 2: Data Logging Table

**โจทย์:** เพิ่ม Tab ที่ 3 "Log" แสดงข้อมูล 10 readings ล่าสุดในรูปแบบตาราง:

**Requirements:**

* ใช้ `lv_table_create()` สร้างตาราง
* 4 คอลัมน์: Time, ADC, Accel X, Accel Z
* 10 แถว (circular buffer - เมื่อครบ 10 แถวให้เริ่มเขียนทับแถวเก่า)
* บันทึกค่าทุก 1 วินาที (ไม่ใช่ทุก 100ms)
* แถวล่าสุดแสดงด้วยสีพื้นหลังเด่น

**Layout:**

```bash
Log Tab:
  | Time  | ADC  | X(m/s2) | Z(m/s2) |
  |-------|------|---------|---------|
  | 00:01 | 2048 |  +0.50  |  +9.81  |
  | 00:02 | 1825 |  +0.32  |  +9.79  |
  | ...   | ...  |   ...   |   ...   |
  | 00:10 | 3012 |  -0.15  |  +9.85  |
```

**การประยุกต์ใช้งานจริง:**

* Data Logger ในอุตสาหกรรมอาหาร (บันทึกอุณหภูมิห้องเย็น)
* Flight Data Recorder (บันทึกข้อมูลระหว่างบิน)
* Process Control: บันทึกค่า parameter ย้อนหลัง

**Hint:**

* `lv_table_set_cell_value(table, row, col, "text")`
* Circular buffer: `write_idx = (write_idx + 1) % 10`
* Time format: \`lv\_label\_set\_text\_fmt(label, "%02d:%02d", min, sec)

***

### 7. References

* [LVGL TabView](https://docs.lvgl.io/9.2/widgets/tabview.html)
* [LVGL Arc](https://docs.lvgl.io/9.2/widgets/arc.html)
* [lv\_example\_tabview\_2](https://github.com/lvgl/lvgl/blob/release/v9.2/examples/widgets/tabview/lv_example_tabview_2.c)

***


---

# 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/sensor-to-hmi-display/hardware-interfacing-workshops/sensor-dashboard.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.
