# lyfPrinter 上位机 APP 迁移到 ESP32(ESP-IDF) 实施文档 本文档基于当前 Android 上位机 APP 实现(`MainActivity + ECBLE + BlueHandler + 各预览页`),给出一套可落地的 ESP32/ESP-IDF 迁移方案。 适用目标: - 让 ESP32 作为 BLE Central 连接 `lyfPrinter` 热敏打印机 - 复用现有私有打印协议(`0x00~0x07`、`0xA0~0xA4`) - 在 ESP32 上实现打印、状态监控、标签纸定位、OTA(打印机固件)能力 --- ## 1. 现有 APP 能力基线(迁移输入) Android 端关键行为: 1. 扫描过滤设备名 `lyfPrinter` 2. 连接 BLE 外设并绑定特征: - Notify: `0000fff1-0000-1000-8000-00805f9b34fb` - Write: `0000fff2-0000-1000-8000-00805f9b34fb` 3. 请求 `MTU=247` 4. 向写特征发送私有协议帧,接收 Notify 回包并解析状态 5. 打印流程: - 输入内容转 384 点宽位图 - 二值化 - 行取模(8 像素打包 1 字节) - 按 240 字节数据体分包(整帧 244 字节) - 按应答节奏发送完毕 6. 打印前后控制: - 开启/关闭 VH 电源 - 设置热参数(浓度映射) - 结束后走纸留白 可参考: - `APP_BLE打印控制实现说明.md` - `BLE_PAIRING_PARAMETERS.md` --- ## 2. 迁移目标定义 建议按两级目标推进: ### 2.1 M1(必做,先跑通) 1. 扫描/连接/重连 2. 状态查询与解析(纸张、电量、温度) 3. 基础打印(接收已编码点阵数据后发送) 4. 标签纸 gap 定位与偏移读写 ### 2.2 M2(增强) 1. ESP32 端文本渲染与位图编码 2. 图片/二维码本地生成与打印 3. 打印机 OTA 完整流程 4. UI 层(按键、串口命令、Web、LCD+LVGL 任一) --- ## 3. ESP-IDF 技术选型建议 推荐: - ESP-IDF `v5.1+` 或 `v5.2+` - BLE Host:`NimBLE`(内存占用更低,Central 场景稳定) 备选: - Bluedroid 也可实现,但本项目建议优先 NimBLE。 编译配置建议(`menuconfig`): 1. 启用 BLE(NimBLE) 2. 增大 GATT MTU 到 `247` 3. 提升 BT controller/host 内存预算 4. 打开 NVS(存储设备地址、标签偏移、最近配置) --- ## 4. Android 到 ESP32 模块映射 | Android 类 | 迁移后模块 | 说明 | |---|---|---| | `MainActivity` | `printer_ble_scan.c` + `app_cli.c` | 扫描、设备选择、连接触发 | | `ECBLE` | `printer_ble_client.c` | GATT 连接、服务发现、通知订阅、写特征 | | `BlueHandler` | `printer_proto.c` + `printer_engine.c` | 协议封装/解析、状态机、分包与流控 | | `DataConvertTool` | `image_raster.c` | 二值化、384宽缩放、行取模 | | 各 PreviewActivity | `content_renderer_*.c` | 文本/二维码/模板渲染 | | `otaUpdateActivity` | `printer_ota.c` | `A0~A4` 升级流程 | 建议目录: ```text components/ printer_ble/ include/printer_ble_client.h printer_ble_client.c printer_proto/ include/printer_proto.h printer_proto.c printer_engine/ include/printer_engine.h printer_engine.c image_raster/ include/image_raster.h image_raster.c printer_ota/ include/printer_ota.h printer_ota.c main/ app_main.c app_cli.c app_config.c ``` --- ## 5. BLE 迁移要点(与 Android 行为对齐) ### 5.1 扫描与过滤 逻辑对齐 Android: - 仅处理设备名 `lyfPrinter` - 保存 MAC、RSSI、最后发现时间 - 支持“按 MAC 直连”模式(量产更稳) ### 5.2 建链流程 1. `scan -> connect` 2. `discover service/characteristics` 3. 找到 `FFF1/FFF2` 4. 对 `FFF1` 写 CCCD `0x0001` 开启 Notify 5. 交换 MTU(目标 247) ### 5.3 写入策略 与 Android 保持一致: - Write Without Response - 发送内容使用十六进制帧字节序列 ### 5.4 断线策略 建议状态机: - `DISCONNECTED` - `SCANNING` - `CONNECTING` - `DISCOVERING` - `READY` - `PRINTING` 断线后: - 延时 300ms 重连 - 最多重试 4 次(与 Android 一致) - 失败后回 `SCANNING` --- ## 6. 私有协议迁移(核心) ### 6.1 指令定义 ```c // 打印 #define CMD_POWER 0x00 #define CMD_GET_STATUS 0x01 #define CMD_SET_DISTANCE 0x02 #define CMD_SET_PARAM 0x03 #define CMD_SEND_DATA 0x04 #define CMD_GAP_MOVE 0x05 #define CMD_GET_LABEL_OFFSET 0x06 #define CMD_SET_LABEL_OFFSET 0x07 // OTA #define CMD_BOOT_JUMP_BOOT 0xA0 #define CMD_BOOT_ERASE_PAGE 0xA1 #define CMD_BOOT_WRITE_DATA 0xA2 #define CMD_BOOT_JUMP_APP 0xA3 #define CMD_BOOT_GET_VERSION 0xA4 ``` ### 6.2 帧结构 常规帧: ```text [addr:1][func:1][lenH:1][lenL:1][payload:len][checksum:optional] ``` 校验和规则: - 从 `addr` 到 payload 最后一个字节累加,取低 8 位 与 Android 对齐点: - 控制类命令一般带校验 - `CMD_SEND_DATA(0x04)` 数据帧可不带校验(当前 Android 逻辑) ### 6.3 回包解析 按 `func` 分发处理: 1. `0x01`:设备状态 2. `0x04`:数据发送 ACK,用于释放“发送下一包”锁 3. `0x05`:标签定位完成 4. `0x06`:标签偏移读取结果 5. `0xA1~0xA4`:OTA流程响应 --- ## 7. 打印引擎迁移设计 ### 7.1 打印参数映射 浓度映射(与 Android 对齐): - `较淡 -> 1000` - `中等 -> 1500` - `较浓 -> 2000` - `最深 -> 3000` 打印前序列: 1. `CMD_POWER` 开 2. `CMD_SET_PARAM(hot_mode, move_time, hot_time)` 3. 分包发送 `CMD_SEND_DATA` 打印后序列: 1. `CMD_POWER` 关 2. `CMD_SET_DISTANCE(12.5mm)` 留白走纸 ### 7.2 分包规则 与 Android 同步: - 单帧上限 244 bytes - 协议头 4 bytes - 数据体 240 bytes(384 点宽 -> 48 bytes/行 -> 每包 5 行) 流控策略: - 发出数据包后等待 `0x04` ACK - 首包后可短延时一次 - 后续每包 ACK 驱动 - ACK 超时建议 `2~5s`,整任务超时 `30s` ### 7.3 打印状态门限 建议保持一致: - 缺纸:禁止打印 - 电量 `<=40%`:禁止打印 - 温度 `>=60℃`:禁止打印 --- ## 8. 图像处理迁移策略(重点) ESP32 内存有限,不建议一次性处理大图。推荐 3 种模式: ### 8.1 模式 A(推荐首版) 外部(PC/手机/云)先生成“384宽 + 二值化 + 行取模”数据,ESP32 仅负责协议发送。 优点: - 开发最快 - ESP32 负载最低 ### 8.2 模式 B(文本优先) ESP32 只做文本/模板渲染,不做复杂图片解码。 优点: - 资源可控 - 适合收据、标签、测试页 ### 8.3 模式 C(全本地) ESP32 本地做图片解码+缩放+二值化+取模。需外接 PSRAM,建议 ESP32-S3。 --- ## 9. FreeRTOS 任务模型建议 建议拆成 4 个任务 + 2 个队列: 1. `ble_task` - 处理 GAP/GATT 事件 2. `proto_task` - 帧收发、ACK 管理、回包解析 3. `print_task` - 打印流程状态机(预热、分包、收尾) 4. `cmd_task` - 外部命令入口(串口/Web/UI) 队列: - `q_cmd`:业务命令(print/status/ota) - `q_evt`:BLE/协议事件(connected/ack/timeout) 同步对象: - `EventGroup`:`READY`、`ACK_04`、`GAP_OK`、`OTA_ACK` - `Mutex`:写特征互斥 --- ## 10. 关键 C 接口建议 ```c // BLE esp_err_t printer_ble_start_scan(void); esp_err_t printer_ble_connect_by_name(const char *name); esp_err_t printer_ble_write(const uint8_t *data, size_t len, bool no_rsp); // 协议 size_t printer_proto_build_frame(uint8_t addr, uint8_t cmd, const uint8_t *payload, uint16_t len, bool with_checksum, uint8_t *out); void printer_proto_handle_notify(const uint8_t *data, size_t len); // 打印引擎 esp_err_t printer_engine_print_raw(const uint8_t *raw, size_t len, int hot_time); esp_err_t printer_engine_get_status(void); esp_err_t printer_engine_gap_move(void); esp_err_t printer_engine_set_label_offset(uint8_t value); // OTA esp_err_t printer_ota_run(const uint8_t *fw, size_t len); ``` --- ## 11. OTA 迁移(针对打印机固件升级) 流程对齐 Android: 1. `A0` 跳 Boot 2. `A1` 擦页(按 1024 bytes 估页数) 3. `A2` 写入(单包 236 bytes 数据) 4. `A3` 跳回 App 5. `A4` 读版本确认 建议: - 每步都有超时和重试(每步 3 次) - 断电恢复策略:记录 last packet index --- ## 12. 分阶段实施计划 ### Phase 1(3~5天) 1. BLE 扫描连接 + 订阅通知 + MTU 2. 实现 `GET_STATUS` 3. 实现 `POWER / SET_PARAM / SEND_DATA / SET_DISTANCE` 4. 用固定测试页 raw 数据打印 验收: - 可稳定打印 50 次无死锁 ### Phase 2(3~7天) 1. 文本模板渲染 2. 标签定位/偏移 3. 设备参数保存(NVS) 验收: - 标签纸对齐稳定 ### Phase 3(3~7天) 1. OTA 全流程 2. 回归测试与异常恢复 验收: - 升级成功率 > 99% --- ## 13. 测试清单 基础通信: 1. 扫描到 `lyfPrinter` 2. 连接后找到 `FFF1/FFF2` 3. Notify 有数据 4. MTU 协商到 247 协议一致性: 1. 每条命令帧结构正确 2. 校验和与 Android 一致 3. `0x04` ACK 能正确驱动分包 打印质量: 1. 浓度 4 档效果一致 2. 长图连续打印无丢行 3. 结束留白距离稳定 异常场景: 1. 打印中断线后可恢复 2. 缺纸/低电/高温阻断生效 3. OTA 超时重试有效 --- ## 14. 常见问题与规避 1. `write without response` 太快导致对端缓存溢出 规避:严格按 `0x04 ACK` 节奏发送。 2. 连接成功但收不到 Notify 规避:确认 CCCD 写成功且未被后续重连覆盖。 3. 打印偏移不稳定 规避:先 `GAP_MOVE`,再按偏移走纸,偏移值写入 NVS。 4. ESP32 内存不足 规避:首版采用“外部预编码 raw 数据”,不在设备端做重图像处理。 --- ## 15. 最小可用迁移路径(建议) 如果你希望最快落地,按下面最小路径: 1. 先只做 BLE + 协议 + raw 发送 2. 用串口命令输入 `print_raw/status/gap/offset` 3. 打通后再逐步补 UI 和本地渲染 这样可以最短时间复用 Android 的核心协议能力,并把主要风险收敛在 BLE 链路与分包流控上。 --- ## 16. 附:协议发送伪代码 ```c void do_print(const uint8_t *raw, size_t raw_len, int hot_time) { send_cmd_power(true); // 0x00 send_cmd_set_param(1, 2, hot_time); // 0x03 const size_t chunk = 240; size_t off = 0; int idx = 0; while (off < raw_len) { size_t n = (raw_len - off > chunk) ? chunk : (raw_len - off); send_cmd_data(raw + off, n); // 0x04 if (idx > 0) { if (!wait_ack_04(3000)) { // 超时处理:重发或中止 break; } } else { vTaskDelay(pdMS_TO_TICKS(10)); } off += n; idx++; } send_cmd_power(false); // 0x00 send_cmd_set_distance(12.5f); // 0x02 } ```