Files
BLE-USB_Dongle/apps/usr_le_code/usr_usb_jb.c
T

401 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************************************************************
* @file usr_usb_jb.c
* @brief USB CDC 见宝帧解析:校验后写入产品码并重广播
* @author cyWu <1917507415@qq.com>
* @date 2026.07.24
* @version V1.0.1
* @history
* - V1.0.1, 2026.07.24, cyWu, CDC 中断内禁止 syscfg_write,改延时到任务上下文
* - V1.0.0, 2026.07.24, cyWu, 首次发布
******************************************************************************/
#include "system/includes.h"
#include "app_config.h"
#include "vm.h"
#include "usr_usb_jb.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[USB_JB]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CLI_ENABLE
#include "debug.h"
#if TCFG_USB_SLAVE_CDC_ENABLE
#include "usb/device/cdc.h"
#endif
/*============================================================================*/
/* 协议常量(对齐 jb_protocol / jb_common */
/*============================================================================*/
#define PKT_HEAD_0 0x55
#define PKT_HEAD_1 0xAA
#define MAX_PACKAGE_LEN 128
#define JB_RB_CAPACITY 256
#define USR_PROD_MAGIC 0x5A
#ifndef CFG_USER_PROD_INFO
#define CFG_USER_PROD_INFO 28
#endif
extern void usr_ble_adv_init(void);
/*============================================================================*/
/* 类型 */
/*============================================================================*/
typedef struct {
uint8_t magic;
uint8_t prodcode[USR_PRODCODE_LEN];
uint8_t pcode[USR_PCODE_LEN];
} usr_prod_info_t;
typedef struct {
uint8_t buf[JB_RB_CAPACITY];
uint16_t write;
uint16_t read;
uint16_t count;
} usr_jb_rb_t;
/*============================================================================*/
/* 静态变量 */
/*============================================================================*/
static const uint8_t s_default_prodcode[USR_PRODCODE_LEN] = {'C', 'B', 'C', '0'};
static const uint8_t s_default_pcode[USR_PCODE_LEN] = {'P', 'I', 'C', 'B', 'C', '0'};
static uint8_t s_prodcode[USR_PRODCODE_LEN];
static uint8_t s_pcode[USR_PCODE_LEN];
static usr_jb_rb_t s_rb;
/* 待写 flash / 回 ACK 的缓存(ISR 只填,定时器里执行) */
static uint8_t s_pending_save;
static uint8_t s_pending_cmd;
static uint8_t s_pending_sn;
static uint8_t s_pending_prod[USR_PRODCODE_LEN];
static uint8_t s_pending_pcode[USR_PCODE_LEN];
static int s_process_timer;
/*============================================================================*/
/* 环形缓冲 / 校验 */
/*============================================================================*/
static void usr_jb_rb_init(usr_jb_rb_t *rb)
{
memset(rb, 0, sizeof(*rb));
}
static void usr_jb_rb_push(usr_jb_rb_t *rb, uint8_t byte)
{
if (rb->count >= JB_RB_CAPACITY) {
rb->read = (rb->read + 1) % JB_RB_CAPACITY;
rb->count--;
}
rb->buf[rb->write] = byte;
rb->write = (rb->write + 1) % JB_RB_CAPACITY;
rb->count++;
}
static uint8_t usr_jb_rb_pop(usr_jb_rb_t *rb)
{
uint8_t b = rb->buf[rb->read];
rb->read = (rb->read + 1) % JB_RB_CAPACITY;
rb->count--;
return b;
}
static uint16_t usr_jb_rb_available(const usr_jb_rb_t *rb)
{
return rb->count;
}
static uint16_t usr_jb_read_u16_be(const uint8_t *buf)
{
return ((uint16_t)buf[0] << 8) | buf[1];
}
/**
* @brief 校验和:sum(LEN_H .. payload_last) & 0xFF
*/
static uint8_t usr_jb_checksum(const uint8_t *frame, uint16_t total_len)
{
uint16_t sum = 0;
uint16_t i;
if (!frame || total_len < 4) {
return 0;
}
for (i = 2; i < total_len - 1; i++) {
sum += frame[i];
}
return (uint8_t)(sum & 0xFF);
}
/**
* @brief 从环形缓冲提取完整帧(逻辑对齐 jbGetOnePacket
* @return 0 成功, 1 需要更多数据, -2 校验失败
*/
static int8_t usr_jb_get_one_packet(uint8_t *out, uint16_t *out_len)
{
static uint8_t state = 0;
static uint16_t expect = 0;
static uint16_t idx = 0;
static uint8_t prev = 0;
while (usr_jb_rb_available(&s_rb)) {
uint8_t b = usr_jb_rb_pop(&s_rb);
if (state == 0) {
if (prev == PKT_HEAD_0 && b == PKT_HEAD_1) {
out[0] = PKT_HEAD_0;
out[1] = PKT_HEAD_1;
idx = 2;
state = 1;
}
} else if (state == 1) {
out[idx++] = b;
if (idx == 6) {
expect = 4 + usr_jb_read_u16_be(&out[2]);
if (expect > MAX_PACKAGE_LEN || expect < 7) {
state = 0;
} else {
state = 2;
}
}
} else {
out[idx++] = b;
if (idx >= expect) {
state = 0;
if (out[expect - 1] == usr_jb_checksum(out, expect)) {
*out_len = expect;
return 0;
}
printf("usr_jb checksum fail expect=0x%02x calc=0x%02x\n",
out[expect - 1], usr_jb_checksum(out, expect));
return -2;
}
}
prev = b;
}
return 1;
}
/*============================================================================*/
/* 产品码 flash */
/*============================================================================*/
static void usr_prodcode_set_default(void)
{
memcpy(s_prodcode, s_default_prodcode, USR_PRODCODE_LEN);
memcpy(s_pcode, s_default_pcode, USR_PCODE_LEN);
}
void usr_prodcode_init(void)
{
usr_prod_info_t info;
int ret;
usr_jb_rb_init(&s_rb);
s_pending_save = 0;
s_process_timer = 0;
usr_prodcode_set_default();
memset(&info, 0, sizeof(info));
ret = syscfg_read(CFG_USER_PROD_INFO, (u8 *)&info, sizeof(info));
if (ret > 0 && info.magic == USR_PROD_MAGIC) {
memcpy(s_prodcode, info.prodcode, USR_PRODCODE_LEN);
memcpy(s_pcode, info.pcode, USR_PCODE_LEN);
printf("prodcode from flash: %c%c%c%c / %c%c%c%c%c%c\n",
s_prodcode[0], s_prodcode[1], s_prodcode[2], s_prodcode[3],
s_pcode[0], s_pcode[1], s_pcode[2], s_pcode[3], s_pcode[4], s_pcode[5]);
} else {
printf("prodcode use default: %c%c%c%c / %c%c%c%c%c%c\n",
s_prodcode[0], s_prodcode[1], s_prodcode[2], s_prodcode[3],
s_pcode[0], s_pcode[1], s_pcode[2], s_pcode[3], s_pcode[4], s_pcode[5]);
}
}
void usr_prodcode_get(uint8_t *prodcode, uint8_t *pcode)
{
if (prodcode) {
memcpy(prodcode, s_prodcode, USR_PRODCODE_LEN);
}
if (pcode) {
memcpy(pcode, s_pcode, USR_PCODE_LEN);
}
}
/**
* @brief 写 VM(必须在任务/定时器上下文调用,禁止在 CDC 中断里调用)
*/
static int usr_prodcode_save(const uint8_t *prodcode, const uint8_t *pcode)
{
usr_prod_info_t info;
int ret;
if (!prodcode || !pcode) {
return -1;
}
memset(&info, 0, sizeof(info));
info.magic = USR_PROD_MAGIC;
memcpy(info.prodcode, prodcode, USR_PRODCODE_LEN);
memcpy(info.pcode, pcode, USR_PCODE_LEN);
memcpy(s_prodcode, prodcode, USR_PRODCODE_LEN);
memcpy(s_pcode, pcode, USR_PCODE_LEN);
ret = syscfg_write(CFG_USER_PROD_INFO, (u8 *)&info, sizeof(info));
if (ret <= 0) {
printf("prodcode flash write fail ret=%d\n", ret);
return -1;
}
printf("prodcode saved: %c%c%c%c / %c%c%c%c%c%c ret=%d\n",
s_prodcode[0], s_prodcode[1], s_prodcode[2], s_prodcode[3],
s_pcode[0], s_pcode[1], s_pcode[2], s_pcode[3], s_pcode[4], s_pcode[5],
ret);
return 0;
}
/**
* @brief 解析产品码 payload(仅 TLV
* 格式: [len=4][ProdtCode 4B][len=6][productCode 6B]
* @return 0 成功, -1 失败
*/
static int usr_jb_parse_prod_payload(const uint8_t *payload, uint16_t payload_len,
uint8_t *prodcode, uint8_t *pcode)
{
if (!payload || !prodcode || !pcode) {
return -1;
}
/* TLV: 04 xx xx xx xx 06 yy yy yy yy yy yy */
if (payload_len < (1 + USR_PRODCODE_LEN + 1 + USR_PCODE_LEN)) {
return -1;
}
if (payload[0] != USR_PRODCODE_LEN) {
return -1;
}
if (payload[1 + USR_PRODCODE_LEN] != USR_PCODE_LEN) {
return -1;
}
memcpy(prodcode, &payload[1], USR_PRODCODE_LEN);
memcpy(pcode, &payload[1 + USR_PRODCODE_LEN + 1], USR_PCODE_LEN);
return 0;
}
#if TCFG_USB_SLAVE_CDC_ENABLE
/**
* @brief 回 ACKCMD = 请求 CMD+1payload = result
*/
static void usr_jb_send_ack(uint8_t cmd, uint8_t sn, uint8_t result)
{
uint8_t buf[8];
uint16_t len_field = 4; /* CMD+SN+result+CKSUM */
uint16_t total = len_field + 4;
buf[0] = PKT_HEAD_0;
buf[1] = PKT_HEAD_1;
buf[2] = (uint8_t)(len_field >> 8);
buf[3] = (uint8_t)(len_field & 0xFF);
buf[4] = (uint8_t)(cmd + 1);
buf[5] = sn;
buf[6] = result;
buf[7] = usr_jb_checksum(buf, total);
cdc_write_data(0, buf, total);
}
#endif
/**
* @brief 任务上下文:解析帧 / 写 flash / ACK / 重建广播
*/
static void usr_jb_process_timeout(void *priv)
{
uint8_t pkt[MAX_PACKAGE_LEN];
uint16_t pkt_len;
int8_t ret;
uint8_t cmd;
uint8_t sn;
uint16_t payload_len;
(void)priv;
s_process_timer = 0;
/* 先把环形缓冲里的完整帧抽完 */
do {
pkt_len = 0;
ret = usr_jb_get_one_packet(pkt, &pkt_len);
if (ret != 0) {
break;
}
cmd = pkt[4];
sn = pkt[5];
payload_len = (pkt_len >= 7) ? (pkt_len - 7) : 0;
printf("usr_jb cmd=0x%02x sn=%u plen=%u\n", cmd, sn, payload_len);
printf_buf(pkt, pkt_len);
if (cmd != USR_JB_CMD_SET_PRODCODE) {
printf("usr_jb ignore cmd 0x%02x\n", cmd);
continue;
}
if (usr_jb_parse_prod_payload(&pkt[6], payload_len,
s_pending_prod, s_pending_pcode) != 0) {
printf("usr_jb set prodcode payload invalid\n");
#if TCFG_USB_SLAVE_CDC_ENABLE
usr_jb_send_ack(cmd, sn, 0x01);
#endif
continue;
}
/* 缓存后统一落盘,避免同一周期多次写 flash */
s_pending_cmd = cmd;
s_pending_sn = sn;
s_pending_save = 1;
} while (1);
if (!s_pending_save) {
return;
}
s_pending_save = 0;
if (usr_prodcode_save(s_pending_prod, s_pending_pcode) == 0) {
#if TCFG_USB_SLAVE_CDC_ENABLE
usr_jb_send_ack(s_pending_cmd, s_pending_sn, 0x00);
#endif
extern void usr_goto_pair_mode(void);
usr_goto_pair_mode();
printf("prodcode applied, adv rebuilt\n");
} else {
#if TCFG_USB_SLAVE_CDC_ENABLE
usr_jb_send_ack(s_pending_cmd, s_pending_sn, 0x05);
#endif
}
}
/**
* @brief USB CDC 喂数:仅压入环形缓冲并挂定时器(可在中断调用)
*/
void usr_usb_jb_feed(uint8_t *buf, uint32_t len)
{
uint32_t i;
if (!buf || len == 0) {
return;
}
for (i = 0; i < len; i++) {
usr_jb_rb_push(&s_rb, buf[i]);
}
/* 延时到系统定时器任务再解析/写 flash,避免中断里擦写导致复位 */
if (s_process_timer == 0) {
s_process_timer = sys_timeout_add(NULL, usr_jb_process_timeout, 20);
}
}