1、对逗猫棒和喂食器的设备增加应答功能

2、对于V3协议的设备,目前只能电脑端应答,对电脑端的应答进行封包并通过BLE发送
This commit is contained in:
2026-07-30 14:43:30 +08:00
parent d8021154f2
commit 79e15a9ccc
23 changed files with 2131 additions and 1883 deletions
+4
View File
@@ -304,6 +304,10 @@ int bleproto_appdata_encode(uint8_t * txbuf,
rc = bleproto_encbin_otadata_rsp(&desc->datast.otadata_rsp,
appdata.data);
break;
case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2:
case E_BLEPROTO_SERVICE_ID_RUNCMD_V2:
rc = ble_proto_pack(&desc->datast.runcmd_v2_rsp, appdata.data, sizeof(appdata.data));
break;
default:
/* unkown serviceid */
return (-1);
+104 -1
View File
@@ -15,6 +15,7 @@
#include "vm.h"
#include "bleproto.h"
#include "bleproto_api.h"
#include "usr_usb_jb.h"
#if TCFG_USB_SLAVE_CDC_ENABLE
#include "usb/device/cdc.h"
#endif
@@ -129,6 +130,10 @@ void usr_set_device_default()
void usr_data_ana(bleproto_appdata_desc_t *desc)
{
bleproto_appdata_desc_t encode_desc = {0};
/* 记录本次 BLE 收到的 msgid,USB 侧回包时复用 */
usr_ble_rx_msgid_save(desc->header.msgid);
if (desc->header.msgtype /*desc.header.msgtype*/ == BLEPROTO_APPDATA_MSGTYPE_REQ)
{
switch (desc->header.serviceid)
@@ -454,19 +459,117 @@ void usr_run_cmd_code(bleproto_runcmd_req_t *runcmd_par, u8 usr_msg_id)
switch (runcmd_par->ycmd.cmd_id)
{
case 202:
printf("runcmd_par->ycmd.arg_int32 0 = %d\n", runcmd_par->ycmd.arg_int32[0]);
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 2;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_bytes_count = 0;
/*
| 索引 | 类型 | 描述 | 取值 |
| ---- | ----- | ---------- | ---------------- |
| 0 | int32 | 开关机控制 | 0:关机;1:开机 |
*/
rsp->ycmd.arg_int32[0] = 202;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 203:
/*
| 索引 | 类型 | 描述 | 取值 |
| ---- | ----- | ------------------ | ----------------------------------------------------------------- |
| 0 | int32 | 运动模式 | 0:关闭内置模式;1-鸡血,2-佛系 |
| 1 | int32 | 底座转动模式 | 0:关闭;1:平稳;2:狂转 |
| 2 | int32 | 逗猫棒摇动模式 | 0:关闭;1:自动; 2:转圈; 3:抖动; |
| 3 | int32 | 逗猫棒手动参数 | 逗猫棒摇动模式为0时有效, 0:无效;1:手动正转一圈 ;2:手动正转一圈 |
*/
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 3;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_int32[0] = 203;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.arg_int32[2] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 204:
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 2;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_int32[0] = 204;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 205:
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 2;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_int32[0] = 205;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 206: /// 震动开机参数配置
/*
| 索引 | 类型 | 描述 | 取值 |
| ---- | ------ | ------------------------------------------------------------ | ----------------------------- |
| 0 | int32 | 震动开机开关 | -1:忽略, 0:关闭;1:开启 |
| 1 | int32 | 勿扰模式开关 | -1:忽略, 0:关闭;1:开启 |
| 0 | string | 周计划 + 开始时间点 + 结束时间点<br />周计划:dddddd,
从左到右表示7个,分别表示周一到周日,1表示有效,0表示无效 <br />
时间点:hhmm, hh表示小时,mm表示分钟<br />
例如<br />0
0000001+1828+1930 表示每周日重复+18:28开始+19:30结束<br />
1000001+0928+1930 表示每周一和周日重复+09:28开始+19:30结束<br />
1100000+1328+1930 表示每周一和周二重复+13:28开始+19:30结束<br / | 字符串<br />ddddddd+hhmm+hhmm |
*/
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 2;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_int32[0] = 206;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 207: /// 周计划查询
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 4;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_int32[0] = 207;
rsp->ycmd.arg_int32[1] = 0;
rsp->ycmd.arg_int32[2] = 0;
rsp->ycmd.arg_int32[3] = 0;
rsp->ycmd.t = usr_var.usr_cureent_utc;
break;
case 600:
/*
| 索引 | 类型 | 描述 | 取值 |
| ---- | ----- | ---------------- | ------------------------------------------------- |
| 0 | int32 | cmdid | 600 |
| 1 | int32 | 返回值 | 0: 设备接受命令成功; 非零: 参见具体的命令错误代码 |
| 2 | int32 | 当前电量 | [1, 100]:百分比;0:不使用电池供电 |
| 3 | int32 | 当前电量是否正常 | 0:正常;1:电量过低 |
| 4 | int32 | 充电状态 | 0: 不支持充电; 1:充电 2:未充电 |
| 5 | int32 | 开机状态 | 0:关闭;1:开启 |
| 6 | int32 | 运动模式 | 0:关闭;1:鸡血;2:佛系 |
| 7 | int32 | 底座转动模式 | 0:关闭;1:平稳;2:狂转 |
| 8 | int32 | 逗猫棒摇动模式 | 0:手动;1:自动;2:转圈;3:抖动 |
*/
rsp->ycmd.cmd_id = 110;
rsp->ycmd.arg_int32_count = 9;
rsp->ycmd.arg_string_count = 0;
rsp->ycmd.arg_bytes_count = 0;
rsp->ycmd.arg_int32[0] = 600;
rsp->ycmd.arg_int32[1] = 0; // 0:命令接收成功
rsp->ycmd.arg_int32[1] = 0; // 0:命令接收成功
rsp->ycmd.arg_int32[2] = 100; // 当前电量
rsp->ycmd.arg_int32[3] = 0; // 当前电量是否正常
rsp->ycmd.arg_int32[4] = 2; // 充电状态
rsp->ycmd.arg_int32[5] = 1; // 开机状态
rsp->ycmd.arg_int32[6] = 0; // 运动模式
rsp->ycmd.arg_int32[7] = 0; // 底座转动模式
rsp->ycmd.arg_int32[8] = 0; // 逗猫棒摇动模式
memcpy(rsp->ycmd.arg_int32 + 2, 0, 7);
rsp->ycmd.t = usr_var.usr_cureent_utc; // UTC时间戳;
break;
+134 -14
View File
@@ -3,8 +3,9 @@
* @brief USB CDC 见宝帧解析:校验后写入产品码并重广播
* @author cyWu <1917507415@qq.com>
* @date 2026.07.24
* @version V1.0.1
* @version V1.0.2
* @history
* - V1.0.2, 2026.07.28, cyWu, 非产品码命令整帧透传 BLE REPORTCMD_V2
* - V1.0.1, 2026.07.24, cyWu, CDC 中断内禁止 syscfg_write,改延时到任务上下文
* - V1.0.0, 2026.07.24, cyWu, 首次发布
******************************************************************************/
@@ -13,6 +14,7 @@
#include "app_config.h"
#include "vm.h"
#include "usr_usb_jb.h"
#include "bleproto_api.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[USB_JB]"
@@ -35,12 +37,17 @@
#define MAX_PACKAGE_LEN 128
#define JB_RB_CAPACITY 256
#define USR_PROD_MAGIC 0x5A
#define USR_JB_BLE_CMD_REPORT 100 /* 0x07/0x34/0x38 → 主动上报类 */
#define USR_JB_BLE_CMD_ACK 110 /* 0x04/0x06/0x31/0x37 → 应答类 */
#define USR_JB_BLE_TX_SZ 384
#ifndef CFG_USER_PROD_INFO
#define CFG_USER_PROD_INFO 28
#endif
extern void usr_ble_adv_init(void);
extern void usr_ble_send_data(u8 *data, u16 len);
extern u16 usr_get_conn_service(void);
/*============================================================================*/
/* 类型 */
@@ -77,6 +84,118 @@ 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 uint8_t s_ble_txbuf[USR_JB_BLE_TX_SZ];
static uint8_t s_last_ble_msgid; /* 最近一次 BLE RX 的 msgid */
void usr_ble_rx_msgid_save(uint8_t msgid)
{
s_last_ble_msgid = msgid & 0x0F;
printf("usr_ble rx msgid save=%u\n", s_last_ble_msgid);
}
uint8_t usr_ble_rx_msgid_get(void)
{
return s_last_ble_msgid;
}
/**
* @brief 按 USB JB 命令映射 ble_proto cmd / gateway_int
* @param jb_cmd USB 帧 CMDframe[4]
* @param pkt 待填充的 ble_proto 包
* @return 0 可透传, -1 不支持的命令
*/
static int usr_jb_map_ble_pkt(uint8_t jb_cmd, ble_proto_packet_t *pkt)
{
if (!pkt) {
return -1;
}
memset(pkt, 0, sizeof(*pkt));
switch (jb_cmd) {
case 0x07: /* REPORT */
case 0x34: /* OTA_COMPLETE */
case 0x38: /* OTA_STOP_MCU */
pkt->cmd = USR_JB_BLE_CMD_REPORT;
pkt->gateway_int_cnt = 0;
break;
case 0x04: /* CONTROL_ACK */
case 0x06: /* READ_ACK */
case 0x31: /* OTA_NOTIFY_ACK */
case 0x37: /* OTA_STOP_BLE_ACK */
pkt->cmd = USR_JB_BLE_CMD_ACK;
pkt->gateway_int_cnt = 2;
pkt->gateway_int[0] = 0;
pkt->gateway_int[1] = 0;
break;
default:
return -1;
}
return 0;
}
/**
* @brief 将完整 JB 帧封装为 REPORTCMD_V2 后经 BLE 发出
* @param frame 完整 55 AA 帧
* @param len 帧长度
*/
static void usr_jb_forward_to_ble(const uint8_t *frame, uint16_t len)
{
bleproto_appdata_desc_t encode_desc = {0};
ble_proto_packet_t *pkt;
uint8_t jb_cmd;
int elen;
if (!frame || len < 7 || len > MAX_PACKAGE_LEN) {
return;
}
if (usr_get_conn_service() == 0) {
printf("usr_jb ble forward skip: not connected\n");
return;
}
jb_cmd = frame[4];
pkt = &encode_desc.datast.reportcmd_v2_req;
if (usr_jb_map_ble_pkt(jb_cmd, pkt) != 0) {
printf("usr_jb ble forward ignore jb_cmd=0x%02x\n", jb_cmd);
return;
}
encode_desc.header.version = 0;
encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
/* 100 上报用 REQ110 应答用 RSP */
encode_desc.header.msgtype = (pkt->cmd == USR_JB_BLE_CMD_ACK)
? BLEPROTO_APPDATA_MSGTYPE_RSP
: BLEPROTO_APPDATA_MSGTYPE_REQ;
encode_desc.header.msgid = usr_ble_rx_msgid_get();
encode_desc.header.encrypt = 0;
encode_desc.header.serviceid = (pkt->cmd == USR_JB_BLE_CMD_ACK)
? E_BLEPROTO_SERVICE_ID_RUNCMD_V2
: E_BLEPROTO_SERVICE_ID_REPORTCMD_V2;
pkt->reserved = 0;
pkt->device_int_len = 0;
pkt->device_str_len = 0;
pkt->device_bytes_len = len;
pkt->bytes_data = frame;
elen = bleproto_appdata_encode(s_ble_txbuf, sizeof(s_ble_txbuf),
sizeof(s_ble_txbuf), &encode_desc);
printf("usr_jb ble forward jb_cmd=0x%02x ble_cmd=%u msgtype=%u msgid=%u gw_cnt=%u elen=%d\n",
jb_cmd, pkt->cmd, encode_desc.header.msgtype,
encode_desc.header.msgid, pkt->gateway_int_cnt, elen);
if (elen > 0) {
usr_ble_send_data(s_ble_txbuf, (u16)elen);
printf_buf(s_ble_txbuf, elen);
} else {
printf("usr_jb ble encode fail\n");
}
}
/*============================================================================*/
/* 环形缓冲 / 校验 */
@@ -339,24 +458,25 @@ static void usr_jb_process_timeout(void *priv)
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 (cmd == USR_JB_CMD_SET_PRODCODE) {
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);
usr_jb_send_ack(cmd, sn, 0x01);
#endif
continue;
}
/* 缓存后统一落盘,避免同一周期多次写 flash */
s_pending_cmd = cmd;
s_pending_sn = sn;
s_pending_save = 1;
continue;
}
/* 缓存后统一落盘,避免同一周期多次写 flash */
s_pending_cmd = cmd;
s_pending_sn = sn;
s_pending_save = 1;
/* 其它命令:整帧透传到 BLE(按 JB cmd 映射 ble_proto cmd */
usr_jb_forward_to_ble(pkt, pkt_len);
} while (1);
if (!s_pending_save) {
+13
View File
@@ -39,6 +39,19 @@ void usr_prodcode_init(void);
*/
void usr_prodcode_get(uint8_t *prodcode, uint8_t *pcode);
/**
* @brief 记录最近一次 BLE 收到的 msgid(供 USB 回包复用)
* @param msgid BLE 包头 msgid4bit
* @return void
*/
void usr_ble_rx_msgid_save(uint8_t msgid);
/**
* @brief 获取最近一次 BLE 收到的 msgid
* @return msgid
*/
uint8_t usr_ble_rx_msgid_get(void);
/**
* @brief USB CDC 喂数:仅入环并挂定时器(可在中断调用)
* @note 帧解析 / syscfg_write / ACK / 重广播在定时器任务中执行