除了显示驱动,其余全部测试通过

This commit is contained in:
guo
2026-08-30 14:13:24 +08:00
commit c0ace98dff
146 changed files with 9476 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
#include "mqtt_config.h"
#include "wifi/wifi_connect.h"
#include "mbedtls/md.h"
#include <string.h>
#include <stdio.h>
static mqtt_config_t mqtt_config;
/*
* 生成紧凑MAC == 用户名
*
* AA:BB:CC:DD:EE:FF -> AABBCCDDEEFF(大写)
*/
static int make_compact_mac(char *buf, uint32_t len)
{
uint8_t mac[6];
int i;
if (!buf || len < 13)
{
return -1;
}
if (wifi_get_mac(mac))
{
return -1;
}
for (i = 0; i < 6; i++)
{
sprintf(buf + i * 2, "%02X", mac[i]);
}
return 0;
}
/*
* 生成密码
*
* password = MD5(PRODUCT_SECRET + client_id) 小写hex
*/
static int make_password(const char *client_id, char *buf, uint32_t len)
{
char raw[128];
unsigned char digest[16];
const mbedtls_md_info_t *md_info;
int i;
if (!client_id || !buf || len < 33)
{
return -1;
}
snprintf(raw, sizeof(raw), "%s%s", MQTT_PRODUCT_SECRET, client_id);
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
if (!md_info ||
mbedtls_md(md_info, (const unsigned char *)raw, strlen(raw), digest))
{
return -1;
}
for (i = 0; i < 16; i++)
{
sprintf(buf + i * 2, "%02x", digest[i]);
}
buf[32] = '\0';
return 0;
}
void mqtt_config_init(void)
{
char device_name[13];
memset(
&mqtt_config,
0,
sizeof(mqtt_config)
);
/*
* MQTT服务器
*/
strcpy(
mqtt_config.host,
MQTT_SERVER_HOST
);
mqtt_config.port = MQTT_SERVER_PORT;
mqtt_config.keepalive = 60;//秒
/*
* 设备身份
* username = 紧凑MAC
* client_id = PRODUCT_KEY_MAC_MODEL
* password = MD5(PRODUCT_SECRET + client_id)
*
*/
if (make_compact_mac(device_name, sizeof(device_name))) {
strcpy(device_name, "unknown");
}
strcpy(
mqtt_config.username,
device_name
);
snprintf(
mqtt_config.client_id,
sizeof(mqtt_config.client_id),
"%s_%s_%s",
MQTT_PRODUCT_ID,
device_name,
MQTT_DEVICE_MODEL
);
make_password(
mqtt_config.client_id,
mqtt_config.password,
sizeof(mqtt_config.password)
);
/*
* topic
*/
snprintf(
mqtt_config.subscribe_topic,
sizeof(mqtt_config.subscribe_topic),
"/sys/%s/%s/c/#",
MQTT_PRODUCT_ID,
device_name
);
snprintf(
mqtt_config.publish_topic,
sizeof(mqtt_config.publish_topic),
"/sys/%s/%s/s/event/property/post",
MQTT_PRODUCT_ID,
device_name
);
}
mqtt_config_t *mqtt_config_get(void)
{
return &mqtt_config;
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef MQTT_CONFIG_H
#define MQTT_CONFIG_H
#include <stdint.h>
/*
* MQTT固定配置
*/
#define MQTT_PRODUCT_ID "cHXbMScFyRs6rmX8" //产品标识
#define MQTT_PRODUCT_SECRET "7e0b7bd5f1fd4f218c8094267818b83c" //产品密钥
#define MQTT_DEVICE_MODEL "ai_voice_radar_1.0" //设备型号
#define MQTT_SERVER_HOST "mqtt.lmhrt.cn"
#define MQTT_SERVER_PORT 11883
#define MQTT_SERVER_HOST_MAX_LEN 64
#define MQTT_CLIENT_ID_MAX_LEN 64
#define MQTT_USERNAME_MAX_LEN 64
#define MQTT_PASSWORD_MAX_LEN 64
#define MQTT_TOPIC_MAX_LEN 96
/*
* MQTT运行配置结构
*/
typedef struct
{
char host[MQTT_SERVER_HOST_MAX_LEN];
uint16_t port;
char client_id[MQTT_CLIENT_ID_MAX_LEN];
char username[MQTT_USERNAME_MAX_LEN];
char password[MQTT_PASSWORD_MAX_LEN];
uint16_t keepalive; //心跳时间;掉线
char subscribe_topic[MQTT_TOPIC_MAX_LEN];//订阅主题
char publish_topic[MQTT_TOPIC_MAX_LEN]; //发布主题
}mqtt_config_t;
/*
* 获取MQTT配置
*/
mqtt_config_t *mqtt_config_get(void);
/*
* 初始化MQTT配置
*/
void mqtt_config_init(void);
#endif
+369
View File
@@ -0,0 +1,369 @@
#include "mqtt_manager.h"
#include "mqtt_config.h"
#include "mqtt_protocol.h"
#include "wifi_manager.h"
#include "app_log.h"
#include "mqtt/MQTTClient.h"
#include "os/os_api.h"
#include <string.h>
#include <stdio.h>
/*
* MQTT对象
*
* 按AC79官方demo改成静态生命周期
*/
static Client mqtt_client;
static Network mqtt_network;
/*
* MQTT状态
*/
static mqtt_state_t mqtt_state = MQTT_STATE_INIT;
static u32 mqtt_reconnect_delay = 0;
/*
* MQTT消息回调
*/
static mqtt_message_callback_t message_callback = NULL;
/*
* MQTT缓存
*
* AC79 Paho需要
*/
static unsigned char mqtt_send_buffer[2048];
static unsigned char mqtt_read_buffer[2048];
/*
* 收到MQTT消息
*
* 对应ESP32:
*
* mqtt event callback
*/
static void message_arrived
(
MessageData *data
)
{
/*
* 先交给协议层
*
* 已识别的小智消息由协议层处理
*/
if(
mqtt_protocol_handle_message(
data->topicName->lenstring.data,
(uint8_t *)data->message->payload,
data->message->payloadlen
) == 0
)
{
return;
}
if(message_callback == NULL)
{
return;
}
APP_LOG("mqtt message arrived\n");
APP_LOG(
"topic:%s\n",
data->topicName->lenstring.data
);
APP_LOG(
"payload:%.*s\n",
data->message->payloadlen,
data->message->payload
);
mqtt_message_callback_t cb =
message_callback;
cb(
data->topicName->lenstring.data,
(uint8_t *)data->message->payload,
data->message->payloadlen
);
}
/*
* MQTT连接
*/
static int mqtt_connect_server(void)
{
mqtt_config_t *cfg = mqtt_config_get();
MQTTPacket_connectData connect_data = MQTTPacket_connectData_initializer;
/*
* 创建Network
*/
NewNetwork(&mqtt_network);
SetNetworkRecvTimeout(
&mqtt_network,
1000
);
/*
* TCP连接
*/
if(ConnectNetwork(&mqtt_network,cfg->host,cfg->port))
{
APP_LOG("mqtt tcp connect fail\n");
mqtt_state =
MQTT_STATE_ERROR;
return -1;
}
APP_LOG("mqtt tcp connect ok\n");
/*
* 创建MQTT Client
*/
MQTTClient(
&mqtt_client, // 客户端对象-->我的设备
&mqtt_network, // 已经建立的 TCP 网络
1000, // 命令超时 ms
mqtt_send_buffer, // 发送缓冲区
sizeof(mqtt_send_buffer),
mqtt_read_buffer, // 接收缓冲区
sizeof(mqtt_read_buffer)
);
/*
* MQTT身份
*
* 暂时使用config中的固定值
*/
connect_data.clientID.cstring = cfg->client_id;
if (cfg->username[0])
{
connect_data.username.cstring =
cfg->username;
}
if (cfg->password[0])
{
connect_data.password.cstring =
cfg->password;
}
connect_data.keepAliveInterval =
cfg->keepalive;
/*
* 建立MQTT连接
*/
int rc = MQTTConnect( &mqtt_client, &connect_data);
APP_LOG("MQTTConnect rc=%d\n", rc);
if(rc)
{
APP_LOG("mqtt connect failed\n");
mqtt_network.disconnect(
&mqtt_network
);
mqtt_state = MQTT_STATE_ERROR;
return -1;
}
APP_LOG("mqtt connect ok\n");
mqtt_state = MQTT_STATE_CONNECTED;
return 0;
}
/*
* MQTT任务
*/
static void mqtt_task(void *arg)
{
while(1)
{
if(
!wifi_manager_is_network_ready()
)
{
os_time_dly(200);
continue;
}
if(
mqtt_state != MQTT_STATE_CONNECTED
)
{
mqtt_state = MQTT_STATE_CONNECTING;
if(mqtt_connect_server())
{
if (mqtt_reconnect_delay < 16000)
{
mqtt_reconnect_delay =
mqtt_reconnect_delay ?
mqtt_reconnect_delay * 2 : 500;
}
os_time_dly(mqtt_reconnect_delay);
continue;
}
mqtt_reconnect_delay = 0;
/*
* 连接成功后订阅
*/
if(MQTTSubscribe
(
&mqtt_client,
mqtt_config_get()->subscribe_topic,
QOS0,
message_arrived
)
)
{
APP_LOG("mqtt subscribe failed\n");
MQTTDisconnect(
&mqtt_client
);
mqtt_network.disconnect(
&mqtt_network
);
mqtt_state =
MQTT_STATE_ERROR;
continue;
}
APP_LOG("mqtt subscribe ok\n");
char online_payload[256];
snprintf(
online_payload,
sizeof(online_payload),
"{\"id\":1,\"method\":\"thing.event.property.post\","
"\"params\":{\"deviceId\":\"%s\",\"reportType\":\"heartbeat\","
"\"personDetected\":0,\"heartbeat\":1}}",
mqtt_config_get()->username
);
int pub_ret = mqtt_manager_publish(
mqtt_config_get()->publish_topic,
(const uint8_t *)online_payload,
(uint32_t)strlen(online_payload)
);
APP_LOG("mqtt online publish ret=%d\n", pub_ret);
}
/*
* 保持MQTT通信
*
* 收消息依靠yield
*/
MQTTYield
(
&mqtt_client,
1000
);
os_time_dly(10);
}
}
int mqtt_manager_init(void)
{
mqtt_config_init();
mqtt_state = MQTT_STATE_INIT;
return 0;
}
int mqtt_manager_start(void)
{
return thread_fork(
"mqtt_task",
10,
2048,
0,
NULL,
mqtt_task,
NULL
);
}
int mqtt_manager_publish(const char *topic,const uint8_t *data,uint32_t len)
{
MQTTMessage message;
memset(
&message,
0,
sizeof(message)
);
message.qos = QOS0;
message.payload = (void *)data;
message.payloadlen = len;
return MQTTPublish
(
&mqtt_client,
topic,
&message
);
}
void mqtt_manager_set_callback(mqtt_message_callback_t callback)
{
message_callback = callback;
}
mqtt_state_t mqtt_manager_get_state(void)
{
return mqtt_state;
}
+88
View File
@@ -0,0 +1,88 @@
#ifndef MQTT_MANAGER_H
#define MQTT_MANAGER_H
#include <stdint.h>
/*
* MQTT状态
*/
typedef enum
{
MQTT_STATE_INIT = 0,
MQTT_STATE_CONNECTING,
MQTT_STATE_CONNECTED,
MQTT_STATE_DISCONNECTED,
MQTT_STATE_ERROR
} mqtt_state_t;
/*
* MQTT消息接收回调
*
* topic:
* 主题
*
* payload:
* 数据
*
* len:
* 长度
*/
typedef void (*mqtt_message_callback_t)//函数指针==指针==保存函数地址的指针
(
const char *topic,
const uint8_t *payload,
uint32_t len
);
/*
* MQTT初始化
*/
int mqtt_manager_init(void);
/*
* 启动MQTT任务
*/
int mqtt_manager_start(void);
/*
* 发布数据
*/
int mqtt_manager_publish
(
const char *topic,
const uint8_t *data,
uint32_t len
);
/*
* 设置接收回调
*/
void mqtt_manager_set_callback
(
mqtt_message_callback_t callback
);
/*
* 获取MQTT状态
*/
mqtt_state_t mqtt_manager_get_state(void);
#endif
+389
View File
@@ -0,0 +1,389 @@
#include "mqtt_protocol.h"
#include "mqtt_config.h"
#include "mqtt_manager.h"
#include "app_log.h"
#include "system/includes.h"
#include "json_c/json.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
/*
* 当前会话ID
*/
static char protocol_session_id[64];
/*
* 协议消息回调
*/
static mqtt_protocol_callback_t protocol_callback = NULL;
/*
* 解析type字段
*/
static enum mqtt_protocol_message_type parse_type(const char *value)
{
if (!value)
{
return MQTT_PROTOCOL_MSG_UNKNOWN;
}
if (!strcmp(value, "hello"))
{
return MQTT_PROTOCOL_MSG_HELLO;
}
if (!strcmp(value, "tts"))
{
return MQTT_PROTOCOL_MSG_TTS;
}
if (!strcmp(value, "stt"))
{
return MQTT_PROTOCOL_MSG_STT;
}
if (!strcmp(value, "llm"))
{
return MQTT_PROTOCOL_MSG_LLM;
}
if (!strcmp(value, "listen"))
{
return MQTT_PROTOCOL_MSG_LISTEN;
}
if (!strcmp(value, "goodbye"))
{
return MQTT_PROTOCOL_MSG_GOODBYE;
}
return MQTT_PROTOCOL_MSG_UNKNOWN;
}
/*
* 解析state字段
*/
static enum mqtt_protocol_message_state parse_state(const char *value)
{
if (!value)
{
return MQTT_PROTOCOL_STATE_NONE;
}
if (!strcmp(value, "start"))
{
return MQTT_PROTOCOL_STATE_START;
}
if (!strcmp(value, "sentence_start"))
{
return MQTT_PROTOCOL_STATE_SENTENCE_START;
}
if (!strcmp(value, "stop"))
{
return MQTT_PROTOCOL_STATE_STOP;
}
if (!strcmp(value, "detect"))
{
return MQTT_PROTOCOL_STATE_DETECT;
}
return MQTT_PROTOCOL_STATE_NONE;
}
/*
* 解析收到的MQTT消息
*/
static int protocol_parse
(
const char *payload,
uint32_t len,
struct mqtt_protocol_message *message
)
{
json_object *root;
json_object *item;
char *json_buf;
const char *value;
if (!payload || !len || !message)
{
return -1;
}
memset(message, 0, sizeof(*message));
json_buf = zalloc(len + 1);
if (!json_buf)
{
return -1;
}
memcpy(json_buf, payload, len);
root = json_tokener_parse(json_buf);
free(json_buf);
if (!root)
{
return -1;
}
if (json_object_object_get_ex(root, "type", &item))
{
message->type = parse_type(json_object_get_string(item));
}
if (json_object_object_get_ex(root, "state", &item))
{
message->state = parse_state(json_object_get_string(item));
}
if (json_object_object_get_ex(root, "code", &item))
{
message->has_code = 1;
message->code = json_object_get_int(item);
}
if (json_object_object_get_ex(root, "version", &item))
{
message->has_version = 1;
message->version = json_object_get_int(item);
}
if (json_object_object_get_ex(root, "transport", &item))
{
value = json_object_get_string(item);
if (value)
{
snprintf(message->transport, sizeof(message->transport), "%s", value);
}
}
if (json_object_object_get_ex(root, "session_id", &item))
{
value = json_object_get_string(item);
if (value)
{
snprintf(message->session_id, sizeof(message->session_id), "%s", value);
}
}
if (json_object_object_get_ex(root, "text", &item))
{
value = json_object_get_string(item);
if (value)
{
snprintf(message->text, sizeof(message->text), "%s", value);
}
}
json_object_put(root);
return message->type == MQTT_PROTOCOL_MSG_UNKNOWN ? -1 : 0;
}
/*
* 发送JSON文本到发布topic
*/
static int protocol_send_text(const char *text)
{
if (!text)
{
return -1;
}
return mqtt_manager_publish(
mqtt_config_get()->publish_topic,
(const uint8_t *)text,
strlen(text)
);
}
/*
* 带session_id拼接JSON
*/
static int protocol_send_jsonf(const char *fmt, ...)
{
char buf[256];
va_list ap;
int len;
if (!fmt)
{
return -1;
}
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (len <= 0 || len >= sizeof(buf))
{
return -1;
}
return protocol_send_text(buf);
}
int mqtt_protocol_handle_message
(
const char *topic,
const uint8_t *payload,
uint32_t len
)
{
struct mqtt_protocol_message message;
if (protocol_parse((const char *)payload, len, &message))
{
return -1;
}
if (message.session_id[0])
{
strcpy(protocol_session_id, message.session_id);
}
if (message.type == MQTT_PROTOCOL_MSG_HELLO)
{
APP_LOG(
"[MQTT_P] hello: code=%d session=%s\n",
message.has_code ? message.code : -1,
protocol_session_id
);
}
else if (message.type == MQTT_PROTOCOL_MSG_GOODBYE)
{
APP_LOG(
"[MQTT_P] goodbye: session=%s\n",
message.session_id[0] ? message.session_id : "-"
);
protocol_session_id[0] = '\0';
}
if (protocol_callback)
{
protocol_callback(&message);
}
return 0;
}
int mqtt_protocol_send_hello(void)
{
return protocol_send_jsonf(
"{\"type\":\"hello\",\"version\":3,\"transport\":\"udp\","
"\"features\":{\"mcp\":true},"
"\"audio_params\":{\"format\":\"opus\",\"sample_rate\":16000,"
"\"channels\":1,\"frame_duration\":60}}"
);
}
int mqtt_protocol_send_listen_start(void)
{
if (protocol_session_id[0])
{
return protocol_send_jsonf(
"{\"type\":\"listen\",\"state\":\"start\",\"session_id\":\"%s\"}",
protocol_session_id
);
}
return protocol_send_jsonf("{\"type\":\"listen\",\"state\":\"start\"}");
}
int mqtt_protocol_send_listen_stop(void)
{
if (protocol_session_id[0])
{
return protocol_send_jsonf(
"{\"type\":\"listen\",\"state\":\"stop\",\"session_id\":\"%s\"}",
protocol_session_id
);
}
return protocol_send_jsonf("{\"type\":\"listen\",\"state\":\"stop\"}");
}
int mqtt_protocol_send_abort(void)
{
if (protocol_session_id[0])
{
return protocol_send_jsonf(
"{\"type\":\"abort\",\"session_id\":\"%s\"}",
protocol_session_id
);
}
return protocol_send_jsonf("{\"type\":\"abort\"}");
}
int mqtt_protocol_send_goodbye(void)
{
if (protocol_session_id[0])
{
return protocol_send_jsonf(
"{\"type\":\"goodbye\",\"session_id\":\"%s\"}",
protocol_session_id
);
}
return -1;
}
const char *mqtt_protocol_session_id(void)
{
return protocol_session_id;
}
void mqtt_protocol_set_callback(mqtt_protocol_callback_t callback)
{
protocol_callback = callback;
}
+138
View File
@@ -0,0 +1,138 @@
#ifndef MQTT_PROTOCOL_H
#define MQTT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
/*
* 小智MQTT消息类型
*/
enum mqtt_protocol_message_type
{
MQTT_PROTOCOL_MSG_UNKNOWN = 0,
MQTT_PROTOCOL_MSG_HELLO,
MQTT_PROTOCOL_MSG_TTS,
MQTT_PROTOCOL_MSG_STT,
MQTT_PROTOCOL_MSG_LLM,
MQTT_PROTOCOL_MSG_LISTEN,
MQTT_PROTOCOL_MSG_GOODBYE
};
/*
* 小智MQTT消息状态
*/
enum mqtt_protocol_message_state
{
MQTT_PROTOCOL_STATE_NONE = 0,
MQTT_PROTOCOL_STATE_START,
MQTT_PROTOCOL_STATE_SENTENCE_START,
MQTT_PROTOCOL_STATE_STOP,
MQTT_PROTOCOL_STATE_DETECT
};
/*
* 小智MQTT消息
*/
struct mqtt_protocol_message
{
enum mqtt_protocol_message_type type;
enum mqtt_protocol_message_state state;
int has_code;
int code;
int has_version;
int version;
char transport[16];
char session_id[64];
char text[160];
};
/*
* 消息回调
*
* 返回0表示协议层已处理, 返回-1表示无法识别
*/
int mqtt_protocol_handle_message
(
const char *topic,
const uint8_t *payload,
uint32_t len
);
/*
* 发送hello, 申请会话
*/
int mqtt_protocol_send_hello(void);
/*
* 发送监听开始
*/
int mqtt_protocol_send_listen_start(void);
/*
* 发送监听停止
*/
int mqtt_protocol_send_listen_stop(void);
/*
* 发送中止
*/
int mqtt_protocol_send_abort(void);
/*
* 发送bye
*/
int mqtt_protocol_send_goodbye(void);
/*
* 获取当前会话ID
*/
const char *mqtt_protocol_session_id(void);
/*
* 设置协议消息回调
*/
typedef void (*mqtt_protocol_callback_t)
(
const struct mqtt_protocol_message *message
);
void mqtt_protocol_set_callback(mqtt_protocol_callback_t callback);
#endif