除了显示驱动,其余全部测试通过
This commit is contained in:
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user