No description
- C 99.2%
- Python 0.7%
每帧解码耗时不同,原来先解码再调 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 |
||
|---|---|---|
| docs | ||
| effects | ||
| .gitignore | ||
| alpk_board_sim.c | ||
| alpk_sdk.c | ||
| alpk_sdk.h | ||
| alpk_sdk_self_test.c | ||
| ALPK协议时序图.drawio | ||
| ALPK报文结构图.drawio | ||
| ALPK报文结构图.svg | ||
| Makefile | ||
| README.md | ||
| test_alpk_integration.py | ||
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。