No description
  • C 99.2%
  • Python 0.7%
Find a file
maosasagawa bba4a333fd fix: 预存矩阵动效提前一拍算好,到点先交帧
每帧解码耗时不同,原来先解码再调 on_matrix_frame,回调时刻跟着忽早忽晚。
现在到点先交出上一拍算好的画面,再算下一拍。不加内存,协议和接入代码不变,
替换 alpk_sdk.c / alpk_sdk.h 重新编译即可。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WTibEhEwU3RNSTbMpqgb6D
2026-09-24 14:36:56 +08:00
docs feat: 灯带新增 73 单色(SDK / 调试工具 2.1.1) 2026-09-14 15:02:42 +08:00
effects fix: 预存矩阵动效提前一拍算好,到点先交帧 2026-09-24 14:36:56 +08:00
.gitignore feat: 灯带 9 个板端动效,参数固化成预设不上线 2026-09-07 13:40:59 +08:00
alpk_board_sim.c feat: 灯带 9 个板端动效,参数固化成预设不上线 2026-09-07 13:40:59 +08:00
alpk_sdk.c fix: 预存矩阵动效提前一拍算好,到点先交帧 2026-09-24 14:36:56 +08:00
alpk_sdk.h fix: 预存矩阵动效提前一拍算好,到点先交帧 2026-09-24 14:36:56 +08:00
alpk_sdk_self_test.c fix: 预存矩阵动效提前一拍算好,到点先交帧 2026-09-24 14:36:56 +08:00
ALPK协议时序图.drawio 明确矩阵握手和灯带帧处理语义 2026-06-30 16:56:31 +08:00
ALPK报文结构图.drawio 初始化 ALPK SDK 2026-06-30 16:54:05 +08:00
ALPK报文结构图.svg 初始化 ALPK SDK 2026-06-30 16:54:05 +08:00
Makefile perf: 优化板端播放调度和解码峰值 2026-09-14 18:15:21 +08:00
README.md perf: 优化板端播放调度和解码峰值 2026-09-14 18:15:21 +08:00
test_alpk_integration.py feat: 灯带 9 个板端动效,参数固化成预设不上线 2026-09-07 13:40:59 +08:00

ALPK Board-Side SDK — YTM32 对接说明

适用协议:USB_CH347_SPI_MATRIX_PROTOCOL_V1
适用芯片:YTM32(SPI Slave)
SDK 文件:alpk_sdk.h / alpk_sdk.c(纯 C99,无外部依赖)


概述

上位机(PC)通过 CH347 USB 转 SPI,将 ALPK 协议报文发往 YTM32。
本 SDK 运行在 YTM32 一侧,负责:接收报文 → 校验 CRC → 自动回 ACK → 触发应用回调。 握手包中的 width/height 表示矩阵面板尺寸;当前调试工具内置 30×16 和 60×32 两种矩阵资产。灯带尺寸不通过握手协商。

PC / App  →  CH347 USB→SPI  →  YTM32(本 SDK)

快速接入(三步)

第一步:实现传输钩子

static int my_spi_write(void *ctx, const uint8_t *data, size_t len) {
    SPI_WriteBlocking(SPI0, data, len);
    return 0;  /* 0 = 成功,非 0 = 失败 */
}

static int my_spi_read(void *ctx, uint8_t *buf, size_t len, uint32_t timeout_ms) {
    return (int)SPI_ReadBlocking(SPI0, buf, len, timeout_ms);
    /* 返回实际读到的字节数,小于 len 表示超时 */
}

第二步:初始化

#include "alpk_sdk.h"

static alpk_transport_t transport = {
    .write = my_spi_write,
    .read  = my_spi_read,
    .ctx   = NULL,
};

static void on_matrix_frame(void *ctx, const alpk_matrix_frame_t *h,
                             const uint8_t *rgb) {
    /* rgb 指向 h->rgb_len 字节的 RGB24 数据,仅在回调期间有效 */
    render_matrix(h->width, h->height, rgb);
}

static alpk_callbacks_t callbacks = {
    .on_brightness   = NULL,
    .on_power        = NULL,
    .on_mode         = NULL,
    .on_matrix_frame = on_matrix_frame,
    .on_strip_frame  = NULL,
    .user_ctx        = NULL,
};

/* max_payload_len 须 >= width * height * 3 + 16 */
static alpk_board_config_t config = {60, 32, 30, 5776};

static alpk_board_t board;
static uint8_t rx_buf[5800];   /* 60×32 RGB24 约需 5776 字节 */

void app_init(void) {
    alpk_result_t rc = alpk_board_init(&board, &transport, &callbacks, &config);
    if (rc != ALPK_OK) { /* 处理错误 */ }
}

第三步:主循环

void app_loop(void) {
    for (;;) {
        alpk_result_t rc = alpk_board_recv_one(&board, rx_buf,
                                                sizeof(rx_buf), 30000);
        if (rc == ALPK_ERR_TIMEOUT) continue;
        if (rc != ALPK_OK) {
            /* 可选:记录错误。SDK 已自动丢弃坏帧,下一帧可正常接收。*/
        }
    }
}

上面是仅推流固件的写法。启用 ALPK_WITH_FX 后,不能在 color mode 下固定阻塞 30 秒; 请按 effects/README.md 使用 alpk_fx_wait_ms() 计算收包超时,再调用 alpk_fx_tick()。


回调说明

回调 触发时机 关键字段
on_brightness 收到亮度设置 b->matrix、b->strip(0–1000,千分制)
on_power 收到开关机 p->matrix、p->strip(0=关,1=开)
on_mode 收到模式 JSON json(UTF-8 字符串,长度 json_len)
on_matrix_frame 收到矩阵帧 h->width/height/duration_ms,rgb(RGB24)
on_strip_frame 收到灯带帧 h->channel_id/led_count/duration_ms,rgb(RGB24)

rgb 指针仅在回调期间有效,如需保留请自行拷贝。 MATRIX_FRAME 会按板端矩阵尺寸严格校验;STRIP_FRAME 仅解析包内 channel_id/led_count/rgb_len,不做固定灯带尺寸校验。


返回值

值 含义
ALPK_OK 正常收到并分发一帧
ALPK_ERR_TIMEOUT 超时,无报文到达
ALPK_ERR_CRC CRC 校验失败(SDK 已丢弃,可继续)
ALPK_ERR_BUF_SMALL rx_buf 不够大(需扩大缓冲区)
其他负值 传输层或协议解析错误

rx_buf 大小参考

分辨率 最小 rx_buf
30×16 1456 字节
60×32 5776 字节
自定义 W×H W×H×3 + 16 字节

编译

将 alpk_sdk.c 和 alpk_sdk.h 加入工程即可,无第三方依赖。

SRCS   += alpk_sdk.c
CFLAGS += -std=c99

本地验证

make test          # 纯 C 单元测试(无硬件)
make integration   # Python ↔ C 联调测试(需 Python 3)

两条命令输出 PASS 后,即可将 SDK 移植到 YTM32。