安信可(云知声蜂鸟US516P6)SDK开发学习---log日志打印子系统模块
安信可(云知声蜂鸟US516P6)SDK开发学习—log日志打印子系统模块
文章目录
- 安信可(云知声蜂鸟US516P6)SDK开发学习---log日志打印子系统模块
- 0.0 核心产品系列:VC系列离线语音模块
- 0.0.1 核心产品系列硬件架构与性能
- 0.0.2 开发流程:零代码定制与二次开发
- 0.0.3 应用场景与典型案例
- 0.0.4 选型对比与注意事项
- 1.0 硬件日志接口设计
- 2.0 日志分级与分类
- 3.0 开发调试支持
- 4.0 应用场景与案例
- 5.0 最佳实践建议
- 6.0 总结
- 7.0 参考代码
关于安信可语音模块的全面解析,结合其核心产品系列(VC系列)、技术特性、开发流程及应用场景,综合多份技术资料整理而成:
0.0 核心产品系列:VC系列离线语音模块
0.0.1 核心产品系列硬件架构与性能
主控芯片:云知声锋鸟M(US516P6)
32位RISC内核,主频240MHz,集成DSP指令集、FPU浮点单元及FFT加速器。
内置2MB Flash + 242KB SRAM,支持1024点复数FFT运算(加速音频处理)。
音频性能:
单麦克风输入(SNR≥94dB),双通道DAC输出。
支持AEC回声消除、稳态降噪,5米远场唤醒,抗干扰能力强。
识别能力:
支持150条本地指令离线识别,中英文双语控制。
响应时间<100ms,综合识别率≥98%,误唤醒率极低。
接口与功耗
接口类型 支持功能 应用场景
UART 串口通信(默认115200bps) 与MCU数据交互(如STM32)
I²C/SPI 外设扩展(传感器、显示屏) 环境参数读取
PWM 电机/灯光控制 智能调光、风扇调速
GPIO 自定义按键/指示灯 唤醒触发、状态反馈
功耗:工作电压3.6V–5V,休眠电流低至8μA,适合电池供电设备。
0.0.2 开发流程:零代码定制与二次开发
零代码开发(安信可语音开放平台)
词条定制:在线设置唤醒词(如“小安小安”)、指令词(如“打开灯光”)及回复语音。
固件生成:自助生成SDK并编译烧录,无需编写代码。
配置示例:
步骤:
注册平台 → 创建产品(如智能台灯)→ 选择VC-02模组。
关闭AEC降噪(避免与自学习冲突)→ 配置UART引脚为通信接口。
设置应答词:“已开灯” → 生成固件 → 烧录至模块。
二次开发(MCU集成)
通信协议:通过UART发送结构化数据包,格式示例:
// 指令格式:[包头 0xAA] [命令字] [数据长度] [数据] [校验和]
uint8_t cmd_open_light[] = {0xAA, 0x01, 0x01, 0x01, 0xAC}; // 开灯指令
关键函数:
void UART_SendCmd(uint8_t cmd) {HAL_UART_Transmit(&huart1, cmd, sizeof(cmd), 100); // STM32示例
中断处理:接收模块返回的状态码(如识别成功/失败)。
0.0.3 应用场景与典型案例
智能家居
灯具控制:语音指令调节亮度/色温(如“调至暖光模式”)。
家电联动:
抽油烟机:喊“加大风力”自动调整档位。
空调:通过红外转发器语音控温(需搭配红外学习模块)。
工业控制
语音遥控器:离线指令控制车间设备(如“启动传送带”),响应快且无网络依赖。
安防系统:声控布防/撤防(如“进入警戒模式”),保护隐私数据安全。
低成本方案
VC-02模组:单价约10元人民币,尺寸仅18×17mm,适合嵌入式小家电。
开发板套件:含麦克风、喇叭腔体,25元即可原型验证。
0.0.4 选型对比与注意事项
VC-01 vs VC-02 核心差异
参数 VC-01 VC-02
封装 25.5×24mm (SMD) 18×17mm (SMD-20)
功耗 500mA@5V 500mA@3.6–5V
接口 支持I²C/SPI/PWM 同VC-01,GPIO更多
适用场景 大家电(空调、洗衣机) 小家电(台灯、插座)
设计建议
抗干扰布线:
麦克风走线远离电源,包地处理。
启用稳态降噪时,避免同时使用自学习功能。
功耗优化:
非活跃期关闭麦克风供电,休眠电流降至μA级。
安全冗余:
关键指令双重验证(如“确认关灯” → “是的”)。
💎 总结
安信可VC系列语音模块以高识别率离线控制、零代码开发平台及超低成本优势,成为智能家居/工业控制的理想选择:
✅ 优先选VC-02:小尺寸、低功耗,适合灯具/插座等小设备;
✅ 复杂场景用VC-01:丰富接口支持大家电多功能集成;
✅ 务必验证引脚配置:避免A28引脚电平冲突导致音频失效。
🔍 扩展资源:
-
https://voice.ai-thinker.com/:在线定制词条
-
《VC-02硬件设计指南》:
引脚定义与PCB布局规范
通过合理选型与开发流程,可快速实现“免联网、即说即控”的智能化升级。
安信可的日志打印子系统模块是其嵌入式开发平台中的核心调试工具,主要用于设备运行状态监控、故障排查和数据传输追踪。该系统通过硬件串口和软件接口实现多级日志管理,以下是其关键特性及应用详解:
1.0 硬件日志接口设计
双串口架构
AT
指令串口:用于发送控制命令(如AT+LOG=1开启日志),对应模块的PB1/AT_TX和PB2/AT_RX引脚。
LOG专用串口:独立用于日志输出(如PA30/LOG_TX和PA15/LOG_RX),避免与业务通信串口冲突,确保日志实时性。
典型应用:在BW16模块中,LOG串口可实时打印WiFi连接状态、数据包传输详情及错误码。
低功耗优化
支持动态关闭日志输出(AT+LOG=0),休眠模式下电流低至8μA,适用于电池供电场景(如Ra-09 LoRa模块)。
2.0 日志分级与分类
安信可日志系统采用五级分类策略,与Android Logcat设计类似:
级别 标识符 应用场景 示例指令
Verbose V 底层通信细节(如字节流) [V] TX: 0x12 0x34…
Debug D 模块状态变更(如网络重连) [D] WiFi reconnect…
Info I 关键操作记录(如MQTT连接) [I] MQTT connected
Warn W 非致命异常(如信号弱) [W] RSSI <-90dBm
Error E 硬件错误或协议失败 [E] GPS signal lost!
通过指令AT+LOG_LEVEL=2可动态调整输出级别(如仅显示Warn及以上)。
日志分级与分类
3.0 开发调试支持
固件下载与日志关联
LOG串口支持固件烧录(如A9G模块),烧录过程日志实时输出至串口助手,便于定位固件兼容性问题。
工具链:需配合coolwatcher工具链(CSDTK环境)实现日志捕获与解析。
环形缓冲区技术
突发高流量日志场景下(如GPS数据持续上报),自动启用内存缓存,避免丢失关键故障信息。
4.0 应用场景与案例
工业物联网:
Ra-09模块通过LOG串口记录LoRaWAN入网过程(如+EVT:JOIN_SUCCESS),结合TTN平台实现远程诊断。
智能家居:
BW16模块在连接云端失败时,输出[E] TCP Timeout并触发自动重连机制。
低功耗设备:
A9G模块休眠前自动保存未发送日志至Flash,唤醒后续传至云端。
5.0 最佳实践建议
资源优化
量产固件关闭Verbose/Debug日志(AT+LOG_LEVEL=4),仅保留Error级输出以减少Flash磨损。
安全增强
敏感信息(如WiFi密码)自动脱敏处理,日志中显示为[I] Connect to SSID: *。
多平台兼容
日志格式兼容主流分析工具(如Wireshark、PyCharm插件),支持时间戳和模块ID过滤。
6.0 总结
安信可日志子系统通过硬件隔离串口、五级分类机制及低功耗设计,为嵌入式开发提供全生命周期调试支持。开发者在复杂场景(如LoRaWAN协议栈调试或MQTT重连)中,可结合指令控制与环形缓存技术,实现故障快速闭环。
🔍 扩展参考:
-
https://docs.ai-thinker.com/
-
https://blog.csdn.net/Boantong_
通过合理运用日志分级与硬件资源,可显著提升设备可维护性及开发效率。
7.0 参考代码
uni_log.c
/*************************************************************************** Copyright (C) 2017-2017 Unisound** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License along* with this program; if not, write to the Free Software Foundation, Inc.,* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.**************************************************************************** Description : uni_log.c* Author : wufangfang@unisound.com* Date : 2019.09.10***************************************************************************/#include "osal-log.h"
#include "uni_log.h"
#include "uni_iot.h"
#include <stdarg.h>#define BUF_DEFAULT_LEN (255)typedef enum {LOG_WORK_INIT = 0,LOG_WORK_IDLE,LOG_WORK_RUNNING
}log_work_state;typedef struct {log_work_state state;LogLevel set_level;char buffer[BUF_DEFAULT_LEN];uni_mutex_t mutex;
} log_context_t;static log_context_t *g_log_context = NULL;static const char* _level_tostring(LogLevel level) {switch (level) {case N_LOG_ERROR: return "[E]";case N_LOG_DEBUG: return "[D]";case N_LOG_TRACK: return "[T]";case N_LOG_WARN: return "[W]";default: return "[N/A]";}
}static void _get_thread_id_str(char *buf, int len) {uni_snprintf(buf, len, "%llu", uni_get_clock_time_ms());
}static int _fill_log_level(LogLevel level, char *buf, int len) {int write_len = 0;switch (level) {case N_LOG_DEBUG:write_len = uni_snprintf(buf, len, "\033[0m\033[47;33m%s\033[0m ",_level_tostring(N_LOG_DEBUG));break;case N_LOG_TRACK:write_len = uni_snprintf(buf, len, "\033[0m\033[42;33m%s\033[0m ",_level_tostring(N_LOG_TRACK));break;case N_LOG_WARN:write_len = uni_snprintf(buf, len, "\033[0m\033[41;33m%s\033[0m ",_level_tostring(N_LOG_WARN));break;case N_LOG_ERROR:write_len = uni_snprintf(buf, len, "\033[0m\033[41;33m%s\033[0m ",_level_tostring(N_LOG_ERROR));break;default:break;}return uni_max(0, write_len);
}static int _fill_tag(char *buf, int len, const char *tag) {return uni_max(0, uni_snprintf(buf, len, "<%s>", tag));
}static int _fill_function_line(char *buf, int len,const char *function, int line) {return uni_max(0, uni_snprintf(buf, len, "%s:%d->", function, line));
}static int _fill_thread_id(char *buf, int len) {char thread_id[32] = {0};_get_thread_id_str(thread_id, sizeof(thread_id));return uni_max(0, uni_snprintf(buf, len, "%s", thread_id));
}static void _fill_customer_info(char *buf, int len, const char *fmt, va_list args,int append_feed_line) {int length, remain_len;length = vsnprintf(buf, len, fmt, args);length = uni_max(length, 0);length = uni_min(length, len);remain_len = len - length;if (0 == remain_len) {if (append_feed_line) {buf[len - 2] = '\n';}buf[len - 1] = '\0';return;}if (1 == remain_len) {if (append_feed_line) {buf[len - 2] = '\n';}return;}if (append_feed_line) {uni_strncat(buf, "\n", remain_len);}return;
}uni_bool LogLevelValid(LogLevel level) {if (!g_log_context) {return false;}return level <= g_log_context->set_level ? true : false;
}static void _sync_write_process(LogLevel level, const char *tags,const char *function, int line,const char *fmt, va_list args) {int len = 0;if (!g_log_context) {return ;}if (level != N_LOG_RAW) {len += _fill_log_level(level, g_log_context->buffer + len,BUF_DEFAULT_LEN - len);len += _fill_thread_id(g_log_context->buffer + len, BUF_DEFAULT_LEN - len);len += _fill_tag(g_log_context->buffer + len, BUF_DEFAULT_LEN - len, tags);len += _fill_function_line(g_log_context->buffer + len,BUF_DEFAULT_LEN - len, function, line);}_fill_customer_info(g_log_context->buffer + len, BUF_DEFAULT_LEN - len,fmt, args, level != N_LOG_RAW);uni_printf("%s", g_log_context->buffer);
}//implement aik Log func
void OsalLogDump(OsalLogLevel level, const char* tags, const char* function,uint32_t line, const char* fmt, ...){int uni_level;if (!g_log_context) {return ;}if (LOG_WORK_RUNNING != g_log_context->state) {return ;}uni_level = 5 - level;if (LogLevelValid(uni_level)) {uni_pthread_mutex_lock(g_log_context->mutex);va_list args;va_start(args, fmt);_sync_write_process(uni_level, tags, function, line, fmt, args);va_end(args);uni_pthread_mutex_unlock(g_log_context->mutex);}
}int LogWrite(LogLevel level, const char *tags,const char *function, int line, char *fmt, ...) {if (!g_log_context) {return -1;}if (LOG_WORK_RUNNING != g_log_context->state) {return -1;}uni_pthread_mutex_lock(g_log_context->mutex);va_list args;va_start(args, fmt);_sync_write_process(level, tags, function, line, fmt, args);va_end(args);uni_pthread_mutex_unlock(g_log_context->mutex);return 0;
}int LogLevelSet(LogLevel level) {if (!g_log_context) {return -1;}g_log_context->set_level = level;return 0;
}static int _log_mutex_init(void) {uni_pthread_mutex_init(&g_log_context->mutex);return 0;
}static void _log_mutex_final(void) {uni_pthread_mutex_destroy(g_log_context->mutex);
}int LogInitialize(void) {if (g_log_context) {return -1;}g_log_context = (log_context_t *)uni_malloc(sizeof(log_context_t));if (!g_log_context) {return -1;}_log_mutex_init();g_log_context->state = LOG_WORK_RUNNING;return 0;
}void LogFinalize(void) {if (LOG_WORK_INIT != g_log_context->state) {_log_mutex_final();g_log_context->state = LOG_WORK_INIT;}if (g_log_context) {uni_free(g_log_context);g_log_context = NULL;}
}ubi_log.h```c
/*************************************************************************** Copyright (C) 2017-2017 Unisound** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License along* with this program; if not, write to the Free Software Foundation, Inc.,* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.**************************************************************************** Description : uni_log.h* Author : wufangfang@unisound.com* Date : 2019.09.10***************************************************************************/#ifndef HAL_INC_UNI_LOG_H_
#define HAL_INC_UNI_LOG_H_#ifdef __cplusplus
extern "C" {
#endif#include "uni_types.h"typedef enum {N_LOG_NONE = -1,N_LOG_ERROR,N_LOG_WARN,N_LOG_TRACK,N_LOG_DEBUG,N_LOG_RAW,N_LOG_ALL
} LogLevel;/*** Usage: Initialize log print* Params: * Return: Result of initialize*/
int LogInitialize(void);/*** Usage: Finalize log print* Params: * Return: */
void LogFinalize(void);/*** Usage: Set print level* Params: level: level that can print* Return: Result of set*/
int LogLevelSet(LogLevel level);/*** Usage: Verify the level can be print or not* Params: level: level that can print* Return: true or false*/
uni_bool LogLevelValid(LogLevel level);/*** Usage: Print log string with format data* Params: level: print level* tags: tag string of modul* function: function name* line: line number of log code* fmt: fomat string* Return: Result of print*/
int LogWrite(LogLevel level, const char *tags, const char *function,int line, char *fmt, ...);#define LOG(level, tag, fmt, ...) do { \if (LogLevelValid(level)) { \LogWrite(level, tag, __FUNCTION__, __LINE__, (char *)fmt, ##__VA_ARGS__); \} \
} while (0)#define LOGD(tag, fmt, ...) LOG(N_LOG_DEBUG, tag, fmt, ##__VA_ARGS__)
#define LOGT(tag, fmt, ...) LOG(N_LOG_TRACK, tag, fmt, ##__VA_ARGS__)
#define LOGW(tag, fmt, ...) LOG(N_LOG_WARN, tag, fmt, ##__VA_ARGS__)
#define LOGE(tag, fmt, ...) LOG(N_LOG_ERROR, tag, fmt, ##__VA_ARGS__)
#define LOGR(tag, fmt, ...) LOG(N_LOG_RAW, tag, fmt, ##__VA_ARGS__)#ifdef __cplusplus
}
#endif
#endif /*_IPC_DRV_H_*/
#define uni_printf printf
#define uni_sprintf sprintf
#define uni_snprintf snprintf
主程序调用接口```c
static int _init_log_print(void) {uni_s64 tmp = 0;if (0 != ConfigReadItemNumber("log.enable", &tmp)) {printf("Cannot found log.enable, disable log print\r\n");return 0;}if (tmp) {if (0 != LogInitialize()) {printf("LogInitialize failed !\r\n");return -1;}LogLevelSet(N_LOG_NONE);if (0 == ConfigReadItemNumber("log.set_level", &tmp)) {LogLevelSet((LogLevel)tmp);}}return 0;
}
LOG函数打印示意
Result MediaPlayerInit(MediaPlayerparam *param) {if (NULL == param) {LOGE(MEDIA_PLAYER_TAG, "param null");return E_FAILED;}uni_memset(&g_mediaplayer, 0, sizeof(MediaPlayer));uni_memcpy(&g_mediaplayer.param, param, sizeof(MediaPlayerparam));g_mediaplayer.is_shutup = false;_mutex_init();if (E_OK != _init_player_audio()) {LOGE(MEDIA_PLAYER_TAG, "_init_player_audio failed !");_mutex_destroy();return E_FAILED;}_set_volume(MEDIA_VOLUME_DEFAULT);if (E_OK != _register_all_player()) {LOGE(MEDIA_PLAYER_TAG, "_register_all_player failed !");_final_player_audio();_mutex_destroy();return E_FAILED;}LOGT(MEDIA_PLAYER_TAG, "mediaplayer init success");return E_OK;
}