# C in ModusToolBox (MTB)

## 1. โครงสร้างโปรแกรม C ใน ModusToolbox

### <mark style="color:blue;">1.1 Header Files และ Include</mark>

การจัดการ `#include` ให้เป็นระบบเป็นพื้นฐานที่สำคัญมากในการเขียน Embedded C\
โดยเฉพาะบน **Infineon PSoC™ Edge E84** ที่ใช้ ModusToolbox ซึ่งมีทั้ง HAL, BSP และ Peripheral Driver Library (PDL)

การจัดกลุ่ม header ที่ดี จะช่วยให้:

* โค้ดอ่านง่ายและดูเป็นมืออาชีพ
* ลดการพึ่งพาไฟล์ที่ไม่จำเป็น
* ลดโอกาสเกิดปัญหา compile และ dependency ที่ซับซ้อนในอนาคต

***

{% hint style="info" %}

#### แนวคิด (Concept)

ใน ModusToolbox ควรแบ่ง `#include` ออกเป็น **2 กลุ่มหลัก** อย่างชัดเจน:

1. **System headers**\
   เป็น header จาก C standard library ใช้กับภาษา C ทั่วไป
2. **Infineon / PSoC platform headers**\
   เป็น header ที่เกี่ยวข้องกับ hardware, board และ middleware ของ Infineon

การเรียงลำดับที่แนะนำคือ\
👉 *System headers ก่อน* → *Platform headers ตามหลัง*
{% endhint %}

***

#### ตัวอย่างโครงสร้าง `#include` ที่แนะนำ

```c
/* ===================== System headers ===================== */
#include <stdio.h>      /* printf */
#include <stdint.h>     /* uint32_t, int16_t */
#include <stdbool.h>    /* bool, true, false */
#include <string.h>     /* memcpy, strlen */

/* ================= Infineon / PSoC headers ================= */
#include "cy_pdl.h"         /* Peripheral Driver Library */
#include "cyhal.h"          /* Hardware Abstraction Layer */
#include "cybsp.h"          /* Board Support Package */
#include "cy_retarget_io.h" /* UART printf redirection */
```

***

#### Best Practice

* Include เฉพาะ header ที่ใช้งานจริงเท่านั้น
* แยกกลุ่ม System กับ Platform ให้ชัดเจนเสมอ
* อย่า include header ซ้ำซ้อนโดยไม่จำเป็น
* หลีกเลี่ยงการ include header ใน `.h` ถ้าไม่จำเป็น (ควร include ใน `.c` แทน)

***

{% hint style="warning" %}

#### **ข้อควรระวัง (Pitfall)**

* การ include header จำนวนมากเกินไป อาจทำให้
  * compile time เพิ่มขึ้น
  * dependency ซับซ้อน
  * เกิด warning หรือ error ที่ debug ยาก
* การ include header ในลำดับที่ไม่เหมาะสม อาจทำให้ macro หรือ type ชนกันได้
  {% endhint %}

***

#### 📘 MISRA-C Note (สำหรับงานอุตสาหกรรม)

* MISRA-C แนะนำให้ include header เท่าที่จำเป็นเท่านั้น
* Header ควรมี include guard หรือ `#pragma once`
* หลีกเลี่ยงการ include header ที่มี side effect (เช่น มี code execution)

***

**สรุปสั้น ๆ**

> การจัด `#include` ที่ดี คือจุดเริ่มต้นของ firmware ที่ดูแลรักษาง่าย และขยายต่อได้ในระยะยาว

### <mark style="color:blue;">1.2 Simple Define (</mark><mark style="color:blue;">`#define`</mark> <mark style="color:blue;"></mark><mark style="color:blue;">สำหรับค่าคงที่)</mark>

การใช้ `#define` สำหรับกำหนดค่าคงที่ (constant) เป็นสิ่งที่พบได้บ่อยมากในงาน Embedded C\
โดยเฉพาะบน **PSoC™ Edge E84** ที่ต้องจัดการกับ GPIO, communication, sensor และ hardware configuration จำนวนมาก

หากใช้ `#define` อย่างเป็นระบบ จะช่วยให้โค้ด:

* อ่านง่าย
* แก้ไขง่าย
* ลด bug จากการใช้ magic number

***

{% hint style="info" %}

#### แนวคิด (Concept)

`#define` เหมาะสำหรับ:

* ค่าคงที่ที่ **ไม่เปลี่ยนระหว่าง runtime**
* ค่า configuration ที่เกี่ยวข้องกับ hardware
* ค่า parameter ที่ต้องใช้ซ้ำหลายจุดในโค้ด

ชื่อของ macro ควร:

* ใช้ **ตัวพิมพ์ใหญ่ทั้งหมด**
* ใช้ `_` คั่นคำ
* สื่อความหมายชัดเจน
  {% endhint %}

***

#### ตัวอย่าง Simple Define พื้นฐาน

**GPIO Pin Configuration**

(ตัวอย่างจาก hello-world project)

```c
#define LED_PIN        CYBSP_USER_LED
#define BUTTON_PIN     CYBSP_USER_BTN
```

***

**Communication Settings**

```c
#define UART_BAUDRATE  115200
#define I2C_FREQUENCY  400000U   /* 400 kHz */
```

***

**Sensor Configuration**

(ตัวอย่างจาก BMI270 driver)

```c
#define SAMPLE_RATE_HZ    100
#define IMU_I2C_ADDRESS  0x68
#define BUFFER_SIZE      256
```

***

**Application Constants**

```c
#define MAX_RETRIES       3
#define TIMEOUT_MS        5000
#define LED_BLINK_DELAY   500
```

***

#### ตัวอย่างจากโค้ดจริงของ Infineon

**จาก `ml-deepcraft-data-collection`**

```c
#define MAX_FRAMES_IN_CHUNK   (8U)      /* 400Hz / 8 = 50Hz */
#define AXIS_COUNT            (3U)      /* X, Y, Z */
#define SENSOR_COUNT          (2U)      /* Accel, Gyro */
#define GRAVITY_EARTH         (9.80665f)/* m/s^2 */
```

***

**Accelerometer Ranges (BMI270)**

```c
#define IMU_ACC_RANGE_2G      0x4000
#define IMU_ACC_RANGE_4G      0x2000
#define IMU_ACC_RANGE_8G      0x1000
#define IMU_ACC_RANGE_16G     0x0800
```

***

**Gyroscope Conversion Factors**

```c
#define IMU_GYRO_DIVIDE_125   262.0f   /* ±125 dps */
#define IMU_GYRO_DIVIDE_250   131.0f   /* ±250 dps */
#define IMU_GYRO_DIVIDE_500   65.5f    /* ±500 dps */
```

***

**ตัวอย่างจาก `wifi-udp-server`**

```c
#define UDP_LED_CMD_LEN          (1U)
#define LED_ON_CMD               ('1')
#define LED_OFF_CMD              ('0')
#define MAX_UDP_RECV_BUFFER_SIZE (20U)

#define SHIFT_BIT_8              (8U)
#define SHIFT_BIT_16             (16U)
#define SHIFT_BIT_24             (24U)

#define APP_SDIO_FREQUENCY_HZ    (25000000U) /* 25 MHz */
#define SDHC_SDIO_64BYTES_BLOCK  (64U)
```

***

#### Best Practice

* ใช้ `U`, `UL`, `f` ให้เหมาะกับชนิดข้อมูล (type)
* หลีกเลี่ยง magic number ในโค้ด
* ใช้ชื่อ macro ที่อธิบายความหมายได้ด้วยตัวมันเอง
* กลุ่ม macro ตามหน้าที่ (GPIO / Sensor / Network / App)

***

{% hint style="warning" %}

#### **ข้อควรระวัง (Pitfall)**

* การไม่ระบุ suffix (`U`, `f`) อาจทำให้เกิด type mismatch
* Macro ที่ชื่อไม่ชัดเจน จะทำให้โค้ดอ่านยากในระยะยาว
* การใช้ค่าคงที่ฝังในโค้ด (hard-coded) ทำให้แก้ไขยาก
  {% endhint %}

***

#### 📘 MISRA-C Note (สำหรับงานอุตสาหกรรม)

* MISRA-C อนุญาตให้ใช้ `#define` สำหรับ constant
* ควรหลีกเลี่ยง `#define` ที่ซับซ้อนหรือมี logic
* ค่าคงที่ที่เป็นกลุ่มเดียวกัน ควรถูกรวมไว้ใน header เดียว

***

**สรุปสั้น ๆ**

> ใช้ `#define` เพื่อแทนค่าคงที่เท่านั้น\
> ถ้าเริ่มมี logic → พิจารณาใช้ `static inline function` แทน

### <mark style="color:blue;">1.3 การใช้งานจริงของ Function-like Macros</mark>

Function-like macro เป็นเครื่องมือที่ถูกใช้บ่อยมากในงาน Embedded C\
โดยเฉพาะงานที่เกี่ยวข้องกับ **register control, sensor data processing และ performance-critical code**

อย่างไรก็ตาม macro ประเภทนี้ก็เป็นหนึ่งในแหล่งกำเนิด bug ที่พบบ่อยที่สุดเช่นกัน\
หากไม่เข้าใจข้อจำกัดและใช้งานอย่างระมัดระวัง

***

{% hint style="info" %}

#### **แนวคิด (Concept)**

Function-like macro คือ macro ที่มีลักษณะเหมือน function แต่ถูกแทนค่าตั้งแต่ขั้นตอน preprocessing\
จึง **ไม่มี type checking** และ **ไม่มีการป้องกัน side effect**

จุดเด่นคือ:

* เร็ว (ไม่มี function call overhead)
* ใช้กับ type ใดก็ได้ (type-generic)
* เหมาะกับ logic สั้น ๆ
  {% endhint %}

***

#### ตัวอย่าง Function-like Macros ที่ใช้บ่อย

```c
/* Min / Max macros - Generic for any type */
#define MIN(a, b)    ((a) < (b) ? (a) : (b))
#define MAX(a, b)    ((a) > (b) ? (a) : (b))

/* Clamp value to range - Limit sensor values */
#define CLAMP(val, min, max)  (MIN(MAX((val), (min)), (max)))

/* Bit manipulation macros - Register control */
#define BIT_SET(reg, bit)     ((reg) |=  (1U << (bit)))
#define BIT_CLEAR(reg, bit)   ((reg) &= ~(1U << (bit)))
#define BIT_TOGGLE(reg, bit)  ((reg) ^=  (1U << (bit)))
#define BIT_CHECK(reg, bit)   (((reg) >> (bit)) & 1U)

/* Array size macro - Prevent buffer overrun */
#define ARRAY_SIZE(arr)       (sizeof(arr) / sizeof((arr)[0]))

/* Unit conversion macros */
#define MS_TO_TICKS(ms)       ((ms) * configTICK_RATE_HZ / 1000U)
#define DEG_TO_RAD(deg)       ((deg) * 3.14159f / 180.0f)
#define CELSIUS_TO_F(c)       ((c) * 9.0f / 5.0f + 32.0f)
```

***

#### ตัวอย่างการใช้งานจริง (Real-world Usage)

**Sensor data validation**

```c
int16_t sensor_raw = read_sensor();
int16_t sensor_clamped = CLAMP(sensor_raw, -2000, 2000);
```

***

**Array iteration (ป้องกัน out-of-bounds)**

```c
int adc_readings[100];
size_t count = ARRAY_SIZE(adc_readings);

for (size_t i = 0; i < count; i++)
{
    process_reading(adc_readings[i]);
}
```

***

**GPIO register manipulation**

```c
uint32_t gpio_reg = 0;

BIT_SET(gpio_reg, 5);      /* Enable pin */
BIT_CLEAR(gpio_reg, 3);    /* Disable interrupt */

if (BIT_CHECK(gpio_reg, 5))
{
    printf("Pin 5 is HIGH\n");
}
```

***

**Temperature range limit**

```c
float temp = read_temperature();
float temp_limited = CLAMP(temp, -40.0f, 85.0f);
```

***

**FreeRTOS delay conversion**

```c
vTaskDelay(MS_TO_TICKS(100));   /* Delay 100 ms */
```

***

#### ตัวอย่างจากโค้ดจริงของ Infineon (IMU)

```c
#if IMU_SAMPLE_RANGE == BMI2_ACC_RANGE_2G
    #define IMU_ACC_DIVIDE  0x4000  /* 16384 */
#elif IMU_SAMPLE_RANGE == BMI2_ACC_RANGE_4G
    #define IMU_ACC_DIVIDE  0x2000  /* 8192 */
#elif IMU_SAMPLE_RANGE == BMI2_ACC_RANGE_8G
    #define IMU_ACC_DIVIDE  0x1000  /* 4096 */
#elif IMU_SAMPLE_RANGE == BMI2_ACC_RANGE_16G
    #define IMU_ACC_DIVIDE  0x0800  /* 2048 */
#endif
```

```c
#define IMU_INTR_MASK  (0x00000001UL << CYBSP_IMU_INT1_PORT_NUM)

#if defined(IMU_ACC) && defined(IMU_GYR)
    #define IMU_NUM_AXIS  (6U)   /* 3 accel + 3 gyro */
#else
    #define IMU_NUM_AXIS  (3U)   /* Only accel or gyro */
#endif
```

***

#### Best Practice

* ใส่วงเล็บรอบ **ทุก parameter และทุก expression**
* ใช้ macro กับ logic **สั้นและชัดเจนเท่านั้น**
* ใช้ชื่อ macro เป็น **ตัวพิมพ์ใหญ่ทั้งหมด**
* ใช้ macro สำหรับ register / bit manipulation จะเหมาะที่สุด

***

{% hint style="warning" %}

#### **ข้อควรระวัง (Pitfall)**

**❌ Side effect**

```c
#define MAX(a, b)  ((a) > (b) ? (a) : (b))

int x = 5;
int result = MAX(x++, 10);   /* x ถูกเพิ่มสองครั้ง */
```

**❌ Multi-statement macro ที่ไม่ใช้ `do { } while(0)`**

```c
#define LOG_ERROR(msg) printf("Error: %s\n", msg); error_count++
```

```c
if (failed)
    LOG_ERROR("Init failed");   /* error_count++ ทำงานเสมอ */
```

***

**✅ รูปแบบที่ถูกต้อง**

```c
#define LOG_ERROR(msg) do { \
    printf("Error: %s\n", msg); \
    error_count++; \
} while(0)
```

{% endhint %}

***

#### ⚖️ Macro vs Inline Function

| Aspect      | Macro       | Inline Function |
| ----------- | ----------- | --------------- |
| Type safety | ❌ No        | ✅ Yes           |
| Debugging   | ❌ Hard      | ✅ Easy          |
| Side effect | ❌ Dangerous | ✅ Safe          |
| Performance | ✅ Fast      | ✅ Fast          |

***

#### 📘 MISRA-C Note (สำหรับงานอุตสาหกรรม)

* MISRA-C แนะนำให้ **หลีกเลี่ยง function-like macro**
* อนุญาตเฉพาะ macro ที่:
  * ไม่มี side effect
  * ใช้กับ constant หรือ register
* Logic ที่ซับซ้อนควรใช้ `static inline function` แทน

```c
static inline int calculate_checksum(uint8_t *data, size_t len)
{
    int sum = 0;
    for (size_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    return (sum & 0xFF);
}
```

***

**สรุปสั้น ๆ**

> Function-like macro ทรงพลัง แต่ก็อันตราย\
> ถ้าเริ่มคิดนาน → อย่าใช้ macro

### <mark style="color:blue;">1.4 โครงสร้าง</mark> <mark style="color:blue;"></mark><mark style="color:blue;">`main()`</mark> <mark style="color:blue;"></mark><mark style="color:blue;">ที่แนะนำสำหรับ PSoC™ Edge E84</mark>

ฟังก์ชัน `main()` คือจุดเริ่มต้นของทุกโปรแกรม C\
ในงาน Embedded โดยเฉพาะบน **Infineon PSoC™ Edge E84**\
การจัดโครงสร้าง `main()` ให้ถูกต้องตั้งแต่ต้น จะช่วยให้ระบบ:

* ทำงานเสถียร
* ประหยัดพลังงาน
* Debug และขยายระบบได้ง่ายในอนาคต

***

{% hint style="info" %}

#### **แนวคิด (Concept)**

`main()` ในระบบ Embedded **ไม่ใช่โปรแกรมที่จบแล้ว exit**\
แต่เป็นจุดที่:

1. Initialize hardware และ system
2. Enable interrupt
3. เข้าสู่ main loop ที่ทำงานตลอดอายุของอุปกรณ์

ใน ModusToolbox โครงสร้าง `main()` ที่ดีควร:

* แยกขั้นตอน init อย่างชัดเจน
* ตรวจสอบ error ทุกครั้งที่ init
* รองรับ **Low power operation**
  {% endhint %}

***

#### โครงสร้าง `main()` พื้นฐานที่แนะนำ

```c
int main(void)
{
    cy_rslt_t result;

    /* 1. Initialize board and peripherals */
    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        /* Critical error: stop execution */
        CY_ASSERT(0);
    }

    /* 2. Enable global interrupts */
    __enable_irq();

    /* 3. Initialize debug UART (optional) */
    cy_retarget_io_init(CYBSP_DEBUG_UART_TX,
                         CYBSP_DEBUG_UART_RX,
                         CY_RETARGET_IO_BAUDRATE);

    /* 4. Application-specific initialization */
    app_init();

    /* 5. Main loop */
    for (;;)
    {
        app_task();

        /* Enter deep sleep to save power */
        Cy_SysPm_CpuEnterDeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT);
    }
}
```

***

#### คำอธิบายแต่ละขั้นตอน

**1. `cybsp_init()`**

* Initialize clock, pins, peripherals ตาม BSP
* ต้อง **check return value เสมอ**
* ถ้าล้มเหลว → ระบบไม่ควรทำงานต่อ

**2. `__enable_irq()`**

* เปิด global interrupt
* ต้องเรียกหลังจาก init hardware เสร็จแล้ว
* ถ้าลืมเรียก → interrupt ทั้งระบบจะไม่ทำงาน

**3. `cy_retarget_io_init()` (optional)**

* ใช้ redirect `printf()` ไปที่ UART
* เหมาะสำหรับ debug / development
* ไม่จำเป็นใน production build เสมอไป

**4. Application Init / Task**

* ควรแยก logic ออกเป็น function
* หลีกเลี่ยงการเขียน code ยาว ๆ ใน `main()`

***

#### ตัวอย่างจริงจาก Infineon (hello-world project)

```c
/* From: mtb-example-psoc-edge-hello-world/proj_cm55/main.c */

int main(void)
{
    cy_rslt_t result;

    /* Initialize the device and board peripherals */
    result = cybsp_init();

    /* Board init failed. Stop program execution */
    if (CY_RSLT_SUCCESS != result)
    {
        __disable_irq();
        CY_ASSERT(0);
    }

    /* Enable global interrupts */
    __enable_irq();

    /* Put the CPU to Deep Sleep - saves power */
    for (;;)
    {
        Cy_SysPm_CpuEnterDeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT);
    }
}
```

***

#### Best Practice

* ตรวจสอบ return value ของ `cybsp_init()` ทุกครั้ง
* เรียก `__enable_irq()` หลัง init เสมอ
* แยก application logic ออกเป็น function (`app_init()`, `app_task()`)
* ใช้ **Deep Sleep** ใน main loop เมื่อไม่มีงาน

***

{% hint style="warning" %}

#### **ข้อควรระวัง (Pitfall)**

**❌ Loop เปล่า ๆ ที่ไม่ sleep**

```c
while (1)
{
    /* do nothing */
}
```

ผลลัพธ์:

* CPU ใช้งาน 100%
* เปลืองพลังงาน
* แบตเตอรี่หมดเร็วมาก

***

**❌ ลืม enable interrupt**

```c
cybsp_init();
/* forgot __enable_irq() */
```

ผลลัพธ์:

* Timer / UART / GPIO interrupt ไม่ทำงาน
* Debug ยากมาก
  {% endhint %}

***

#### 📘 MISRA-C Note (สำหรับงานอุตสาหกรรม)

* `main()` ต้องมี signature ชัดเจน (`int main(void)`)
* ไม่ควรมี code ที่ไม่ reachable
* Infinite loop เป็นสิ่งที่ **ยอมรับได้** ใน Embedded
* ควรหลีกเลี่ยง logic ซับซ้อนใน `main()`

***

#### สรุปสั้น ๆ

> `main()` ที่ดี\
> \= init ชัดเจน + check error + sleep เมื่อว่าง\
> คือหัวใจของ Embedded firmware ที่เสถียรและประหยัดพลังงาน

### <mark style="color:blue;">1.5 ANSI Escape Sequence สำหรับ Console Debug</mark>

ในระหว่างการพัฒนา Embedded firmware นักพัฒนามักใช้ `printf()` ผ่าน UART เพื่อ debug ค่า sensor, state machine หรือ system status

**ANSI Escape Sequence** คือชุดรหัสควบคุมพิเศษ\
ที่ทำให้ terminal สามารถ:

* ล้างหน้าจอ
* ย้ายตำแหน่ง cursor
* เปลี่ยนสีตัวอักษร
* จัด layout ข้อมูลแบบ real-time

ซึ่งมีประโยชน์มากในช่วง **development & debugging**

{% hint style="info" %}

#### **แนวคิด (Concept)**

ANSI Escape Sequence เป็น string ที่ขึ้นต้นด้วย **ESC character (ASCII 27)**\
ในภาษา C เขียนเป็น:

```c
\x1b
```

รูปแบบทั่วไป:

```
ESC [ <command>
```

ตัวอย่าง:

```c
\x1b[2J    // Clear screen
\x1b[H     // Move cursor to home
```

> Terminal ที่รองรับ: **Tera Term, PuTTY, Linux terminal**\
> Terminal ที่อาจไม่รองรับ: บาง Serial Monitor แบบง่าย
> {% endhint %}

```c
printf("\x1b[2J\x1b[;H");
//      ───┬─── ───┬───
//         │       │
//         │       └─ [;H = Move cursor to home (0,0)
//         └──────── [2J = Clear entire screen

// \x1b = ESC character (ASCII 27)
// ทำให้ terminal ล้างหน้าจอก่อนแสดงข้อความ
// ถ้าใช้ Tera Term หรือ PuTTY จะเห็นผล
// แต่ถ้าใช้ terminal ไม่รองรับ จะเห็นขยะ
```

***

#### ตัวอย่างพื้นฐานที่ใช้บ่อยที่สุด

**ล้างหน้าจอ + ย้าย cursor กลับจุดเริ่มต้น**

```c
printf("\x1b[2J\x1b[H");
```

อธิบาย:

```c
\x1b       // ESC character
[2J        // Clear entire screen
[H         // Move cursor to (0,0)
```

***

#### ตัวอย่างการใช้งานจริง (Real-world Usage)

**แสดงค่า sensor แบบ refresh หน้าจอ**

```c
while (1)
{
    printf("\x1b[2J\x1b[H");   /* Clear screen */

    printf("Temperature: %.2f C\n", temperature);
    printf("Humidity   : %.2f %%\n", humidity);
    printf("Pressure   : %.2f hPa\n", pressure);

    Cy_SysLib_Delay(1000);
}
```

ผลลัพธ์:

* หน้าจอไม่เลื่อนยาว
* ดูเหมือน dashboard แบบ real-time

***

**เปลี่ยนสีข้อความ (optional)**

```c
printf("\x1b[31mERROR\x1b[0m\n");   /* Red text */
printf("\x1b[32mOK\x1b[0m\n");      /* Green text */
```

สีที่ใช้บ่อย:

* `31` = Red
* `32` = Green
* `33` = Yellow
* `34` = Blue
* `0` = Reset

***

#### ทำไม ANSI Escape ถึงเหมาะกับ Embedded Debug

* ไม่ต้องใช้ GUI
* ใช้ resource น้อย
* เหมาะกับ board ที่ไม่มีจอ
* Debug ได้ผ่าน UART ธรรมดา

เหมาะมากกับ:

* Sensor bring-up
* Power consumption debug
* State machine monitoring

***

#### Best Practice

* ใช้ ANSI Escape **เฉพาะใน debug build**
* แยก debug output ด้วย macro

```c
#ifdef DEBUG_CONSOLE
#define CLEAR_SCREEN()  printf("\x1b[2J\x1b[H")
#else
#define CLEAR_SCREEN()
#endif
```

* ใช้ร่วมกับ `Cy_SysLib_Delay()` หรือ sleep เพื่อลด UART spam

***

{% hint style="warning" %}

#### **ข้อควรระวัง (Pitfall)**

**❌ Terminal ไม่รองรับ**

ถ้า terminal ไม่รองรับ ANSI:

* จะเห็นเป็นตัวอักษรแปลก ๆ เช่น `[2J[H`

**❌ ใช้ใน production firmware**

* เปลือง flash
* เปลือง UART bandwidth
* ไม่เหมาะกับระบบที่ต้อง deterministic timing
  {% endhint %}

***

#### ⚖️ ANSI Escape vs GUI Debug

| Aspect           | ANSI Escape | GUI Tool |
| ---------------- | ----------- | -------- |
| Resource         | ต่ำมาก      | สูง      |
| Setup            | ง่าย        | ซับซ้อน  |
| Flexibility      | ปานกลาง     | สูง      |
| Production ready | ❌           | ✅        |

***

{% hint style="success" %}

#### **MISRA-C Note (สำหรับงานอุตสาหกรรม)**

* ANSI Escape เป็น **string literal** → ไม่ผิด MISRA โดยตรง
* แต่:
  * ไม่ควรใช้ใน production code
  * ควรถูก guard ด้วย macro (`#ifdef DEBUG`)
* หลีกเลี่ยงการใช้ `printf()` ใน timing-critical path
  {% endhint %}

***

#### สรุปสั้น ๆ

> ANSI Escape = เครื่องมือ debug ที่ดีมาก\
> แต่ควรใช้ **เฉพาะตอนพัฒนา**\
> ไม่ใช่ solution ระยะยาวสำหรับ production system

### <mark style="color:blue;">1.6 Coding Style จากโค้ดตัวอย่างจริงของ Infineon (Hello-world & MQTT Multi-tasking)</mark>

หัวข้อนี้เป็นการ **สรุปแนวทางการเขียน C ที่ Infineon ใช้จริง**\
โดยอ้างอิงจากตัวอย่างทางการ เช่น:

* `mtb-example-psoc-edge-hello-world`
* ตัวอย่าง IoT / MQTT client ที่ใช้ **FreeRTOS multi-tasking**

เป้าหมายไม่ใช่แค่ “โค้ดรันได้”\
แต่คือ **เขียนให้ตรง mindset ของ Infineon และงานอุตสาหกรรม**

***

#### โครงสร้างโปรเจกต์ (Project Structure Mindset)

{% hint style="info" %}

#### **แนวคิด (Concept)**

จากตัวอย่างจริงของ Infineon จะเห็น pattern ชัดเจนว่า:

* `main.c` → ทำหน้าที่ **orchestration**
* logic งานจริง → แยกเป็น module
* hardware config → มาจาก BSP / Config Tool
* middleware → จัดการผ่าน Library Manager

โค้ด **ไม่กระจุกอยู่ไฟล์เดียว**
{% endhint %}

#### โครงสร้างที่พบได้บ่อย

```
proj_cm55/
 ├── main.c
 ├── app.c
 ├── app.h
 ├── FreeRTOSConfig.h
 ├── bsp/
 ├── middleware/
 └── generated/
```

***

#### Best Practice

* `main.c` ไม่ควรยาว
* Application logic ควรอยู่ใน `app_xxx.c`
* Hardware-specific code ไม่ควรปนกับ business logic
* ให้ Config Tool เป็นเจ้าของไฟล์ config (ไม่แก้มือ)

***

{% hint style="warning" %}

#### Pitfall

❌ เขียน logic ทั้งหมดใน `main.c`\
❌ แก้ไฟล์ที่ auto-generated → พังตอน regenerate\
❌ module หนึ่งทำหลายหน้าที่
{% endhint %}

***

#### Pattern ของ `main()` จาก Hello-world (Bare-metal Style)

{% hint style="info" %}

#### แนวคิด (Concept)

จาก hello-world ของ Infineon\
`main()` มีหน้าที่ชัดเจน 3 อย่าง:

1. Initialize system
2. Enable interrupt
3. เข้าสู่ loop ที่ประหยัดพลังงาน
   {% endhint %}

***

#### Pattern ที่พบจริง

```c
int main(void)
{
    cy_rslt_t result;

    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        __disable_irq();
        CY_ASSERT(0);
    }

    __enable_irq();

    for (;;)
    {
        Cy_SysPm_CpuEnterDeepSleep(
            CY_SYSPM_WAIT_FOR_INTERRUPT);
    }
}
```

***

#### Best Practice

* check return value ทุกครั้ง
* error ร้ายแรง → หยุดระบบทันที
* idle loop ต้อง sleep เสมอ

***

#### MISRA-C Note

* Infinite loop ใน `main()` → ยอมรับได้
* หลีกเลี่ยง code ที่ unreachable
* `main()` ไม่ควรมี logic ซับซ้อน

***

#### สรุป 1.6

> ถ้าเขียนโค้ดให้ **โครงสร้างเหมือนตัวอย่างของ Infineon**\
> แปลว่าโค้ดคุณ “พร้อมต่อยอดเป็น production ได้จริง”

{% hint style="danger" %}

### Common Mistakes ที่ควรหลีกเลี่ยง

❌ เขียนทุกอย่างไว้ใน `main.c`\
❌ ไม่ check return value ของ init function\
❌ ใช้ macro แทน logic ที่ควรเป็น function\
❌ ใช้ printf เป็น logging หลักใน production\
❌ แก้ไฟล์ที่ Config Tool สร้างให้\
❌ ไม่คิดเรื่อง power consumption ตั้งแต่ต้น
{% endhint %}

***


---

# 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/basic-mcu-interfacing/c-in-modustoolbox-mtb.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.
