SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (MTB & µPython)
Loading...
Searching...
No Matches

Functions

void tacp_init (void)
 รีเซ็ต state machine, ล้าง ring, ระบาย FIFO; ครั้งเดียวต่อหนึ่ง soft reset
bool tacp_poll_uart (void)
 pump UART; ต้องเรียกจากลูปรอแบบบล็อกทุกลูป
void tacp_request_delete_main_from_isr (void)
 ทางออกฉุกเฉินที่เรียกจาก ISR ได้: หยุดสคริปต์, สั่ง soft reset, ลบ /main.py
void tacp_claw_respond (uint8_t sub_cmd, const char *payload, uint16_t payload_len)
 ส่งเฟรมคำตอบไบนารีของ BentoClaw หนึ่งเฟรมออกทาง UART
int tacp_ring_buf_read (void)
 ดึงไบต์ของ REPL ออกมาหนึ่งไบต์ หรือคืน -1 เมื่อว่าง ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ
bool tacp_ring_buf_readable (void)
 การทดสอบแบบไม่บล็อกว่ามีข้อมูลพร้อมหรือไม่ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

Detailed Description

6 ฟังก์ชัน: เป็นโปรโตคอลควบคุมฝั่ง UART ที่ BENTO IDE ใช้คุยกับบอร์ด (magic 0xAA 0x55, คำสั่งควบคุม, การโอนไฟล์แบบไบนารี และ sub-protocol 0x30 ของ BentoClaw) เขียนไว้ใน tacp.c คอมไพล์รวมอยู่ใน libbento_mpy.a ไม่ได้ส่งมอบมาเป็นซอร์ส เทมเพลตส่งมอบ tacp.h มาให้

4 ตัวมี call site อยู่จริงในของที่ส่งมอบ (ใน mpy_main.c, modui.c, modsensors.c, modbentoclaw.c และ sensor_auto_task.c) ส่วนอีก 2 ตัว คือ tacp_ring_buf_read() และ tacp_ring_buf_readable() ไม่มีผู้เรียกที่ใดเลย: ในเฟิร์มแวร์ที่ส่งมอบจริง REPL ของ MicroPython กิน ring อยู่ภายใน ตัวอย่างของทั้งสองเป็นตัวอย่างที่เขียนขึ้นเองและกำกับไว้

variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)

Function Documentation

◆ tacp_init()

void tacp_init ( void )

รีเซ็ต state machine, ล้าง ring, ระบาย FIFO; ครั้งเดียวต่อหนึ่ง soft reset

Initialize TACP state machine and ring buffer.

ข้อกำหนดการเรียกใช้
รีเซ็ต state machine ของ TACP ล้าง ring buffer และระบาย FIFO ของ UART ถูกเรียก ครั้งเดียวต่อหนึ่ง soft reset ที่ label soft_reset ของ MicroPython task ไบต์ค้างจากก่อนรีเซ็ตจึงถูกนำมา parse ซ้ำจนเกิดการรีเซ็ตซ้อนสองครั้งไม่ได้ ต้องเรียกก่อนฟังก์ชัน TACP ตัวอื่นทุกตัวในกลุ่มฟังก์ชันนี้ — tacp_poll_uart() ระหว่างการเริ่มต้นระบบปลอดภัยได้ก็เพราะ tacp_init() ทำงานไปก่อนแล้วเท่านั้น ทำงานใน MicroPython task context; เป็น void
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
label ของ soft reset ใน mpy_main.c
/* ...context: inside the MicroPython task, at the soft_reset label ... */
soft_reset:
/* Clear TACP ring buffer, state machine, and UART FIFO on every
* soft reset so stale bytes don't cause double-resets. */
/* Peek at safe-boot flag early so g_is_safe_boot is correct before
* check_boot_mode() runs later. Defensive: if any code path calls
* tacp_poll_uart() during init, the TACP handler sees the right value.
* The flag is NOT consumed here — check_boot_mode() handles that. */
g_is_safe_boot = (s_safe_boot_once_flag == MPY_SAFE_BOOT_MAGIC);

◆ tacp_poll_uart()

bool tacp_poll_uart ( void )

pump UART; ต้องเรียกจากลูปรอแบบบล็อกทุกลูป

Poll UART for TACP commands and REPL bytes. Returns true if a command was detected.

ข้อกำหนดการเรียกใช้
pump UART: กินไบต์ที่มีอยู่ เดิน state machine ของ TACP และผลักไบต์ของ REPL เข้า ring ต้องเรียกจากลูปรอแบบบล็อกทุกลูป ใน MicroPython task context มิฉะนั้น Ctrl-C, ปุ่ม Stop ของ IDE และการอัปโหลดไฟล์จะใช้ไม่ได้ตลอดช่วงที่รออยู่ tacp_init() ต้องทำงานมาก่อน ครั้งเดียวต่อหนึ่ง soft reset ค่าที่คืนมาถูกทิ้งโดยเจตนาที่จุดเรียกทั้ง 7 แห่งในของที่ส่งมอบจริง — มันคือ pump ไม่ใช่ predicate รูปแบบมาตรฐานจับคู่มันกับ MICROPY_EVENT_POLL_HOOK ส่วนรูปแบบฝั่ง FreeRTOS จับคู่กับ vTaskDelay(pdMS_TO_TICKS(1)) แทน ไม่มีการจับ lock ไม่ปลอดภัยต่อการเรียกจาก ISR — ดู tacp_request_delete_main_from_isr() สำหรับทางออกฉุกเฉินทางเดียวเมื่อสคริปต์ที่หลุดการควบคุมทำให้ pump นี้ไม่ได้ทำงาน
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
รูปแบบ pump มาตรฐานภายในการรอ IPC ของ UI (modui.c):
/* ...context: inside the UI IPC response wait loop ... */
mp_uint_t deadline = mp_hal_ticks_ms() + timeout_ms;
while (!ui_ipc_resp.ready) {
if ((mp_int_t)(mp_hal_ticks_ms() - deadline) >= 0) break;
MICROPY_EVENT_POLL_HOOK;
}

รูปแบบที่คืนคิวแบบ FreeRTOS (modsensors.c):

/* ...context: inside the joystick IPC response wait ... */
for (int w = 0; w < 50 && !js_ipc_response.ready; w++) {
vTaskDelay(pdMS_TO_TICKS(1));

◆ tacp_request_delete_main_from_isr()

void tacp_request_delete_main_from_isr ( void )

ทางออกฉุกเฉินที่เรียกจาก ISR ได้: หยุดสคริปต์, สั่ง soft reset, ลบ /main.py

ISR-safe trigger for the CM55 "Delete main.py" button. Breaks a running / looping script (keyboard interrupt) and forces a MicroPython soft reset so the boot path removes /main.py. Safe to call from interrupt context.

ข้อกำหนดการเรียกใช้
เรียกจาก ISR ได้อย่างปลอดภัย: หยุดสคริปต์ที่กำลังทำงาน (keyboard interrupt) และบังคับให้ MicroPython ทำ soft reset เพื่อให้เส้นทางบูตลบ /main.py ทิ้ง ไม่มีการจองหน่วยความจำ ไม่มี hard reset; แฟล็กใน SRAM อยู่รอดข้าม soft reset นี่คือ ทางสำรองสำหรับกรณีที่ลูปใน /main.py หลุดการควบคุมจนยึด CPU ไว้ผู้เดียวและทำให้ tacp_poll_uart() ไม่ได้ทำงาน — เส้นทางแบบนุ่มนวล (s_delete_pending ซึ่งวนถามใน task context) ยังคงมีอยู่เคียงกัน ถูกเรียกจาก IPC ISR ของการควบคุมเซนเซอร์บน CM33_NS โดยมี BENTO_HAS_MPY เป็น guard: บน variant mtb-only ไม่มี VM และไม่มี /main.py ให้ลบ guard จึงคอมไพล์การเรียกนั้นทิ้งไป เป็น void
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
callback ของ IPC ISR ใน sensor_auto_task.c
/* ...context: inside the sensor-ctrl IPC ISR callback ... */
if (msg->cmd == IPC_CMD_DELETE_MAIN_PY) {
/* Graceful path: polled by tacp_poll_uart() in task context (works when
* the MP loop is alive, e.g. at the REPL). */
s_delete_pending = true;
/* Robust path: break the script + force a MicroPython soft reset DIRECTLY
* from this IPC ISR, so the Delete button works even when a runaway
* /main.py loop monopolises the CPU and starves tacp_poll_uart(). The
* soft reset keeps SRAM (s_delete_main_flag) intact -> boot removes
* /main.py. ISR-safe (no allocation, no hard reset). Ported from
* Game-libraries 8a0689a (HW-verified on Eva). */
#if BENTO_HAS_MPY
#endif /* no VM: there is no /main.py to delete */

◆ tacp_claw_respond()

void tacp_claw_respond ( uint8_t sub_cmd,
const char * payload,
uint16_t payload_len )

ส่งเฟรมคำตอบไบนารีของ BentoClaw หนึ่งเฟรมออกทาง UART

Send a BentoClaw TACP binary response frame. Frame: [0xAA][0x55][0x30][sub_cmd][len_lo][len_hi][payload][crc_lo][crc_hi] Use sub_cmd matching request for success, TACP_CLAW_ERROR (0xFF) for errors.

ข้อกำหนดการเรียกใช้
ส่งเฟรมคำตอบไบนารีของ BentoClaw หนึ่งเฟรมออกทาง UART (0xAA 0x55 0x30, sub-command, ความยาว, payload, CRC-16/CCITT) ให้ใช้ sub_cmd ของคำขอสำหรับกรณีสำเร็จ และใช้ TACP_CLAW_ERROR (0xFF) สำหรับข้อผิดพลาด ต้องเรียก tacp_init() มาก่อน payload_len คือความยาวจริง — ค่าที่ snprintf คืนมาแล้ว cast เป็น uint16_t — ห้ามใช้ strlen ของบัฟเฟอร์ที่อาจถูกตัดทอนไปแล้ว โค้ดในของที่ส่งมอบจริงไม่เคยเรียกฟังก์ชันนี้ตรง ๆ: เรียกผ่าน wrapper claw_respond / claw_respond_err เสมอ เฟรม TACP_CLAW_READY ที่ส่งขึ้นเองโดยไม่มีคำขอจะถูกส่ง ก็ต่อเมื่อ tacp_init(), mp_init(), การเมานต์ VFS และ boot.py / main.py ทำงานจบแล้วเท่านั้น IDE จึงไม่มีทางเห็น READY จากบอร์ดที่ยังรับคำขอไม่ได้ เป็น void ไม่มีเส้นทางแจ้งข้อผิดพลาด; ทำงานใน MicroPython task context ตัวตอบภายในของ archive อีก 20 ตัวใน tacp.c ไม่ใช่ส่วนที่ผู้ใช้ไลบรารีเรียกได้ — ส่วนที่ผู้ใช้ไลบรารีเรียกได้ในของที่ส่งมอบจริงคือจุดเรียก 3 แห่งใน modbentoclaw.c พอดี
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
wrapper ทั้งสองตัวและเฟรม READY
static void claw_respond(uint8_t sub_cmd, const char *payload, uint16_t payload_len) {
tacp_claw_respond(sub_cmd, payload, payload_len);
}
static void claw_respond_err(const char *msg, uint16_t msg_len) {
}
/*******************************************************************************
* READY frame — sent once at boot to announce firmware readiness.
* IDE listens for this instead of polling STATUS with delay+retry.
******************************************************************************/
void bentoclaw_send_ready(void) {
bentoclaw_ensure_init();
claw_ipc_init();
int n = snprintf(s_work_small, sizeof(s_work_small),
"{\"fw\":\"%s\",\"board\":\"%s\",\"tools\":%u,\"proto\":2}",
BENTOCLAW_VERSION, MICROPY_HW_BOARD_NAME, (unsigned)TOOL_COUNT);
tacp_claw_respond(TACP_CLAW_READY, s_work_small, (uint16_t)n);
/* Push initial stats to CM55 LCD so it shows real tool count immediately */
claw_ipc_send_stats();

◆ tacp_ring_buf_read()

int tacp_ring_buf_read ( void )

ดึงไบต์ของ REPL ออกมาหนึ่งไบต์ หรือคืน -1 เมื่อว่าง ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

Read one byte from the ring buffer (for REPL consumption). Returns -1 if empty.

ข้อกำหนดการเรียกใช้
ดึงไบต์ของ REPL ออกจาก ring หนึ่งไบต์ (0 ถึง 255) หรือคืนค่า -1 เมื่อว่าง ring จะเติมก็ต่อเมื่อ tacp_poll_uart() ทำงานอยู่เท่านั้น — ให้ pump ก่อน tacp_init() ครั้งเดียวต่อหนึ่ง soft reset; ทำงานใน MicroPython task context; มีผู้อ่านได้รายเดียว ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ — ในเฟิร์มแวร์ที่ส่งมอบจริง REPL กิน ring อยู่ภายใน archive; ตัวนิยาม (tacp.c) ไม่ได้ส่งมอบมาเป็นซอร์ส
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
static void bento_ex_tacp_ring_buf_read(void)
{
/* Pump first — the ring only fills while tacp_poll_uart() runs.
* The return value is deliberately discarded at all shipped pump
* sites: it is a pump, not a predicate. */
(void)tacp_poll_uart();
int c;
while ((c = tacp_ring_buf_read()) >= 0) {
/* consume the byte (REPL character, 0..255) */
(void)c;
}
/* c == -1: ring empty — return to the wait loop and keep pumping. */
}

◆ tacp_ring_buf_readable()

bool tacp_ring_buf_readable ( void )

การทดสอบแบบไม่บล็อกว่ามีข้อมูลพร้อมหรือไม่ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

Check if the ring buffer has data.

ข้อกำหนดการเรียกใช้
การทดสอบแบบไม่บล็อกว่ามีข้อมูลพร้อมหรือไม่: เป็นการเทียบ head/tail ที่เป็น volatile ปลอดภัยต่อการวนถามถี่ ๆ มีไว้สำหรับผู้เรียกที่ต้องไม่แตะ ring โดยที่ยังไม่รู้ว่ามีข้อมูลหรือไม่; tacp_ring_buf_read() รายงานสภาพว่างเป็น -1 ให้อยู่แล้ว ต้องเรียก tacp_init() มาก่อน; ทำงานใน MicroPython task context ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ ที่ใดเลย
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
static void bento_ex_tacp_ring_buf_readable(void)
{
(void)tacp_poll_uart(); /* keep the producer pumped */
return; /* nothing buffered — no work */
}
int c = tacp_ring_buf_read(); /* guaranteed >= 0 right after a
* true readable() in this
* single-consumer context */
(void)c;
}