# พื้นฐาน Embedded C - ตอนที่ 2

### ทำไมต้องเรียน Struct, Array, Pointer?

**Struct, Array, และ Pointer คือหัวใจของ Embedded IoT Programming:**

1. **Sensor Data Management**: จัดเก็บข้อมูล multi-axis sensors (IMU: 6-axis, 9-axis)
2. **Efficient Communication**: ส่งข้อมูลหลายค่าพร้อมกัน (I2C, SPI, UART)
3. **Memory Efficiency**: Pass by pointer ประหยัด RAM และ CPU time
4. **Buffering**: Circular buffers สำหรับ ADC, audio streaming
5. **Hardware Abstraction**: Struct-based driver architecture

**Real Applications:**

* **Wearable**: เก็บข้อมูล heart rate, steps, calories ใน array
* **Motion Detection**: IMU data (accel + gyro) organized ใน struct
* **Environmental Monitoring**: Temperature, humidity, pressure arrays
* **Edge AI**: Input features เป็น float arrays ส่งเข้า ML model

```
┌─────────────────────────────────────────────────────────────────┐
│                 Sensor Data Processing Flow                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Sensor    →   Raw Data   →   Process    →   Result            │
│   (BMI270)      (bytes)        (compute)      (decision)        │
│                                                                 │
│   ต้องใช้:                                                        │
│   - Structs: จัดกลุ่มข้อมูล X, Y, Z                                  │
│   - Pointers: ส่งข้อมูลไปฟังก์ชันอย่างมีประสิทธิภาพ                       │
│   - Arrays: เก็บ buffer สำหรับ filtering                          │
│   - Algorithms: magnitude, moving average, thresholding         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 1. Arrays (อาร์เรย์)

#### 1.1 การประกาศและใช้งาน Array

```c
/* Array declaration */
int numbers[5];                     /* Uninitialized array of 5 ints */
int values[5] = {1, 2, 3, 4, 5};   /* Initialized array */
int zeros[10] = {0};               /* All elements = 0 */
char name[] = "PSoC";              /* String (char array) */

/* Access elements (0-indexed) */
int first = values[0];   /* 1 */
int last = values[4];    /* 5 */
values[2] = 100;         /* Modify element */

/* Array size */
#define ARRAY_SIZE(arr)  (sizeof(arr) / sizeof((arr)[0]))
size_t len = ARRAY_SIZE(values);  /* len = 5 */
```

#### 1.2 Multi-dimensional Arrays

```c
/* 2D array (matrix) */
int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

/* Access element at row 1, column 2 */
int val = matrix[1][2];  /* 7 */

/* Iterate through 2D array */
for (int row = 0; row < 3; row++)
{
    for (int col = 0; col < 4; col++)
    {
        printf("%d ", matrix[row][col]);
    }
    printf("\r\n");
}
```

#### 1.3 Array ใช้กับ Sensor Data

```c
/* Buffer for sensor readings */
#define SAMPLE_COUNT    100

int16_t sensor_buffer[SAMPLE_COUNT];
uint32_t buffer_index = 0;

/* Add sample to buffer */
void add_sample(int16_t sample)
{
    sensor_buffer[buffer_index] = sample;
    buffer_index++;

    if (buffer_index >= SAMPLE_COUNT)
    {
        buffer_index = 0;  /* Circular buffer */
    }
}

/* Calculate average */
float calculate_average(void)
{
    int32_t sum = 0;
    for (int i = 0; i < SAMPLE_COUNT; i++)
    {
        sum += sensor_buffer[i];
    }
    return (float)sum / SAMPLE_COUNT;
}
```

***

### 2. Structures (โครงสร้าง)

#### ทำไมต้องใช้ Struct?

**ข้อดี:**

1. **Logical Grouping**: จัดกลุ่มข้อมูลที่เกี่ยวข้องกัน (X,Y,Z axes)
2. **Easy to Pass**: ส่งหลายค่าพร้อมกันในฟังก์ชันเดียว
3. **Self-documenting**: ชื่อ member บอกความหมายชัดเจน
4. **Memory Layout Control**: สามารถ pack เพื่อส่งผ่าน communication
5. **Driver Architecture**: มาตรฐานใน embedded drivers

```c
/* ❌ ปัญหา: ตัวแปรแยกกัน - ยากจัดการ */
int16_t acc_x, acc_y, acc_z;
int16_t gyr_x, gyr_y, gyr_z;
uint32_t timestamp;

/* ถ้าจะส่งไป function ต้องส่งทีละตัว! */
void process(int16_t ax, int16_t ay, int16_t az,
             int16_t gx, int16_t gy, int16_t gz,
             uint32_t time);  /* 7 parameters! */

/* ✓ ใช้ Struct: จัดกลุ่มข้อมูลที่เกี่ยวข้อง */
typedef struct {
    int16_t acc_x, acc_y, acc_z;
    int16_t gyr_x, gyr_y, gyr_z;
    uint32_t timestamp;
} imu_data_t;

void process(imu_data_t *data);  /* 1 parameter! */
```

#### 2.1 การประกาศ Struct

```c
/* วิธีที่ 1: struct tag */
struct sensor_data {
    int16_t x;
    int16_t y;
    int16_t z;
};

struct sensor_data my_sensor;  /* ต้องเขียน struct ทุกครั้ง */
my_sensor.x = 100;

/* วิธีที่ 2: typedef (แนะนำ) */
typedef struct {
    int16_t x;
    int16_t y;
    int16_t z;
} sensor_data_t;

sensor_data_t my_sensor;  /* ไม่ต้องเขียน struct */
my_sensor.x = 100;

/* Convention: ใช้ _t ต่อท้ายชื่อ typedef */
/* เช่น: imu_data_t, motion_state_t, filter_config_t */
```

#### 2.2 Nested Structs (Struct ซ้อน Struct)

```c
/* สร้าง struct ที่ใช้ซ้ำได้ */
typedef struct {
    float x;
    float y;
    float z;
} vector3f_t;

/* ใช้เป็น member ของ struct อื่น */
typedef struct {
    vector3f_t acceleration;   /* m/s² */
    vector3f_t gyroscope;      /* rad/s */
    vector3f_t magnetometer;   /* uT */
    float temperature;         /* °C */
    uint32_t timestamp_ms;
} sensor_fusion_t;

/* การใช้งาน */
sensor_fusion_t fusion;
fusion.acceleration.x = 0.0f;
fusion.acceleration.z = 9.81f;
fusion.temperature = 25.5f;
fusion.timestamp_ms = 1000;

/* คำนวณ magnitude */
float ax = fusion.acceleration.x;
float ay = fusion.acceleration.y;
float az = fusion.acceleration.z;
float mag = sqrtf(ax*ax + ay*ay + az*az);
```

#### 2.3 Struct Initialization

```c
/* วิธีที่ 1: ทีละ member */
imu_data_t data;
data.acc_x = 100;
data.acc_y = 200;
data.acc_z = 300;

/* วิธีที่ 2: Initializer list */
imu_data_t data = {100, 200, 300, 0, 0, 0, 0};
/* อันตราย! ต้องจำลำดับ member */

/* วิธีที่ 3: Designated initializers (แนะนำ!) */
imu_data_t data = {
    .acc_x = 100,
    .acc_y = 200,
    .acc_z = 300,
    .gyr_x = 0,
    .gyr_y = 0,
    .gyr_z = 0,
    .timestamp = 0
};

/* วิธีที่ 4: Zero initialize ทุก member */
imu_data_t data = {0};

/* จากโค้ดจริง - Interrupt config */
cy_stc_sysint_t intrCfg = {
    .intrSrc = CYBSP_USER_BTN_IRQ,
    .intrPriority = GPIO_INTERRUPT_PRIORITY
};
```

#### 2.4 ขนาดของ Struct และ Padding

```c
typedef struct {
    uint8_t  a;    /* 1 byte */
    uint32_t b;    /* 4 bytes */
    uint8_t  c;    /* 1 byte */
} bad_layout_t;

/* คิดว่า size = 1 + 4 + 1 = 6 bytes? */
/* ผิด! size อาจเป็น 12 bytes เพราะ padding */

/*
Memory layout:
a:       [X] [ ] [ ] [ ]    (1 byte + 3 padding)
b:       [X] [X] [X] [X]    (4 bytes, aligned)
c:       [X] [ ] [ ] [ ]    (1 byte + 3 padding)
Total:   12 bytes
*/

/* ✓ จัดเรียงใหม่ให้ประหยัด */
typedef struct {
    uint32_t b;    /* 4 bytes */
    uint8_t  a;    /* 1 byte */
    uint8_t  c;    /* 1 byte */
    /* padding: 2 bytes */
} better_layout_t;  /* size = 8 bytes */

/* ตรวจสอบ size */
printf("Size: %zu bytes\n", sizeof(better_layout_t));
```

#### 2.5 Packed Structs (for communication)

```c
/* Packed struct - no padding between members */
typedef struct __attribute__((packed)) {
    uint8_t header;
    uint16_t length;
    uint8_t data[10];
    uint16_t checksum;
} packet_t;

/* Size is exactly sum of members */
/* sizeof(packet_t) = 1 + 2 + 10 + 2 = 15 bytes */
```

***

### 3. Pointers (พอยน์เตอร์)

#### 3.1 พื้นฐาน Pointer

```c
int value = 42;
int *ptr;           /* Declare pointer to int */

ptr = &value;       /* ptr now points to value (& = address of) */

printf("value = %d\r\n", value);       /* 42 */
printf("&value = %p\r\n", &value);     /* Address of value */
printf("ptr = %p\r\n", ptr);           /* Same address */
printf("*ptr = %d\r\n", *ptr);         /* 42 (* = dereference) */

*ptr = 100;         /* Modify value through pointer */
printf("value = %d\r\n", value);       /* 100 */
```

#### 3.2 Pointer และ Array

```c
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;       /* Array name is pointer to first element */

/* Access via pointer */
printf("%d\r\n", *p);       /* 10 (arr[0]) */
printf("%d\r\n", *(p+1));   /* 20 (arr[1]) */
printf("%d\r\n", *(p+2));   /* 30 (arr[2]) */

/* Pointer arithmetic */
p++;                /* Move to next element */
printf("%d\r\n", *p);       /* 20 */

/* Array notation vs pointer notation */
arr[3] == *(arr + 3)  /* Both access 4th element */
```

#### 3.3 ทำไม Embedded ใช้ Pointer เยอะ?

```c
/* เหตุผลหลัก 3 ข้อ: */

/* 1. Efficiency - ประหยัด memory และเร็วกว่า */
typedef struct {
    float data[1000];  /* 4000 bytes! */
} big_struct_t;

/* ❌ Pass by value: copy 4000 bytes ทุกครั้ง */
void process_slow(big_struct_t data);

/* ✓ Pass by pointer: copy 4 bytes (address) */
void process_fast(big_struct_t *data);

/* 2. Modify caller's variable */
void read_sensor(int16_t *result)
{
    *result = 1234;  /* เขียนค่ากลับไปยัง caller */
}

int16_t value;
read_sensor(&value);  /* value = 1234 */

/* 3. Hardware access - memory-mapped I/O */
volatile uint32_t *GPIO_REG = (volatile uint32_t *)0x40000000;
*GPIO_REG = 0x01;  /* Write to hardware register */
```

#### 3.4 Pointer to Struct

```c
imu_data_t data = {100, 200, 300, 10, 20, 30};
imu_data_t *data_ptr = &data;

/* Access members via pointer */
/* Method 1: Dereference then access */
(*data_ptr).acc_x = 500;

/* Method 2: Arrow operator (preferred) */
data_ptr->acc_y = 600;
data_ptr->timestamp = get_tick();

printf("X: %d, Y: %d\r\n", data_ptr->acc_x, data_ptr->acc_y);
```

#### 3.5 Passing Struct to Function

```c
/* Pass by value (copies entire struct - slow for large structs) */
void print_data_copy(imu_data_t data)
{
    printf("Acc: %d, %d, %d\r\n", data.acc_x, data.acc_y, data.acc_z);
}

/* Pass by pointer (efficient - only copies address) */
void print_data_ptr(imu_data_t *data)
{
    printf("Acc: %d, %d, %d\r\n", data->acc_x, data->acc_y, data->acc_z);
}

/* Pass by const pointer (cannot modify) */
void print_data_const(const imu_data_t *data)
{
    printf("Acc: %d, %d, %d\r\n", data->acc_x, data->acc_y, data->acc_z);
    /* data->acc_x = 0;  // ERROR: cannot modify const */
}

/* Usage */
imu_data_t sensor;
print_data_copy(sensor);    /* Copies 12 bytes */
print_data_ptr(&sensor);    /* Copies 4 bytes (pointer size) */
print_data_const(&sensor);  /* Safe read-only access */
```

#### 3.6 Function Pointer (Callback)

```c
/* Define function pointer type */
typedef void (*button_callback_t)(void);

/* Callback function */
void on_button_press(void)
{
    printf("Button pressed!\r\n");
    cyhal_gpio_toggle(CYBSP_USER_LED);
}

/* Register callback */
button_callback_t registered_callback = NULL;

void register_button_callback(button_callback_t callback)
{
    registered_callback = callback;
}

/* Call the callback */
void button_interrupt_handler(void)
{
    if (registered_callback != NULL)
    {
        registered_callback();
    }
}

/* Usage */
register_button_callback(on_button_press);
```

### 4. Arrays และ Buffers

#### 4.1 Array Basics

```c
/* Declaration */
int16_t samples[100];           /* 100 elements, uninitialized */
float buffer[10] = {0};         /* 10 elements, all zeros */
int values[5] = {1, 2, 3, 4, 5}; /* 5 elements with values */

/* Access (0-indexed) */
samples[0] = 100;   /* First element */
samples[99] = 200;  /* Last element */
/* samples[100] = ?; ❌ Out of bounds! Undefined behavior */

/* Array size */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
size_t len = ARRAY_SIZE(samples);  /* len = 100 */
```

#### 4.2 Array และ Pointer ความสัมพันธ์

```c
int arr[5] = {10, 20, 30, 40, 50};

/* Array name = pointer to first element */
int *ptr = arr;  /* เหมือน: int *ptr = &arr[0]; */

/* Access via index vs pointer arithmetic */
arr[0]    == *ptr        /* 10 */
arr[1]    == *(ptr + 1)  /* 20 */
arr[2]    == *(ptr + 2)  /* 30 */

/* ในทางกลับกัน */
ptr[0]    == arr[0]      /* 10 */
ptr[1]    == arr[1]      /* 20 */

/* Pointer arithmetic: +1 = เลื่อนไป sizeof(type) bytes */
/* ถ้า int = 4 bytes, ptr + 1 = address + 4 bytes */
```

#### 4.3 Circular Buffer

```c
/*
 * Circular Buffer: ใช้เก็บข้อมูลแบบวนรอบ
 * เหมาะสำหรับ: Sensor data, Moving average, FIFO
 */

#define BUFFER_SIZE 10

typedef struct {
    float data[BUFFER_SIZE];
    uint32_t head;      /* ตำแหน่งที่จะเขียนถัดไป */
    uint32_t count;     /* จำนวนข้อมูลปัจจุบัน */
} circular_buffer_t;

void buffer_init(circular_buffer_t *buf)
{
    memset(buf, 0, sizeof(circular_buffer_t));
}

void buffer_push(circular_buffer_t *buf, float value)
{
    buf->data[buf->head] = value;
    buf->head = (buf->head + 1) % BUFFER_SIZE;  /* Wrap around */

    if (buf->count < BUFFER_SIZE)
    {
        buf->count++;
    }
}

/*
 * Example: Push values 1, 2, 3, 4, 5
 *
 * After push(1): [1, _, _, _, _, _, _, _, _, _] head=1, count=1
 * After push(2): [1, 2, _, _, _, _, _, _, _, _] head=2, count=2
 * ...
 * After push(10):[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] head=0, count=10
 * After push(11):[11,2, 3, 4, 5, 6, 7, 8, 9, 10] head=1, count=10
 *                 ↑ overwrites oldest (1)
 */
```


---

# 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/sensor-interfacing/embedded-c-2.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.
