/*
 * ComAssistant 工作区「文本行」控制帧解析 —— 对外类型与接口（与 workspace_tutorial_code.c 配套）。
 * 适用于 PC 未勾选 Unify 时的下行格式；Unify 二进制控制包须另行按包头 + 5 字节数据段解析。
 * 教程资源中的示例；拷入固件工程时请同时复制 .h / .c 并确保 UTF-8。
 */

#ifndef WORKSPACE_TUTORIAL_CODE_H
#define WORKSPACE_TUTORIAL_CODE_H

#include <stddef.h>
#include <stdio.h>

#ifndef WS_TUT_DEBUG
#define WS_TUT_DEBUG 0
#endif

#if WS_TUT_DEBUG
#define WS_TUT_DBG(...) do { printf("[ws_tut] " __VA_ARGS__); } while (0)
#else
#define WS_TUT_DBG(...) ((void)0)
#endif

#define LINE_CAP    128u
#define WS_CAP       32u
#define CMD_CAP      32u
#define DATA_CAP     32u

typedef struct {
    char workspace[WS_CAP];
    char command[CMD_CAP];
    char data[DATA_CAP];
    int  ok;
} WorkspaceFields;

typedef struct {
    unsigned char buf[LINE_CAP];
    size_t        len;
    int           awaiting_brace;
} LineAccumulator;

typedef struct {
    LineAccumulator line_acc;
    char            line_buf[LINE_CAP];
    char            completed_line[LINE_CAP];
    volatile int    completed_ready;
} StreamParser;

typedef void (*WorkspacePacketCallback)(const WorkspaceFields *fields, void *ctx);

void stream_parser_init(StreamParser *sp);
int  stream_parser_feed_byte(StreamParser *sp, unsigned char b);
int  stream_parser_dispatch_pending(StreamParser *sp,
                                    WorkspacePacketCallback cb, void *ctx);

int parse_workspace_fields(const char *line, WorkspaceFields *out);

/*
 * ---------------------------------------------------------------------------
 * 接入说明（摘）
 * ---------------------------------------------------------------------------
 * A  串口参数与 PC「串口设置」一致；换行可为 \n 或 \r\n。
 * B  实现文件中的内部函数保持 static；头文件已声明的接口在 .c 中定义即可。
 * C  RX 中断：读一字节后 stream_parser_feed_byte(&g_sp, b)，禁止在中断里 dispatch_pending。
 * D  stream_parser_init 不登记回调；回调在每次 dispatch_pending(&g_sp, handler, ctx) 传入。
 * E  主循环中反复调用 dispatch_pending 直到返回 0。
 * F  每路 USART 使用独立 StreamParser。
 *
 * 示例回调（调试打印三段字段；可作 your_handler，按业务改写）：
 *
 *   static void demo_on_packet(const WorkspaceFields *f, void *ctx)
 *   {
 *       (void)ctx;
 *       printf("workspace=[%s]\ncommand=[%s]\ndata=[%s]\n",
 *              f->workspace, f->command, f->data);
 *   }
 *
 * 伪代码（块注释内勿再写 slash-star，否则会提前结束注释）：
 *
 *   #include "workspace_tutorial_code.h"
 *
 *   static StreamParser g_sp;
 *
 *   void board_uart_init(void) {
 *       stream_parser_init(&g_sp);
 *   }
 *
 *   void USARTx_IRQHandler(void) {
 *       if (RX_NOT_EMPTY)
 *           stream_parser_feed_byte(&g_sp, READ_UART_BYTE());
 *   }
 *
 *   void main_loop(void) {
 *       for (;;) {
 *           while (stream_parser_dispatch_pending(&g_sp, demo_on_packet, NULL))
 *               ;
 *       }
 *   }
 */

/*
 * ---------------------------------------------------------------------------
 * 并发与中断（摘）
 * ---------------------------------------------------------------------------
 * - feed_byte 仅在中断（或单一线程）、dispatch_pending 仅在主循环调用；勿多线程并发操作同一 StreamParser。
 * - completed_line 为单行槽：dispatch 慢于收包时新一行会覆盖未处理行；高吞吐请加队列或双缓冲。
 * - dispatch 内「读 completed_line + 清 completed_ready」与 ISR 内写 completed_line 可能交错：可在该段短暂关闭
 *   同级或更低优先级 RX 中断（依 MCU）再拷贝，减轻撕裂；volatile 不能替代互斥。
 * - stream_parser_init 与 feed_byte 勿并发：init 前应暂停 RX 或确认无接收中断。
 * - WS_TUT_DEBUG 开启时 ISR 路径可能 printf，与主线程 printf 存在不可重入风险；发布固件请保持 WS_TUT_DEBUG 为 0。
 */

#endif /* WORKSPACE_TUTORIAL_CODE_H */
