From: snickersun Date: Fri, 15 May 2026 07:18:24 +0000 (+0800) Subject: 添加debug uart打印日志功能。方便调试电流 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=abd96fbdd3574eec4e9a1ea09a9e1f723a8baa6e;p=mirrors%2FASR1603_G5.git 添加debug uart打印日志功能。方便调试电流 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..85ee768d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +2.sdk/release/** \ No newline at end of file diff --git "a/1.doc/AI\345\220\212\345\235\240\357\274\210\345\217\214\346\214\211\351\224\256+\344\270\211\350\211\262\346\214\207\347\244\272\347\201\257\357\274\211\344\272\244\344\272\222\350\247\204\350\214\203_new.md" "b/1.doc/AI\345\220\212\345\235\240\357\274\210\345\217\214\346\214\211\351\224\256+\344\270\211\350\211\262\346\214\207\347\244\272\347\201\257\357\274\211\344\272\244\344\272\222\350\247\204\350\214\203_new.md" new file mode 100644 index 00000000..d6db6a86 --- /dev/null +++ "b/1.doc/AI\345\220\212\345\235\240\357\274\210\345\217\214\346\214\211\351\224\256+\344\270\211\350\211\262\346\214\207\347\244\272\347\201\257\357\274\211\344\272\244\344\272\222\350\247\204\350\214\203_new.md" @@ -0,0 +1,396 @@ +# AI吊坠(双按键+三色指示灯)交互规范 + +核心原则:**操作有反馈、状态有提示、逻辑不冲突**,适配吊坠随身佩戴、无屏操作场景,按键+灯光+提示音三者联动,让用户无需记忆,凭直观反馈即可判断设备状态。 + +基础约定: + +- 按键:Power键(开关键)、AI键(语音交互键) +- 指示灯:红(R)、蓝(B)、绿(G)三色(遵循定义:绿=正常/电量/充满电;蓝=AI交互;红=低电/异常) +- 提示音:采用短促、清晰的单音/双音,区分不同操作,音量适中(避免刺耳,适配贴身佩戴),支持后续可调节(可选) +- 操作逻辑:长按=特殊功能(开关机、强制重启、连续对话);短按/双击=常用功能(唤醒、打断、复读),杜绝误触 + +### LED 灯效与时间术语(与工程 `ai_VC.AI_led` 对齐) + +数字 GPIO 无 PWM 时,**闪 / 慢闪 / 交替 / 慢交替** 均由 `osTimer` 节拍 `**period_ms`** 驱动,含义如下。 + +**单色亮灭(闪、慢闪)**:每隔 `period_ms` 在 **亮 / 灭** 之间翻转一次,故 **一整次「亮→灭→亮」约 `2 × period_ms`**。 + + +| 术语 | 时间含义 | 默认 `period_ms`(半拍) | +| ------ | ------------- | ------------------ | +| **闪** | 约 **1 s** 一亮灭 | `500` | +| **慢闪** | 约 **2 s** 一亮灭 | `1000` | + + +**双色交替(交替、慢交替)**:每隔 `period_ms` **换一色**(蓝↔绿),故 **单色持续约 `period_ms`,蓝→绿→蓝一整圈约 `2 × period_ms`**。 + + +| 术语 | 时间含义 | 默认 `period_ms`(换色间隔) | +| ------------ | --------------- | -------------------- | +| **交替/交替闪** | 约 **0.5 s 换一色** | `500` | +| **慢交替/交替慢闪** | 约 **1 s 换一色** | `1000` | + + +**工程映射(默认)**:聆听蓝 **慢闪**、低电红 **慢闪**、待机绿 **慢闪** → `1000`;思考蓝绿 **交替** → `500`;弱网蓝绿 **慢交替** → `1000`。正文若写「快闪 / 2 次/秒」等,表示周期短于「闪」,工程可按场景单独设 `period_ms`(例如 `**250`** 约 0.5 s 一亮灭,便于对齐「2 次/秒」计数),与上表不冲突。 + +## 备注 + +休眠模式:无灯光,无提示音(最低电量消耗) + +聆听模式:蓝灯闪(1 分钟内无交互,自动进入待机模式) + +思考模式:蓝绿交替闪 + +播放模式:绿灯闪 + +待机模式:绿色慢闪(2 分钟内无交互,自动进入休眠模式) + +进入聆听模式:单声“滴”(短促) + +[请至钉钉文档查看附件《start.mp3》。](https://alidocs.dingtalk.com/i/nodes/KGZLxjv9VGj15aBlU1wKrXGzW6EDybno?iframeQuery=anchorId%3DX02moo4wrj78r6ita1utoy&utm_scene=person_space) + +接入拾音/进入思考:单声“层”(短促,有尾音) + +[请至钉钉文档查看附件《5c893cf044bde33914.mp3》。](https://alidocs.dingtalk.com/i/nodes/KGZLxjv9VGj15aBlU1wKrXGzW6EDybno?iframeQuery=anchorId%3DX02moo4y0r5romh54qr1l&utm_scene=person_space) + +开机提示音 + +[请至钉钉文档查看附件《开机.mp3》。](https://alidocs.dingtalk.com/i/nodes/KGZLxjv9VGj15aBlU1wKrXGzW6EDybno?iframeQuery=anchorId%3DX02moo4z0qlkd1hwu42as&utm_scene=person_space) + +## 第一部分:基础操作(Power键)+ 灯光+提示音联动 + + +| 操作动作 | 设备当前状态 | 指示灯状态 | 提示音 | 执行结果 | +| ------------- | ---------------- | ----------------------- | ------------------- | --------------------------------------------- | +| Power键 长按3秒 | 关机状态 | 绿色灯常亮(持续3秒,同步长按时间),然后熄灭 | 现有设备开机提示音(后续视需求可修改) | 设备开机,进入正常待机状态 | +| Power键 长按8秒 | 任何状态(死机/卡死/异常) | 无变化 | 无提示音 | 设备关机,切断所有电源 | +| Power键 短按(单击) | 待机状态 | 无指示灯 | 无提示音 | 进入休眠模式 | +| Power键 短按(单击) | AI交互中(聆听/处理/TTS) | 绿色慢闪 | 无提示音 | 停止对话,进入待机模式 | +| Power键 短按(双击) | 待机状态(任意状态) | 无变化 | 播报:单对话模式/长对话模式 | 如果对话时停止对话,设置对话模式,进入待机模式, 非对话模式,设置对话模式直接进入待机模式 | + + +## 第二部分:AI交互操作(AI键)+ 灯光+提示音联动 + + +| 操作动作 | 对话模式 | 设备当前状态 | 指示灯状态 | 提示音 | 执行结果 | +| --------------------------------- | ----- | ------------------- | ------------------- | ------------------ | --------------------------------- | +| AI键 短按1次 | 长对话模式 | 待机状态 | 立即切换为蓝色慢闪(1次/秒) | 单声“滴”(短促,清脆) | 唤醒AI,进入语音聆听状态,开始收音(用户可说话) | +| AI键 短按1次 | 长对话模式 | 语音聆听中(蓝色慢闪) | 切换为蓝色慢闪 | 单声“滴”(短促) | 重新进入语音聆听状态,开始收音(用户可说话) | +| AI键 短按1次 | 长对话模式 | TTS播报中(绿色常亮灯) | 切换为蓝色慢闪 | 单声“滴”(短促) | 进入语音聆听状态,开始收音(用户可说话) | +| AI键 短按1次 | 长对话模式 | 思考中(蓝绿交替闪) | 切换为蓝色慢闪 | 单声“滴”(短促) | 进入语音聆听状态,开始收音(用户可说话) | +| AI键 双击(两次短按,间隔≤1秒)-> 可选(根据可实现性而定) | | 待机状态 & TTS播报结束后1分钟内 | 蓝色灯常亮(与正常TTS播报灯光一致) | “滴、滴”(2声短促,间隔0.5秒) | 复读上一次AI的TTS回复内容,复读结束后回到待机状态(蓝色灯灭) | +| AI键 双击>>暂时无功能 | | | | | | +| AI键 长按(按下) | 单对话模式 | 待机状态/思考状态/播报状态 | 蓝色快闪(频率加快,2次/秒) | 单声“滴”(短促,清脆) | 进入收音状态 | +| AI键 长按(松开) | 单对话模式 | 聆听中 | 蓝绿交替闪 | “曾——”(长音,持续1秒) | 进入思考模式 | + + +## 第三部分:电量/充电状态 + 灯光+提示音联动 + + +| 设备状态 | 触发条件 | 指示灯状态 | 提示音 | 补充说明 | +| ----------------- | --------------- | ----------------------- | ------------------- | ------------------------ | +| 正常待机(电量≥30%) | 开机后无操作、交互结束后 | 指示灯灭(AI交互过程遵循如上第二部分的定义) | 无提示音 | | +| 低电量提醒(10%≤电量<30%) | 电量降至阈值、每5分钟触发1次 | 红色慢闪(1次/1秒),每次闪3次 | “滴、滴”(2声短促,与灯光同步) | 提醒用户尽快充电,不频繁打扰 | +| 电量耗尽(电量<10%) | 电量降至关机阈值 | 红色快闪3次(2次/秒)→ 熄灭 | “滴、滴、滴”(3声短促,与灯光同步) | 快闪结束后设备自动关机 | +| 充电中(电量<100%) | 连接充电器,接触正常 | 红色常亮 | 单声“滴”(短促) | 充电期间,按键操作仍有效(开关机、AI交互) | +| 充电满(电量=100%) | 充电至满电阈值 | 红色常亮→切换为绿色常亮(延迟1秒) | “滴——”(长音,持续1秒) | 绿色常亮保持,提醒用户可拔下充电器(晚上不打扰) | + + +## 第四部分:AI交互异常状态 + 灯光+提示音联动 + + +| 异常场景 | 指示灯状态 | 提示音 | 处理方式 | +| ---------------- | ------------------------ | ------------------- | -------------------- | +| 语音识别失败(未听清/无法识别) | 红蓝快闪2次(2次/秒)→ 回到待机状态(灯灭) | “滴、滴”(2声短促,与灯光同步) | 用户可再次短按AI键,重新唤醒聆听 | +| 网络异常(无法请求AI) | 蓝绿交替慢闪(1次/2秒),持续闪烁 | “网络异常信号弱”(每5秒1次,循环) | 检查网络连接,恢复网络后自动回到待机状态 | +| AI处理超时 | 蓝色常亮→红蓝快闪2次→回到待机状态(灯灭) | “滴、滴”(2声短促) | 处理失败,用户可重新发起语音请求 | + + +## 第五部分:补充规范(工程&用户体验) + +### 1. 提示音规范 + +- 音量:默认中等(约50dB),避免贴身佩戴时刺耳,支持后续通过APP调节(可选) +- 音色:统一采用清脆的电子音,避免复杂音效,确保不同场景的提示音可区分(短滴=操作确认,长滴=状态切换,多滴=提醒/异常) +- 优先级:异常提示音(网络异常)>操作提示音(唤醒、打断)>状态提示音(充电满、低电) + +### 2. 灯光规范 + +- **闪 / 慢闪 / 交替 / 慢交替** 的时间定义见文首 **「LED 灯效与时间术语」**;与工程 `period_ms` 一一对应,避免「1 次/秒」等口语与实现不一致。 +- 亮度:柔和不刺眼(≤100cd/m²),适配夜间、贴身佩戴场景,避免强光照射皮肤 +- 响应速度:按键操作后,灯光和提示音同步触发(延迟≤100ms),无卡顿 +- 冲突规避:同一时间仅显示一种状态灯光(如充电中触发AI交互,优先显示AI交互灯光,充电状态暂停显示,交互结束后恢复) + +### 3. 工程可实现性说明 + +- 按键逻辑:长按时间(3秒/8秒/2秒)可通过MCU精准控制,避免误判(如长按2秒切换进入连续对话模式,需持续检测按键按压时间,不足3秒不执行) +- 灯光控制:三色灯采用单灯三色设计,无需额外硬件,逻辑简单易实现 +- 提示音:喇叭播放,无需额外蜂鸣器 + +### 4. 用户易用性补充 + +- 所有操作均有“灯光+提示音”双重反馈,无屏状态下也能清晰判断设备状态 +- 避免复杂操作,核心功能(唤醒、开关机)仅需1种按键动作,老人、儿童可快速上手 +- 误触防护:短按Power键无操作、双击AI键仅在待机/播报后有效,减少误操作带来的困扰 + +--- + +## 附录 A:灯效编程对照表(`ai_VC.AI_led`) + +灯由 `EventMesh.publish("set_led_state", { ... })` 聚合驱动;**优先级自上而下**,先命中先显示,后面的输入仍写入内部状态但不生效,直到高优先级条件解除。 + + +| 优先级 | 输入字段 | 取值(示例) | 内部 `_mode` | 灯效(R/G/B) | `period_ms`(节拍) | 对应术语 | 说明 | +| --- | ---------- | --------------------- | ------------- | --------- | ------------------------------------ | ------- | -------------------- | +| P1 | `ai_state` | `playing` | `green_on` | 绿常亮 | — | — | TTS/本地播报中 | +| P2 | `ai_state` | `thinking` | `bg_alt` | 蓝↔绿交替 | `500` | **交替** | 约 0.5 s 换一色 | +| P3 | `ai_state` | `listening` | `blue_blink` | 蓝亮灭 | `1000` | **慢闪** | 约 2 s 一亮灭;整颗 GPIO 亮灭 | +| B1 | `charging` | `full` | `green_on` | 绿常亮 | — | — | USB 在位且电压达充满阈值 | +| B2 | `charging` | `charging` | `red_on` | 红常亮 | — | — | USB 在位且未充满 | +| B3 | `battery` | `low` / `empty` | `red_blink` | 红亮灭 | `1000` | **慢闪** | 非充电时按 SoC/OCV 判定 | +| B4 | `signal` | `weak` | `bg_alt` | 蓝↔绿交替 | `1000` | **慢交替** | CSQ 低于阈值 | +| 默认 | (上述均未命中) | `ai_state` 一般为 `idle` | `green_blink` | 绿亮灭 | `LED_IDLE_GREEN_BLINK_MS`(默认 `1000`) | **慢闪** | 待机/空闲 | + + +`**set_led_state` 消息字典键** + + +| 键 | 类型 | 含义 | +| ---------- | --- | --------------------------------------------- | +| `ai_state` | str | `idle` / `listening` / `thinking` / `playing` | +| `charging` | str | `none` / `charging` / `full` | +| `battery` | str | `normal` / `low` / `empty` | +| `signal` | str | `normal` / `weak` | + + +**可配置项(`default_config.py` / `vc_config`)** + + +| 配置名 | 作用 | +| --------------------------------------- | --------------------------------------- | +| `LED_GPIO` | (R, G, B) 引脚名 | +| `LED_ACTIVE_LOW` / `LED_ACTIVE_LOW_RGB` | 点亮电平反相 | +| `LED_IDLE_GREEN_BLINK_MS` | 待机绿灯**慢闪**半周期(ms),默认 `1000`,代码侧最小 `400` | + + +**与正文规范的差异(便于联调对齐)** + + +| 正文描述 | 当前工程实现要点 | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| 待机灯灭 / Power 短按待机无灯 | 代码待机为 **绿灯慢闪**(见上表默认行);与正文第三 part「正常待机灯灭」不一致时以代码为准或后续再改表 | +| 休眠无灯光 | 休眠路径在 `ui.py`(`pm.autosleep` 等);LED 是否全灭取决于休眠前是否再发 `set_led_state` | +| Power 长按 8s 关机无灯 / 无提示音 | 正文第一 part 为「无变化、无提示音」;若需与关机动画/提示音一致,由电源键模块与产品再定稿 | +| 备注「蓝灯闪 / 绿灯闪」与附录节拍 | 工程侧聆听为 **慢闪**(`1000`)、播放为 **绿常亮**;与口语「闪」字面不完全相同时,以文首 **术语表** 与附录 A 为准 | +| 闪 / 慢闪 / 交替 / 慢交替 | 与文首 **「LED 灯效与时间术语」** 及上表一致;`listening` / 低电 / 待机为 **慢闪**(`1000`),`thinking` 为 **交替**(`500`),弱网为 **慢交替**(`1000`);若正文写「1 次/秒」亮灭见术语 **闪**(`500`) | + + +--- + +## 附录 B:对话模式与状态机(`ai_VC.py`) + +> **源码对齐**:下列 FSM、`VC_TtsRxPhase`、`[FSM]`/`[KEY]` 日志字段等与 `2.sdk/Helios_SDK/services/microPython/ports/quectel/core/ai_VC.py` 一致。仓库内若另有 `project/*/sdk/.../ai_VC.py` 等副本,可能尚未合并同一套 `VCStateMachine`,**以当前固件实际编译进镜像的文件为准**。 + +### B1 对话模式 `VC_mode`(存储键 `VC_mode`) + + +| 值 | 常量名(代码) | 含义 | 协议侧要点 | +| --- | ------------------- | -------- | ------------------------------------------------------- | +| `0` | `VCMode.Realtime` | 长对话(连续) | VAD 开,一般 **无需** `audio.create` / `audio.completed` 包裹上行 | +| `1` | `VCMode.PushToTalk` | 单对话(PTT) | VAD 关,**必须** `audio.create` → 帧 → `audio.completed` | + + +### B2 会话层 `VCSessionState`(`AI_VC.fsm.session`) + + +| 值 | 名称 | 含义 | +| --- | -------------- | -------------------- | +| `0` | `Disconnected` | 未连接 / 已断开 | +| `1` | `Connecting` | 连接中 | +| `2` | `Starting` | 已发 Start,等 `started` | +| `3` | `Started` | 会话已建立,可上行/收事件 | + + +### B3 轮次层 `VCTurnState`(`AI_VC.fsm.turn`) + + +| 值 | 名称 | 含义(简述) | 当前 `VCStateMachine` 赋值情况 | +| --- | ----------------- | ------------------------ | ---------------------------------------------- | +| `0` | `Idle` | 本轮空闲 | 会写入(会话开始/断开等) | +| `1` | `Listening` | 聆听 / 等用户说话(长对话侧常见) | 会写入(`started` / `canceled` / `audio.played` 后等) | +| `2` | `SpeechStreaming` | 语音上行中(流式) | **枚举保留**;上行是否打开见 `fsm.speech_uplink_open`(`asr.started` ç½® 1) | +| `3` | `SpeechEnded` | 本轮说话结束(等 ASR/LLM) | 会写入(`vad.silence` 等) | +| `4` | `Thinking` | LLM 思考中 | 会写入(`llm.created`;`llm.completed` 兜底补位) | +| `5` | `TtsReceiving` | 正在收 TTS 音频流 | 会写入(`tts.started` / `local.synthesis_sent`) | +| `6` | `Playing` | 本地正在播 TTS | 会写入(`local.play_start`) | +| `7` | `AwaitPlayedAck` | 已播完,等 `audio.played` 等门控 | **枚举保留**;当前以 `fsm.await_played` 布尔门控为主,`turn` 多在 `Playing`/`TtsReceiving` | + + +### B3.1 TTS 接收相 `VC_TtsRxPhase`(`AI_VC.fsm.tts_rx_phase`) + +与 `tts.started` / `tts.completed` 对齐,用于区分服务端下发阶段(本地可能仍在播)。 + + +| 值 | 名称 | 含义 | +| --- | ------------------ | ------------- | +| `0` | `Idle` | 无 TTS 接收相活动 | +| `1` | `Started` | 已收到 `tts.started` | +| `2` | `ServerCompleted` | 已收到 `tts.completed`(本地未必播完) | + + +### B4 旧版 `VC_State_*` 整型(已移除,仅作历史对照) + +源码注释:**「原 `VC_State_*` 整型已移除;会话/轮次见 `VCTurnState` / `VCStateMachine`(含 `tts_rx_phase`、`speech_uplink_open`)。」** 下列宏名**不再出现在运行逻辑中**,仅便于对照旧日志或旧文档。 + + +| 宏名(历史) | 值 | 含义 | +| --------------------------------------- | ---- | ------- | +| `VC_State_None` | 0 | 无 | +| `VC_State_Listening` | 1 | 听 | +| `VC_State_SpeechStart` | 2 | 说开始 | +| `VC_State_SpeechIng` | 3 | 正在说 | +| `VC_State_SpeechEnd` | 4 | 说结束 | +| `VC_State_RequestToRespond` | 5 | 请求回复 | +| `VC_State_Thinking` | 6 | 思考 | +| `VC_State_Responding` | 7 | 响应/播放相关 | +| `VC_State_TTSStart` … `VC_State_TTSEnd` | 8–11 | TTS 子阶段 | +| `VC_State_TTSError` | 12 | TTS 异常 | +| `VC_State_DialogError` | 13 | 对话异常 | +| `VC_State_End` | 14 | 结束 | + + +### B5 灯与 FSM 的对应关系(编程时) + + +| `set_led_state` 的 `ai_state` | 典型触发场景(与 FSM/业务相关) | +| ---------------------------- | -------------------------------------------- | +| `listening` | 开麦聆听、长对话续聊等 | +| `thinking` | `llm.created` / 思考阶段灯 | +| `playing` | `tts.started` 后本地 PCM 播放、`audio_cb` 播放起止等 | +| `idle` | 交互结束、休眠前、或硬件态仅刷新 `charging/battery/signal` 时 | + + +> **调试**:`EventMesh.publish("get_led_debug_state")` 返回当前聚合 `{ ai, charging, battery, signal, mode, period_ms }`,与串口 `[KEY]` / `[FSM]` 日志对照。 + +### B6 状态机层级与典型跳转(实现速查) + +- **两层模型**:`session`(WebSocket 会话生命周期)与 `turn`(单轮「听→说→想→播」)。**`[FSM]` 单行日志**(`VCStateMachine.log`)形如:`[FSM] session=Started turn=Listening await_played=0 tts_rx=0 speech_up=0`(其中 `tts_rx` 为 `VC_TtsRxPhase` 数值,`speech_up` 为 `speech_uplink_open`)。 +- **`[KEY]` 行内片段**(`_vc_fsm_log_snip`):`sess= turn= tts_rx= await=<0|1> sp_up=<0|1>`,与上式含义一致。 +- **协议约束**(代码注释摘要):对齐《金三服务-语音对话 V2.5》——收到 `started` 后才允许发音频帧;VAD 开时长对话无需 `audio.create`/`completed`;VAD 关时 PTT 必须 `audio.create`→帧→`audio.completed`;`audio.played` 为进入下一轮的门控之一。 +- **可选严格协议行为**:模块级开关 `VC_PROTO_GUARDS`(默认 `0`)控制 started 前 PCM 缓冲/丢弃、PTT 下 `audio.create` 前禁发 PCM、`llm.completed` 后久无 `tts.started` 的会话兜底等;与产品灯效无直接耦合,联调协议时可关注。 +- **详细边条件**:以 `ai_VC.py` 中 `VCStateMachine` 各 `on_server_*` / `on_local_*` 及事件适配 `on_server_event` 为准;下图为**阅读级**总览(与当前赋值路径对齐:`Listening` 可直接到 `SpeechEnded`),非穷举所有分支。 + +```mermaid +stateDiagram-v2 + direction LR + state "会话 session" as S { + [*] --> Disconnected + Disconnected --> Connecting : websocket_connect + Connecting --> Starting : 发 Start + Starting --> Started : rx started + Started --> Disconnected : Close / 断链 + } + state "轮次 turn(Started 内)" as T { + [*] --> Idle + Idle --> Listening : 开麦/续聊 + Listening --> SpeechEnded : vad.silence 等 + SpeechEnded --> Thinking : llm.created / completed 兜底 + Thinking --> TtsReceiving : tts.started + TtsReceiving --> Playing : local.play_start + Playing --> Listening : audio.played 后 on_local_audio_played + Listening --> Idle : cancel / Close + } +``` + + + +`**VC_mode` 与 FSM 关系(简述)** + + +| `VC_mode` | 对 `turn` 的影响要点 | +| --------- | ------------------------------------------------------------- | +| `0` 长对话 | 易在 `Listening` 与上行、`canceled` 自动续听等路径间切换;详见 PTT 与长对话分支 | +| `1` 单对话 | 依赖 `audio.create` / `audio.completed`;长按 `ptt_begin` 打断后重开上行等 | + + +--- + +## 附录 C:充电 / 电量 / 信号(硬件态)与 LED 同步(`AI_hw_status` + `AI_led`) + +硬件侧由 `**AI_hw_status._update()`** 周期性(默认 `HW_STATUS_PERIOD_MS`,如 10000 ms)及 `**hw_usb_state` 事件** 刷新,并 **一次下发**: + +`EventMesh.publish("set_led_state", {"charging": chg, "battery": bat, "signal": sig})` + +仅更新这三个字段;`**ai_state` 仍由上一条 VC/业务逻辑保留**,最终灯效由 `**AI_led._apply_by_table` 优先级**决定:**任意非 `idle` 的 `ai_state`(listening/thinking/playing)都会盖住充电/电量/弱网灯**。 + +### C1 采样输入 → 内部枚举(工程判定) + + +| USB 在位 (`GET_USB_STATE` / 事件) | 电池电压 `vbatt_mv`(默认算法) | `charging` | `battery`(仅 **USB 不在位** 时按 SoC 算) | +| ----------------------------- | ------------------------------------------------------- | ---------- | ------------------------------------ | +| 否 | SoC ≥ 5% 且非低电档 | `none` | `normal` | +| 否 | SoC < 5% | `none` | `empty` | +| 否 | 5% ≤ SoC < 20%(工程档,非正文 10%/30%) | `none` | `low` | +| 是 | < 充满阈值(默认 **≥4290 mV** 视为满,可 `VBATT_CHARGE_FULL_MV` 覆盖) | `charging` | 不按 SoC 刷低电(充电中不走路径 B3) | +| 是 | ≥ 充满阈值 | `full` | 不参与 SoC 低电判定,`battery` 仍为默认 `normal` | + + +**说明**:USB 在位时 `**battery` 不按电压刷新**(代码仅在 `usb_status != 1` 时根据 SoC ç½® `low`/`empty`),灯效以 `**charging` 优先**(见附录 C3)。 + +**SoC 来源**:默认 **OCV 电压表插值**(`_ocv_map`);若 `USE_SIMPLE_VBATT_THRESH=True`,则按 `VBATT_CHARGE_FULL_MV` / `VBATT_LOW_MV` / `VBATT_EMPTY_MV` 三档近似。 + +### C2 信号弱网 + + +| 条件 | `signal` | +| ----------------------------------------------------------------------- | -------- | +| `net.csqQueryPoll()` 得到的 RSSI 存在且 **0 ≤ RSSI < SIGNAL_WEAK_CSQ**(默认 10) | `weak` | +| 否则 | `normal` | + + +### C3 枚举 → `AI_led` 灯效(且 `**ai_state == idle`** 时生效) + + +| `charging` | `battery` | `signal` | 内部 `_mode` | 灯效 | 节拍与术语 | +| ---------- | --------------- | -------- | ----------- | --------------- | ----------------------------------- | +| `full` | * | * | `green_on` | 绿常亮 | — | +| `charging` | * | * | `red_on` | 红常亮 | — | +| `none` | `low` / `empty` | * | `red_blink` | 红**慢闪** | `period_ms=1000`(约 2 s 一亮灭) | +| `none` | `normal` | `weak` | `bg_alt` | 蓝绿**慢交替** | `period_ms=1000`(约 1 s 换一色) | +| `none` | `normal` | `normal` | — | 附录 A 默认:**绿慢闪** | `LED_IDLE_GREEN_BLINK_MS`,默认 `1000` | + + +### C4 正文「第三部分」与工程灯效对照(含 AI 覆盖) + + +| 正文设备状态 | 正文指示灯 | 工程基础态(`ai_state=idle`) | **AI 交互中**(`listening`/`thinking`/`playing`) | +| ----------- | ------ | ---------------------------------------------- | -------------------------------------------- | +| 正常待机(≥30%) | 灯灭 | **绿灯慢闪**(见附录 A 差异说明) | 以 AI 灯为准(蓝慢闪 / 蓝绿交替 / 绿常亮) | +| 低电量 10%~30% | 红慢闪等 | `battery=low` → `red_blink`(阈值实为 SoC<20%) | AI 优先:例如 **播放中仍为绿常亮**,低电红慢闪不显示 | +| 电量耗尽 <10% | 红快闪→灭 | `battery=empty` → `red_blink`(SoC<5%);关机另由电源策略 | 同上,AI 可盖住 | +| 充电中 <100% | 红常亮 | `charging=charging` → `red_on` | AI 优先:如 **聆听蓝慢闪** 盖住充电红 | +| 充电满 | 红→绿常亮等 | `charging=full` → `green_on` | 与 **TTS `playing` 绿常亮** 同色,语义需靠场景区分 | + + +--- + +## 附录 D:异常状态(正文第四部分)与 LED 同步(工程现状) + +当前 `**AI_led*`* 无单独「红蓝快闪」「网络异常专用慢闪」等 `_mode`;异常分支多为 **TTS / `websocket_error` / `Close` + `ai_state: idle`**,灯效回到 **硬件态表(附录 C3)** 或 **待机绿灯慢闪**。 + + +| 正文异常场景 | 正文指示灯 | 工程侧典型处理 | 灯效(概括) | +| ------------- | -------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------- | +| 语音识别失败(未听清) | 红蓝快闪 2 次 → 待机灭 | `asr.result` 空串时置 `AI_TTS_str="我没听清…"`,走后续 TTS/状态机;**未专设红蓝闪灯** | 播提示 TTS 时多为 `**playing`→绿常亮**;结束变 `**idle`** 后接 **附录 C3**(弱电则红慢闪,否则绿慢闪) | +| 网络异常(无法请求 AI) | 蓝绿慢交替 + 语音循环 | `websocket_error` 等:`Close`、`set_led_state({"ai_state":"idle"})` | `**idle` + 硬件态**:弱网则 `**bg_alt`(慢交替)**;否则 **绿慢闪**;无「持续网络异常」专用灯型 | +| AI 处理超时 | 蓝常亮 → 红蓝快闪 → 灭 | 依赖超时/兜底分支,**无独立灯型表项** | 过程中可能 `**thinking`(交替)** 或 `**idle`**;未实现规范中的红蓝快闪序列 | + + +### D1 与附录 A 的编程关系(异常联调) + +1. 需要 **「异常专用灯」**:应在业务点增加 `**set_led_state` 新键**(如 `alert`)并在 `**AI_led._apply_by_table`** 中插入优先级;当前未做。 +2. 仅依赖 **现有键**:异常后务必 `**ai_state: idle`** 才会重新露出 **充电/电量/信号** 灯;否则用户会一直看到 **AI 阶段灯**。 +3. `**websocket_error`** 内已 `**set_led_state({"ai_state":"idle"})`**,可与 `**get_led_debug_state**` 联调确认 `charging/battery/signal` 是否已刷新。 + +--- + diff --git "a/1.doc/VC_state\350\277\201\347\247\273FSM\345\255\220\347\212\266\346\200\201-\346\224\271\345\212\250\346\270\205\345\215\225.md" "b/1.doc/VC_state\350\277\201\347\247\273FSM\345\255\220\347\212\266\346\200\201-\346\224\271\345\212\250\346\270\205\345\215\225.md" new file mode 100644 index 00000000..3e1e94da --- /dev/null +++ "b/1.doc/VC_state\350\277\201\347\247\273FSM\345\255\220\347\212\266\346\200\201-\346\224\271\345\212\250\346\270\205\345\215\225.md" @@ -0,0 +1,167 @@ +# `VC_state` 整型 → 扩展 FSM(子状态)迁移改动清单 + +> **策略**:在 `VCStateMachine` 上增加**显式子状态**(尤其覆盖原 `VC_State_TTSStart`~`TTSEnd` 与「说」阶段),所有业务判断只读 `fsm`;**删除** `self.VC_state` 的赋值与比较;常量 `VC_State_*` 整表删除。 +> **范围**:以 `2.sdk/project/7PIN_1_5/.../ai_VC.py` 为主;若产线启用 **Coze 分支**或 **`usr/test1.py`** 等拷贝,需**平行改**或删除未用拷贝(见文末)。 + +--- + +## 0. 前置结论(避免反复确认) + +| 问题 | 结论 | +| --- | --- | +| V2.5 协议是否要求 `VC_state`? | **否**。协议是 JSON 事件/负载;`VC_state` 仅为固件内部历史变量。 | +| 与 `fsm.turn`(B3)关系 | **并行双源**;迁移后 **唯一真源** 为 `fsm` + 本子状态枚举。 | +| `asr_state` | 同文件内另一套整型(`__init__` 附近);**本清单以 `VC_state` 为主**;建议第二阶段同样收敛到 FSM 或独立 `AsrPhase` 枚举。 | + +--- + +## 1. FSM 扩展设计(必须先定稿再改分支) + +### 1.1 新增子状态(建议命名,可按实现微调) + +在 `VCStateMachine` 中新增字段,例如: + +- **`speech_phase`**(可选):`Idle | UplinkOpened | FirstFrame | Streaming | VadEnded` — 仅当需要替代 `VC_State_SpeechStart`~`SpeechEnd` 的细粒度时使用;若可用 `turn == SpeechStreaming/SpeechEnded` + `VC_record_state_flag` 表达,可**不增**此枚举以减负。 +- **`tts_rx_phase`**(推荐):`Idle | Started | Receiving | ServerCompleted | Error` — 对应原 **8~11** 区间在**收包线程**里表达的「服务端 TTS 流生命周期」,用于: + - `tts_in/out` 背压判断(原约 **5428~5431** 行); + - `>= VC_State_TTSStart` 类「已开始 TTS 则不再处理 ASR」逻辑(原约 **4949** 行等)。 + +**转写规则(初稿,实现时以代码审查为准)**: + +| 原 `VC_state` / 区间 | 迁移后(读侧) | +| --- | --- | +| `>= TTSStart and <= TTSEnd` | `tts_rx_phase in (Started, Receiving, ServerCompleted)` **或** `turn in (TtsReceiving, Playing, AwaitPlayedAck)`(二者取并集需对照时序,避免漏判) | +| `== Thinking` | `turn == Thinking`(原 **5622** `think.mp3` 门控) | +| `>= SpeechIng` | `turn in (SpeechStreaming, SpeechEnded, Thinking, TtsReceiving, Playing, AwaitPlayedAck)` **或** `speech_phase` 达到 Streaming 之后(原 **6914** 长空闲门控) | +| `>= SpeechStart`(且配合 `VC_record_state_flag`) | `VC_record_state_flag != 0` **且** `turn in (SpeechStreaming, SpeechEnded, …)` 或 `speech_phase != Idle` | +| `VC_State_End` | `session != Started` **或** `turn == Idle` 且本轮显式结束标志(需与 `Close`/`completed` 语义对齐) | + +### 1.2 子状态**唯一写入点** + +- 在 **`VCStateMachine.on_server_event`**(及 `on_server_tts_*`、本地 `play_start` / `audio.played` 回调)内**集中**更新 `tts_rx_phase` / `speech_phase`。 +- **禁止**在 `AI_client_VC_recv` 大 `if/elif event` 里散落 `self.VC_state = …`;改为调用 `fsm.on_tts_rx_started()` 等小方法。 + +### 1.3 日志 + +- `[KEY]` / `[VC][uplink]` 中 `VC_state=` 改为 **`turn=… tts_rx=… speech=…`**(或单行 `fsm.dump()`),便于与 `[FSM]` 对齐。 + +--- + +## 2. 按文件 / 代码块的删除与替换清单(`ai_VC.py`) + +以下行号以 **当前仓库 `ai_VC.py`** 为准,合并后若有漂移以 `rg "VC_state"` 为准。 + +### 2.1 删除整表与成员 + +| 序号 | 动作 | 位置(约) | +| --- | --- | --- | +| D1 | 删除 `VC_State_None`~`VC_State_End` 常量定义 | **2965–2979** | +| D2 | 删除 `self.VC_state = …` 成员初始化 | **3859**(及所有赋值) | +| D3 | 删除所有 `self.VC_state =` 赋值行 | 见 **2.3** | + +### 2.2 条件与表达式替换(读侧) + +| 序号 | 当前逻辑(约) | 替换方向 | +| --- | --- | --- | +| R1 | **4359** `playing or (VC_state in TTS..) or VC_Play_flag` | `playing or fsm_tts_active() or VC_Play_flag`;`fsm_tts_active` 用 `turn` + `tts_rx_phase` 封装 | +| R2 | **4387** `VC_state in [TTSStart, TTSEnd]` | 同上或仅 `tts_rx_phase` | +| R3 | **4949** `VC_state >= TTSStart` | `tts_rx_phase >= Started` 或 `turn in (TtsReceiving, Playing, AwaitPlayedAck)` | +| R4 | **5428–5431** TTS 缓冲与 `< TTSStart` | 完全基于 `tts_rx_phase` + `turn` | +| R5 | **5622** `VC_state == Thinking` | `getattr(self.fsm, "turn", 0) == VCTurnState.Thinking` | +| R6 | **5672** `record and VC_state >= SpeechStart` | `record and in_speech_or_later()`(封装) | +| R7 | **5785** `_need_audio_played_ack or VC_state >= TTSStart or VC_Play_flag` | `_need_audio_played_ack or fsm_tts_active() or VC_Play_flag` | +| R8 | **6914** `VC_state >= SpeechIng` | `turn >= SpeechStreaming` 或 `speech_phase` 等价 | + +### 2.3 删除所有写侧赋值(逐条勾选) + +在替换读侧后,下列赋值应**整行删除**,改由 FSM 方法内更新子状态: + +| 约行号 | 原赋值 | +| --- | --- | +| 5581, 5583, 5587, 5679, 5703, 5742, 5780, 5791, 5885 | `VC_State_*` 多种 | +| 6865, 6893, 6968 | `VC_State_None` | +| 7037, 7249, 7279, 7313, 7387 | `VC_State_*` | +| 4448, 4500 | `Close`/重置路径中的 `VC_State_None` | + +**事件分支内**(`AI_client_VC_recv` 一带)原 **5581–5791** 与 **5679/5703/5742** 等:每处先标「对应协议事件 + 本地动作」,再映射到 `fsm.on_server_*` / 新 `on_tts_rx_*`。 + +### 2.4 仅日志 + +| 约行号 | 动作 | +| --- | --- | +| 3465–3476, 4332–4333, 4543–4544, 4649–4650, 6910–6911, 7027, 7936–7937 | 去掉 `VC_state`,改为打印 `fsm.session/turn/tts_rx_phase/await_played` | + +### 2.5 注释 / 死代码 + +| 约行号 | 动作 | +| --- | --- | +| 4705, 4863, 5014, 5842, 5919, 7345, 7912 | 删除或改写仍提及 `VC_state` 的注释块 | + +--- + +## 3. `VCStateMachine` 本体改动(骨架) + +| 序号 | 任务 | +| --- | --- | +| F1 | 在 `VCStateMachine.__init__` 增加 `tts_rx_phase`、`speech_phase`(若采用)默认值 `Idle` | +| F2 | 实现 `on_tts_stream_started/receiving/completed/error`(名称自定),由 **recv 线程**在解析 `tts.*` 事件时调用 | +| F3 | `log()` 扩展一行子状态(可选字段) | +| F4 | `on_server_started` / `Close` / `websocket_deconnect` 时**复位**所有子状态,避免跨会话泄漏 | +| F5 | 审查 **`on_server_event`** 中已有 `tts.started` / `tts.completed` 与本地 `play_start` 的先后,保证 `tts_rx_phase` 与 `turn` 一致 | + +--- + +## 4. 回归测试矩阵(必测) + +| 场景 | 验证点 | +| --- | --- | +| 长对话 VAD | `vad.silence` → 上行停;`llm.created` → 思考灯;`tts.started` → TTS 门控与 ASR 抑制 | +| 单对话 PTT | `audio.create`~`completed`;松手进思考;无 `VC_state` 漂移 | +| TTS 大缓冲 | 原 **5428** 条件:背压仍触发 | +| `think.mp3` | 仅在 `turn==Thinking` 且未播放时响(原 **5622**) | +| 长按 20s / `Close` | **6914**、**7936** 路径门控与清零 | +| 按键打断 | **4359/4387** 与 `VC_Play_flag` 组合行为不变 | + +--- + +## 5. 文档 + +| 序号 | 文件 | 动作 | +| --- | --- | --- | +| Doc1 | `1.doc/AI吊坠(双按键+三色指示灯)交互规范_new.md` | **B4** 整节改为「已废弃」或删除,改为 **「FSM:`session` / `turn` / `tts_rx_phase`」** 一小节 + 与日志字段对照 | +| Doc2 | `1.doc/AI吊坠LED状态优先级状态机.md` | 若文中引用 `VC_state=`,改为 `fsm` 字段 | + +--- + +## 6. 并行代码路径(勿漏) + +| 路径 | 说明 | +| --- | --- | +| `ai_VC_coze.py` | 含完整 `VC_State_*` 与大量赋值;若构建仍引用,需**同策略迁移**或从构建剔除 | +| `usr/test1.py` | 测试/样例拷贝;同步删改或标注「未维护」 | +| `sleep_test.py` | 仅注释提及;清理即可 | +| `2.sdk/Helios_SDK/.../ai_VC.py` | 若与 7PIN_1_5 双轨维护,合并策略二选一:**定期同步**或 **单源 + 文档说明** | + +--- + +## 7. 建议实施顺序(降低一次性炸机风险) + +1. **F1–F5**:先加子状态 + 只读封装函数(`fsm_tts_active()` 等),内部**暂时**仍写 `VC_state`(镜像)— 可选,一般跳过。 +2. **R1–R8**:替换所有读侧到 FSM。 +3. **D3**:删所有写侧;跑全场景。 +4. **D1–D2**:删常量与成员。 +5. **Doc / 并行文件**。 + +若团队接受更激进:**直接 D + R 一步完成**(不加镜像),则必须完整跑第 4 节矩阵。 + +--- + +## 8. 完成定义(DoD) + +- `rg "VC_state|VC_State_" ai_VC.py` 无匹配(除历史 `CHANGELOG`/注释若保留需写明)。 +- 串口关键日志仍能通过 **`[FSM]` + 子状态** 还原问题。 +- 交互规范 **B3** 为唯一「轮次状态」权威说明;**不再**出现「兼容旧版数值」表,除非作为 Git 历史附件归档。 + +--- + +*清单版本:与仓库 `ai_VC.py` 行号基于一次 `rg` 快照;合并分支后请重新 `rg` 校准。* diff --git a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/umqtt.py b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/umqtt.py index 23bb0c5a..041408a5 100644 --- a/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/umqtt.py +++ b/2.sdk/Helios_SDK/services/microPython/ports/quectel/core/umqtt.py @@ -12,27 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. - +try: + from qp_log import qp_print as print +except Exception: + pass import uos name, platform = uos.uname()[1].split("=",1) import utime -import log import _thread import usocket as socket import ustruct as struct import osTimer +print("umqtt:{}".format(utime.localtime())) if platform != "FCM360W" and platform != "FCM362K": import net import dataCall - -log.basicConfig(level=log.INFO) -mqtt_log = log.getLogger("MQTT") +print("umqtt2:{}".format(utime.localtime())) # bob.xian 2023/9/20 [FCM360W may be a bit unstable when using the log module, so print is temporarily used] begin -if platform == "FCM360W": - mqtt_log.info = print - mqtt_log.warning = print + # bob.xian 2023/9/20 [FCM360W may be a bit unstable when using the log module, so print is temporarily used] end #ALIYDEVREGISTER = False @@ -271,7 +270,7 @@ class BaseMqtt(object): self.sock.write(b"\xe0\0") # Pawn.zhou 2021/1/12 for JIRA STASR3601-2523 end except: - mqtt_log.warning("Error send mqtt_dis FAIL.") + print("Error send mqtt_dis FAIL.") try: if self.mqttsendlock.locked(): self.mqttsendlock.release() @@ -289,12 +288,12 @@ class BaseMqtt(object): _thread.delete_lock(self.mqttmsglock) self.mqttmsglock = None except: - mqtt_log.warning("Error delete_lock FAIL.") + print("Error delete_lock FAIL.") utime.sleep_ms(500) try: self.sock.close() except: - mqtt_log.warning("Error socket close FAIL.") + print("Error socket close FAIL.") def close(self): self.sock.close() @@ -339,14 +338,14 @@ class BaseMqtt(object): if self.wait_flag == 0: self.wait_msg() if not self._await_pid(pid): - mqtt_log.warning("publish Pid[%s] QOS1 message was not received correctly"%pid) + print("publish Pid[%s] QOS1 message was not received correctly"%pid) return False else: # self.last_time = utime.mktime(utime.localtime()) self.last_time = utime.ticks_ms() // 1000 return True elif qos == 2: - mqtt_log.warning("publish QOS2 Not Support") + print("publish QOS2 Not Support") assert 0 def __subscribe(self, topic, qos, sock): @@ -386,7 +385,7 @@ class BaseMqtt(object): def unsubscribe(self, topic): if topic not in self.topic_list: - mqtt_log.warning("Topic Not Subscribed") + print("Topic Not Subscribed") return False else: pkt = bytearray(b"\xa2\0\0\0") @@ -404,7 +403,7 @@ class BaseMqtt(object): self.mqttsendlock.release() return except Exception as e: - mqtt_log.warning("unsubscribe Pid[%s] ACK OSError[%s]." %(pid, str(e))) + print("unsubscribe Pid[%s] ACK OSError[%s]." %(pid, str(e))) if self.mqttsendlock.locked(): self.mqttsendlock.release() return @@ -442,7 +441,7 @@ class BaseMqtt(object): self.mqttsendlock.release() return except Exception as e: - mqtt_log.warning("Publish Pid[%s] ACK OSError[%s]." %(pid, str(e))) + print("Publish Pid[%s] ACK OSError[%s]." %(pid, str(e))) if self.mqttsendlock.locked(): self.mqttsendlock.release() return @@ -475,7 +474,7 @@ class BaseMqtt(object): if res == b'\x40': # PUBACK: save pid sz = self.sock.read(1) if sz != b"\x02": - mqtt_log.warning("Publish message does not return ACK correctly") + print("Publish message does not return ACK correctly") return rcv_pid = self.sock.read(2) pid = rcv_pid[0] << 8 | rcv_pid[1] @@ -488,7 +487,7 @@ class BaseMqtt(object): if res == b'\xb0': # Unsubscribe Ack: save pid sz = self.sock.read(1) if sz != b"\x02": - mqtt_log.warning("Unsubscribe message does not return ACK correctly") + print("Unsubscribe message does not return ACK correctly") return rcv_pid = self.sock.read(2) pid = rcv_pid[0] << 8 | rcv_pid[1] @@ -505,7 +504,7 @@ class BaseMqtt(object): if pid in self.SERVERACK: self.SERVERACK.discard(pid) if resp[3] == 0x80: - mqtt_log.warning("subscribe topic ACK Fail") + print("subscribe topic ACK Fail") return 0x80 else: return 0x90 @@ -536,7 +535,7 @@ class BaseMqtt(object): try: self.cb(topic, msg) except Exception as e: - mqtt_log.warning("set_callback OSError[%s]." % str(e)) + print("set_callback OSError[%s]." % str(e)) # Checks whether a pending message from server is available. # If not, returns immediately with None. Otherwise, does @@ -636,12 +635,12 @@ class MQTTClient(BaseMqtt): self.sock.close() #felix.hou 2024.5.11 add ,close() may cause reconnecting to the mqtt server to fail time_info = self.logTime() - mqtt_log.info( + print( "[%s] The network condition has been restored and an attempt will be made to reconnect" % time_info) self.pingFlag = False self.connSta = False self.connect(self.clean_session) - mqtt_log.info("[%s] Reconnection successful!" % time_info) + print("[%s] Reconnection successful!" % time_info) if self.manage: self.subtimer.start(3000, 0, self.sub_timer_task) else: @@ -658,14 +657,14 @@ class MQTTClient(BaseMqtt): try: self.error_callback(e)#reconnect success except Exception as e: - mqtt_log.warning("error_callback OSError[%s]." % str(e)) + print("error_callback OSError[%s]." % str(e)) return except Exception as e: if not self.timerFlag: break i += 1 time_info = self.logTime() - mqtt_log.warning( + print( "[%s] The connection attempt failed [%s] and will be tried again after %d seconds." % (time_info, str(e), 5 + i)) utime.sleep(5 + i) if platform != "FCM360W" and platform != "FCM362K": @@ -673,11 +672,11 @@ class MQTTClient(BaseMqtt): if net_sta != -1 and ((net_sta[1][0] == 1) or (net_sta[1][0] == 5)): call_state = dataCall.getInfo(1, 0) if call_state == -1: - mqtt_log.info("LTE datacall Fail.") + print("LTE datacall Fail.") elif call_state[2][0] != 1: - mqtt_log.info("LTE datacall IPV4 Fail.") + print("LTE datacall IPV4 Fail.") else: - mqtt_log.info("LTE Net unregistered.") + print("LTE Net unregistered.") def publish(self, topic, msg, retain=False, qos=0): while True: @@ -690,7 +689,7 @@ class MQTTClient(BaseMqtt): self.mqttsendlock.release() return ret except Exception as e: - mqtt_log.warning("Publish Fail OSError[%s]." % str(e)) + print("Publish Fail OSError[%s]." % str(e)) if self.mqttsendlock.locked(): self.mqttsendlock.release() return False @@ -721,9 +720,9 @@ class MQTTClient(BaseMqtt): time_info = self.logTime() self.wait_flag = 0 if self.ping == True: - mqtt_log.warning("[%s] wait msg, send ping timeout. Trying to reconnect" % time_info) + print("[%s] wait msg, send ping timeout. Trying to reconnect" % time_info) else: - mqtt_log.warning("[%s] wait msg OSError[%s] . Trying to reconnect" % (time_info, str(e))) + print("[%s] wait msg OSError[%s] . Trying to reconnect" % (time_info, str(e))) utime.sleep(1) self.base_reconnect() @@ -776,7 +775,7 @@ class MQTTClient(BaseMqtt): utime.sleep(5) continue if self.PING == True: - mqtt_log.warning("[%s] Send ping timeout 2. Trying to reconnect" % time) + print("[%s] Send ping timeout 2. Trying to reconnect" % time) if not self.reconn: if self.mqttsendlock is not None and self.mqttsendlock.locked(): self.mqttsendlock.release() @@ -784,7 +783,7 @@ class MQTTClient(BaseMqtt): raise Exception("Send ping timeout.") else: if self.pingnum <= 0: - mqtt_log.warning("[%s] Send ping timeout 1. Trying to reconnect" % time) + print("[%s] Send ping timeout 1. Trying to reconnect" % time) self.sock.settimeout(3) self.pingFlag = False if self.mqttsendlock is not None and self.mqttsendlock.locked(): @@ -792,7 +791,7 @@ class MQTTClient(BaseMqtt): self.looptask_id = None break else: - mqtt_log.warning("[%s] Trying to resend ping(%d)" % (time, self.pingnum)) + print("[%s] Trying to resend ping(%d)" % (time, self.pingnum)) self.pingnum = self.pingnum - 1 while True: if self.mqttsendlock is not None and self.mqttsendlock.locked(): @@ -826,9 +825,9 @@ class MQTTClient(BaseMqtt): # Whether to use the built-in reconnect mechanism time_info = self.logTime() if self.PING == True: - mqtt_log.warning("[%s] Send ping timeout 3. Trying to reconnect" % time_info) + print("[%s] Send ping timeout 3. Trying to reconnect" % time_info) else: - mqtt_log.warning("[%s] Send ping, Network exception. Trying to reconnect" % time_info) + print("[%s] Send ping, Network exception. Trying to reconnect" % time_info) utime.sleep(2) self.base_reconnect() break @@ -838,3 +837,5 @@ class MQTTClient(BaseMqtt): time_info = "%d-%d-%d %d:%d:%d" % ( log_time[0], log_time[1], log_time[2], log_time[3], log_time[4], log_time[5],) return time_info + +print("umqtt3:{}".format(utime.localtime())) \ No newline at end of file diff --git a/2.sdk/new_clean.bat b/2.sdk/new_clean.bat index d182db1b..7bfe1d24 100644 --- a/2.sdk/new_clean.bat +++ b/2.sdk/new_clean.bat @@ -1,21 +1,47 @@ @echo off setlocal EnableDelayedExpansion cd /d "%~dp0" +@REM chcp 65001 >nul 2>&1 set "PATH=D:\helios\bin;%PATH%" set "COMSPEC=%SystemRoot%\System32\cmd.exe" +if /i "%~1"=="help" goto :show_help +if /i "%~1"=="/?" goto :show_help +if /i "%~1"=="-h" goto :show_help + if "%~1"=="" ( set "PRODUCT_NAME=k8" ) else ( set "PRODUCT_NAME=%~1" ) -set "CORE_BASE=project\7PIN_1_5\sdk\services\microPython\ports\quectel\core" +REM ¹¤³ÌÃû£¨¶ÔÓ¦ project\¹¤³ÌÃû\£©£¬Ä¬ÈÏ 7PIN_1_5£»µÚ3²ÎÊý¿É¸²¸Ç +set "PROJ=7PIN_1_5" +set "BOARD=EG810MCN_GA_VOLTE" +if not "%~3"=="" set "PROJ=%~3" + +REM µÚ2²ÎÊý£ºqp_log 1=¶³½á qp_log.mpy ²¢Óà qp_print ´ò´®¿ÚÈÕÖ¾£»0=²»¶³½á£¬»ØÍË print +set "QP_LOG_ARG=%~2" +if "!QP_LOG_ARG!"=="" set "QP_LOG_ARG=1" +set "QP_LOG_EN=1" +if /i "!QP_LOG_ARG!"=="0" set "QP_LOG_EN=0" +if /i "!QP_LOG_ARG!"=="off" set "QP_LOG_EN=0" +if /i "!QP_LOG_ARG!"=="no" set "QP_LOG_EN=0" +if /i "!QP_LOG_ARG!"=="n" set "QP_LOG_EN=0" +if /i "!QP_LOG_ARG!"=="false" set "QP_LOG_EN=0" + +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0tools\patch_qp_log.ps1" -Enable:"!QP_LOG_EN!" -Root:"%CD%" -Project:"!PROJ!" -Board:"!BOARD!" +if errorlevel 1 ( + echo [´íÎó] ÉèÖà CONFIG_QP_LOG ʧ°Ü + exit /b 1 +) + +set "CORE_BASE=project\!PROJ!\sdk\services\microPython\ports\quectel\core" set "INI=%CORE_BASE%\products\product_!PRODUCT_NAME!.ini" if not exist "!INI!" ( - echo [错误] 找不到 product.ini: !INI! + echo [´íÎó] ÕÒ²»µ½ product.ini: !INI! exit /b 1 ) @@ -29,15 +55,15 @@ for /f "usebackq tokens=1,* delims==" %%a in ("!INI!") do ( ) if "!DEV_TYPE!"=="" ( - echo [错误] product.ini 中未定义 DEV_TYPE + echo [´íÎó] product.ini ÖÐ䶨Òå DEV_TYPE exit /b 1 ) if "!SRV_TYPE!"=="" ( - echo [错误] product.ini 中未定义 SRV_TYPE + echo [´íÎó] product.ini ÖÐ䶨Òå SRV_TYPE exit /b 1 ) if "!VERSION!"=="" ( - echo [错误] product.ini 中未定义 VERSION + echo [´íÎó] product.ini ÖÐ䶨Òå VERSION exit /b 1 ) set "VERSION=!VERSION:"=!" @@ -48,46 +74,46 @@ set "SRC_CFG=!CORE_BASE!\products\configs\!DEV_TYPE!\default_config.py" set "SRC_SRV=!CORE_BASE!\products\srv_configs\!SRV_TYPE!\default_srv.py" if not exist "!SRC_CFG!" ( - echo [错误] 找不到设备配置: !SRC_CFG! + echo [´íÎó] ÕÒ²»µ½É豸ÅäÖÃ: !SRC_CFG! exit /b 1 ) if not exist "!SRC_SRV!" ( - echo [错误] 找不到服务器配置: !SRC_SRV! + echo [´íÎó] ÕÒ²»µ½·þÎñÆ÷ÅäÖÃ: !SRC_SRV! exit /b 1 ) -echo [信息] 覆盖 core\default_config.py ^<- products\configs\!DEV_TYPE! +echo [ÐÅÏ¢] ¸²¸Ç core\default_config.py ^<- products\configs\!DEV_TYPE! copy /y "!SRC_CFG!" "!CORE_BASE!\default_config.py" >nul if errorlevel 1 ( - echo [错误] copy default_config 失败 + echo [´íÎó] copy default_config ʧ°Ü exit /b 1 ) -echo [信息] 覆盖 core\default_srv.py ^<- products\srv_configs\!SRV_TYPE! +echo [ÐÅÏ¢] ¸²¸Ç core\default_srv.py ^<- products\srv_configs\!SRV_TYPE! copy /y "!SRC_SRV!" "!CORE_BASE!\default_srv.py" >nul if errorlevel 1 ( - echo [错误] copy default_srv 失败 + echo [´íÎó] copy default_srv ʧ°Ü exit /b 1 ) cd Helios_SDK helios clean if errorlevel 1 ( - echo [错误] helios clean 失败 + echo [´íÎó] helios clean ʧ°Ü cd .. exit /b 1 ) cd .. -call new.bat 7PIN_1_5 !PRODUCT_NAME! +call new.bat !PROJ! !PRODUCT_NAME! if errorlevel 1 ( - echo [错误] 编译失败 ^(new.bat^) + echo [´íÎó] ±àÒëʧ°Ü ^(new.bat^) exit /b 1 ) -set "REL_DIR=Helios_SDK\opt\release\EG810MCN_GA_VOLTE" +set "REL_DIR=Helios_SDK\opt\release\!BOARD!" if not exist "!REL_DIR!" ( - echo [错误] 编译产物目录不存在: !REL_DIR! + echo [´íÎó] ±àÒë²úÎïĿ¼²»´æÔÚ: !REL_DIR! exit /b 1 ) @@ -101,15 +127,33 @@ for /f "delims=" %%h in ('git -C "%~dp0.." rev-parse --short HEAD 2^>nul') do se if "!COMMIT!"=="" set "COMMIT=nogit" set "NEWNAME=!PRODUCT_NAME!_!DEV_TYPE!_!SRV_TYPE!_!VERSION!_!BUILD_TIME!_!COMMIT!" +if "!QP_LOG_EN!"=="0" set "NEWNAME=!NEWNAME!_noqplog" if not exist "release" mkdir "release" -echo [信息] 复制产物到 release\!NEWNAME! +echo [ÐÅÏ¢] ¸´ÖƲúÎïµ½ release\!NEWNAME! xcopy /E /I /Y "!REL_DIR!" "release\!NEWNAME!\" >nul if errorlevel 1 ( - echo [错误] xcopy 失败 + echo [´íÎó] xcopy ʧ°Ü exit /b 1 ) -echo [完成] release\!NEWNAME! +echo [Íê³É] release\!NEWNAME! +exit /b 0 + +:show_help +echo. +echo Ó÷¨: new_clean.bat [²úÆ·Ãû] [qp_log] [¹¤³ÌÃû] +echo ²úÆ·Ãû ¶ÔÓ¦ products\product_²úÆ·Ãû.ini£¬Ä¬ÈÏ k8 +echo qp_log ÊÇ·ñ±àÒë¶³½á qp_log ²¢Í¨¹ý qp_print ´ò´®¿ÚÈÕÖ¾ +echo 1 / on / y / yes ¿ªÆô£¨Ä¬ÈÏ£© +echo 0 / off / n / no ¹Ø±Õ +echo ¹¤³ÌÃû ¶ÔÓ¦ project\¹¤³ÌÃû\£¬Ä¬ÈÏ 7PIN_1_5 +echo. +echo ʾÀý: +echo new_clean.bat k8 +echo new_clean.bat k8 1 +echo new_clean.bat k8 0 +echo new_clean.bat k8 1 7PIN +echo. exit /b 0 diff --git a/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h b/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h index c48d2904..b055bb78 100644 --- a/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h +++ b/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h @@ -1,50 +1,50 @@ -/* - * - * Automatically generated file; DO NOT EDIT. - * Helios SDK Configuration - * - */ - - -#define PROJECT_NAME_G3_7PIN 1 //项目宏定义 - - -// #define CONFIG_LVGL_SPAN 1 -// #define CONFIG_LVGL_FS_HELIOS 1 -// #define CONFIG_LVGL_GIF_DECODE 1 -// #define CONFIG_LVGL_SPINNER 1 -//#define CONFIG_LCD 1 -// #define CONFIG_LVGL_ANIMIMG 1 -// #define CONFIG_LVGL_KEYBOARD 1 -// #define CONFIG_LVGL_CALENDAR 1 -// #define CONFIG_LVGL_LED 1 -#define CONFIG_VIOCE_CALL 1 -// #define CONFIG_LVGL_FS_EXTFLASH_HELIOS 1 -// #define CONFIG_LVGL_TABVIEW 1 -//#define CONFIG_LVGL_LINE 1 -//#define CONFIG_LVGL 1 -// #define CONFIG_LVGL_CHART 1 -// #define CONFIG_LVGL_LIST 1 -// #define CONFIG_LVGL_MSGBOX 1 -// #define CONFIG_LVGL_ARC 1 -// #define CONFIG_LVGL_METER 1 -//#define CONFIG_LVGL_JPG_DECODE 1 -// #define CONFIG_LVGL_PNG_DECODE 1 -// #define CONFIG_LVGL_IMGBTN 1 -//#define CONFIG_GH301x 1 -//#define CONFIG_HX3918 1 -#define CONFIG_MBEDTLS 1 -//#define CONFIG_SC7A20 1 -// #define CONFIG_LVGL_WIN 1 -// #define CONFIG_LVGL_COLORWHEEL 1 -// #define CONFIG_LVGL_CANVAS 1 -// #define CONFIG_LVGL_SPINBOX 1 -// #define CONFIG_LVGL_QRCODE 1 -// #define CONFIG_LVGL_TILEVIEW 1 -// #define CONFIG_LVGL_HANDLER_TASK_PRIORITY 80 -//#define CONFIG_CAMERA 1 -//#define CONFIG_JPEG 1 -#define CONFIG_CAMERA_SAVEPHOTOS 1 -#define CONFIG_VAD 1 -//菊风视频通话 -//#define CONFIG_juphoon 1 +/* + * + * Automatically generated file; DO NOT EDIT. + * Helios SDK Configuration + * + */ + + +#define PROJECT_NAME_G3_7PIN 1 //椤圭洰瀹忓畾涔? + +// #define CONFIG_LVGL_SPAN 1 +// #define CONFIG_LVGL_FS_HELIOS 1 +// #define CONFIG_LVGL_GIF_DECODE 1 +// #define CONFIG_LVGL_SPINNER 1 +//#define CONFIG_LCD 1 +// #define CONFIG_LVGL_ANIMIMG 1 +// #define CONFIG_LVGL_KEYBOARD 1 +// #define CONFIG_LVGL_CALENDAR 1 +// #define CONFIG_LVGL_LED 1 +#define CONFIG_VIOCE_CALL 1 +// #define CONFIG_LVGL_FS_EXTFLASH_HELIOS 1 +// #define CONFIG_LVGL_TABVIEW 1 +//#define CONFIG_LVGL_LINE 1 +//#define CONFIG_LVGL 1 +// #define CONFIG_LVGL_CHART 1 +// #define CONFIG_LVGL_LIST 1 +// #define CONFIG_LVGL_MSGBOX 1 +// #define CONFIG_LVGL_ARC 1 +// #define CONFIG_LVGL_METER 1 +//#define CONFIG_LVGL_JPG_DECODE 1 +// #define CONFIG_LVGL_PNG_DECODE 1 +// #define CONFIG_LVGL_IMGBTN 1 +//#define CONFIG_GH301x 1 +//#define CONFIG_HX3918 1 +#define CONFIG_MBEDTLS 1 +//#define CONFIG_SC7A20 1 +// #define CONFIG_LVGL_WIN 1 +// #define CONFIG_LVGL_COLORWHEEL 1 +// #define CONFIG_LVGL_CANVAS 1 +// #define CONFIG_LVGL_SPINBOX 1 +// #define CONFIG_LVGL_QRCODE 1 +// #define CONFIG_LVGL_TILEVIEW 1 +// #define CONFIG_LVGL_HANDLER_TASK_PRIORITY 80 +//#define CONFIG_CAMERA 1 +//#define CONFIG_JPEG 1 +#define CONFIG_CAMERA_SAVEPHOTOS 1 +#define CONFIG_VAD 1 +#define CONFIG_QP_LOG 1 +//鑿婇瑙嗛閫氳瘽 +//#define CONFIG_juphoon 1 diff --git a/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk b/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk index a1d59675..eb60e7ae 100644 --- a/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk +++ b/2.sdk/project/7PIN/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk @@ -1,66 +1,67 @@ -# -# Automatically generated file; DO NOT EDIT. -# Helios SDK Configuration -# -PROJECT_NAME_G3_7PIN=y -# -# System Configuration -# -CONFIG_MBEDTLS=y - -# -# EG810MCN_GA_VOLTE -# -# CONFIG_LVGL=y - -# -# lvgl option -# -# CONFIG_LVGL_PNG_DECODE=y -# CONFIG_LVGL_GIF_DECODE is not set -# CONFIG_LVGL_JPG_DECODE=y -#CONFIG_LVGL_FS_HELIOS=y -# CONFIG_LVGL_FS_SD_HELIOS is not set -# CONFIG_LVGL_FS_EXTFLASH_HELIOS=y -# CONFIG_LVGL_CUSTOMER_FONT_SUPPORT is not set -# CONFIG_LVGL_QRCODE=y -# CONFIG_LVGL_FONT is not set -# CONFIG_LVGL_ARC is not set -#CONFIG_LVGL_IMGBTN=y -#CONFIG_LVGL_LINE=y -#CONFIG_LVGL_LIST=y -# CONFIG_LVGL_CHART is not set -# CONFIG_LVGL_LED is not set -# CONFIG_LVGL_CANVAS=y -# CONFIG_LVGL_WIN=y -# CONFIG_LVGL_TABVIEW is not set -# CONFIG_LVGL_TILEVIEW=y -# CONFIG_LVGL_MSGBOX=y -# CONFIG_LVGL_METER is not set -# CONFIG_LVGL_CALENDAR is not set -# CONFIG_LVGL_SPINNER is not set -# CONFIG_LVGL_SPINBOX is not set -# CONFIG_LVGL_ANIMIMG is not set -# CONFIG_LVGL_COLORWHEEL is not set -# CONFIG_LVGL_KEYBOARD=y -# CONFIG_LVGL_SPAN=y -# CONFIG_LVGL_HANDLER_TASK_PRIORITY=80 -# CONFIG_QRCODE is not set -#CONFIG_CAMERA=y -# CONFIG_CAMERA_DECODE is not set -CONFIG_CAMERA_SAVEPHOTOS=y -# CONFIG_QUECTHING is not set -# CONFIG_SPINAND is not set -# CONFIG_RTMP is not set -#CONFIG_JPEG=y -# CONFIG_SPI_SDCARD is not set -CONFIG_VIOCE_CALL=y -# CONFIG_TTS is not set -#CONFIG_LCD=y -# CONFIG_UART_SLIP is not set -# CONFIG_POC is not set -#CONFIG_GH301x=y -#CONFIG_HX3918=y -#CONFIG_SC7A20=y -CONFIG_VAD=y -#CONFIG_juphoon=y +# +# Automatically generated file; DO NOT EDIT. +# Helios SDK Configuration +# +PROJECT_NAME_G3_7PIN=y +# +# System Configuration +# +CONFIG_MBEDTLS=y + +# +# EG810MCN_GA_VOLTE +# +# CONFIG_LVGL=y + +# +# lvgl option +# +# CONFIG_LVGL_PNG_DECODE=y +# CONFIG_LVGL_GIF_DECODE is not set +# CONFIG_LVGL_JPG_DECODE=y +#CONFIG_LVGL_FS_HELIOS=y +# CONFIG_LVGL_FS_SD_HELIOS is not set +# CONFIG_LVGL_FS_EXTFLASH_HELIOS=y +# CONFIG_LVGL_CUSTOMER_FONT_SUPPORT is not set +# CONFIG_LVGL_QRCODE=y +# CONFIG_LVGL_FONT is not set +# CONFIG_LVGL_ARC is not set +#CONFIG_LVGL_IMGBTN=y +#CONFIG_LVGL_LINE=y +#CONFIG_LVGL_LIST=y +# CONFIG_LVGL_CHART is not set +# CONFIG_LVGL_LED is not set +# CONFIG_LVGL_CANVAS=y +# CONFIG_LVGL_WIN=y +# CONFIG_LVGL_TABVIEW is not set +# CONFIG_LVGL_TILEVIEW=y +# CONFIG_LVGL_MSGBOX=y +# CONFIG_LVGL_METER is not set +# CONFIG_LVGL_CALENDAR is not set +# CONFIG_LVGL_SPINNER is not set +# CONFIG_LVGL_SPINBOX is not set +# CONFIG_LVGL_ANIMIMG is not set +# CONFIG_LVGL_COLORWHEEL is not set +# CONFIG_LVGL_KEYBOARD=y +# CONFIG_LVGL_SPAN=y +# CONFIG_LVGL_HANDLER_TASK_PRIORITY=80 +# CONFIG_QRCODE is not set +#CONFIG_CAMERA=y +# CONFIG_CAMERA_DECODE is not set +CONFIG_CAMERA_SAVEPHOTOS=y +# CONFIG_QUECTHING is not set +# CONFIG_SPINAND is not set +# CONFIG_RTMP is not set +#CONFIG_JPEG=y +# CONFIG_SPI_SDCARD is not set +CONFIG_VIOCE_CALL=y +# CONFIG_TTS is not set +#CONFIG_LCD=y +# CONFIG_UART_SLIP is not set +# CONFIG_POC is not set +#CONFIG_GH301x=y +#CONFIG_HX3918=y +#CONFIG_SC7A20=y +CONFIG_VAD=y +CONFIG_QP_LOG=y +#CONFIG_juphoon=y diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/EventMesh.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/EventMesh.py index 47d80afc..98fe2215 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/EventMesh.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/EventMesh.py @@ -1,3 +1,8 @@ +try: + from qp_log import qp_print as print +except Exception: + pass + import _thread import usys import versions diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/Makefile b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/Makefile index 013850e6..a935438f 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/Makefile +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/Makefile @@ -1156,6 +1156,11 @@ frozen_mpy_list = $(BUILD)/_boot.mpy \ endif endif +# CONFIG_QP_LOG:menuconfig / config.mk 控制是否冻结 qp_log(见 services/microPython/config/config.in) +ifeq (y,$(CONFIG_QP_LOG)) +frozen_mpy_list += $(BUILD)/qp_log.mpy +endif + $(BUILD)/_frozen_mpy.c: $(frozen_mpy_list) $(HEADER_BUILD)/qstrdefs.generated.h @$(ECHO) "MISC freezing bytecode" $(Q)$(MPY_TOOL) -f -q $(HEADER_BUILD)/qstrdefs.preprocessed.h $(frozen_mpy_list) > $@ diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_VC.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_VC.py index dbc250e1..5c5dffac 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_VC.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_VC.py @@ -1,4 +1,8 @@ from common import Abstract, LogAdapter +try: + from qp_log import qp_print as print +except Exception: + pass import EventMesh import uwebsocket import usys diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_alarm.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_alarm.py index 88762c4f..aaa073e9 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_alarm.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/ai_alarm.py @@ -1,4 +1,10 @@ #ai闹钟 +try: + from qp_log import qp_print as print +except Exception: + pass + + import EventMesh import usys import ujson diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/btn_device_ec800m.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/btn_device_ec800m.py index e5e464cf..21799702 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/btn_device_ec800m.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/btn_device_ec800m.py @@ -1,3 +1,9 @@ +try: + from qp_log import qp_print as print +except Exception: + pass + + from common import Abstract import machine import osTimer diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/main_init.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/main_init.py index 962d7e97..aafb6486 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/main_init.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/main_init.py @@ -1,3 +1,8 @@ +try: + from qp_log import qp_print as print +except Exception: + pass + import sms import atcmd import net diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/motor.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/motor.py index d79939f8..9f4c0026 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/motor.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/motor.py @@ -1,3 +1,7 @@ +try: + from qp_log import qp_print as print +except Exception: + pass from common import Abstract import osTimer import EventMesh diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/products/product_k8.ini b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/products/product_k8.ini index 8a7f0651..8651c75d 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/products/product_k8.ini +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/products/product_k8.ini @@ -1,3 +1,3 @@ DEV_TYPE=7PIN SRV_TYPE=beike_dev -VERSION=V1.1 +VERSION=V1.2 diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/protocol.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/protocol.py index 4b898448..0100b8e5 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/protocol.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/protocol.py @@ -1,3 +1,7 @@ +try: + from qp_log import qp_print as print +except Exception: + pass import ujson import utime import EventMesh diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/qp_log.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/qp_log.py new file mode 100644 index 00000000..d2c81cf2 --- /dev/null +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/qp_log.py @@ -0,0 +1,65 @@ +"""QuecPython 标准 log 封装:默认 DEBUG,作为 print 的轻量替代。 + +日志输出到 UART4(与 `log.set_output` 一致)。 +参见:https://developer.quectel.com/doc/quecpython/Application_guide/zh/system/log.html + +推荐在需要统一日志的模块顶部使用(不修改 builtins):: + + from qp_log import qp_print as print +""" + +_orig_print = print +_logger = None +_log_uart = None +_log_ready = 0 # 0 未初始化,1 成功,-1 不可用 +_in_qp_print = 0 + +# UART4 日志口波特率(与业务里其它 UART4 用法冲突时需自行统一) +QP_LOG_UART_BAUD = 115200 + + +def _ensure(): + global _logger, _log_ready, _log_uart + if _log_ready != 0: + return _logger + _log_ready = -1 + try: + import log as _log + from machine import UART + + _log.basicConfig(level=_log.DEBUG) + _logger = _log.getLogger("qp") + if _log_uart is None: + _log_uart = UART(UART.UART0, QP_LOG_UART_BAUD, 8, 0, 1, 0) + _log.set_output(_log_uart) + _log_ready = 1 + except Exception: + _logger = None + return _logger + + +def qp_print(*args, **kwargs): + global _in_qp_print + if _in_qp_print: + return _orig_print(*args, **kwargs) + sep = kwargs.get("sep", " ") + end = kwargs.get("end", "\n") + if kwargs.get("file") is not None or kwargs.get("flush", False): + return _orig_print(*args, **kwargs) + _in_qp_print = 1 + try: + try: + msg = sep.join(str(a) for a in args) + str(end) + msg = msg.rstrip("\r\n") + except Exception: + msg = "" + lg = _ensure() + if lg is not None: + try: + lg.debug(msg) + return + except Exception: + pass + return _orig_print(*args, sep=sep, end=end) + finally: + _in_qp_print = 0 diff --git a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/versions.py b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/versions.py index 6389eda5..5b301140 100644 --- a/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/versions.py +++ b/2.sdk/project/7PIN_1_5/sdk/services/microPython/ports/quectel/core/versions.py @@ -1,2 +1,2 @@ -Version="V1.1" -Build_Time="2026-05-08 10:22:58" +Version="V1.2" +Build_Time="2026-05-15 15:13:48" diff --git a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h index 049ba1dd..bde76821 100644 --- a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h +++ b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/autoconf.h @@ -6,7 +6,7 @@ */ -#define PROJECT_NAME_G3_7PIN 1 //项目宏定义 +#define PROJECT_NAME_G3_7PIN 1 //椤圭洰瀹忓畾涔? // #define CONFIG_LVGL_SPAN 1 @@ -46,5 +46,5 @@ //#define CONFIG_JPEG 1 #define CONFIG_CAMERA_SAVEPHOTOS 1 #define CONFIG_VAD 1 -//菊风视频通话 +//鑿婇瑙嗛閫氳瘽 //#define CONFIG_juphoon 1 diff --git a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk index 2dd020e3..fa64f50d 100644 --- a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk +++ b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/config/config.mk @@ -63,4 +63,5 @@ CONFIG_VIOCE_CALL=y #CONFIG_HX3918=y #CONFIG_SC7A20=y CONFIG_VAD=y +# CONFIG_QP_LOG is not set #CONFIG_juphoon=y diff --git a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/images/firmware_base_release_pack.zip b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/images/firmware_base_release_pack.zip index 33a3a686..54bf2e18 100644 Binary files a/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/images/firmware_base_release_pack.zip and b/2.sdk/project/7PIN_1_5/sdk/system/platform/ASR_1606/boards/EG810MCN_GA_VOLTE/images/firmware_base_release_pack.zip differ diff --git a/2.sdk/tools/patch_qp_log.ps1 b/2.sdk/tools/patch_qp_log.ps1 new file mode 100644 index 00000000..c01c5a6e --- /dev/null +++ b/2.sdk/tools/patch_qp_log.ps1 @@ -0,0 +1,96 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Enable, + + [Parameter(Mandatory = $true)] + [string]$Root, + + [Parameter(Mandatory = $true)] + [string]$Project, + + [string]$Board = 'EG810MCN_GA_VOLTE' +) + +$Enable = [string]$Enable +if ($Enable -notin @('0', '1')) { + Write-Error "Enable must be 0 or 1, got: $Enable" + exit 1 +} +$qpLogOn = ($Enable -eq '1') + +function Patch-Mk([string]$path) { + if (-not (Test-Path -LiteralPath $path)) { + Write-Error "missing $path" + exit 2 + } + $lines = @(Get-Content -LiteralPath $path | Where-Object { $_ -notmatch 'CONFIG_QP_LOG' }) + $out = New-Object System.Collections.Generic.List[string] + $done = $false + foreach ($line in $lines) { + [void]$out.Add($line) + if (-not $done -and $line -match '^CONFIG_VAD=y') { + if ($qpLogOn) { + [void]$out.Add('CONFIG_QP_LOG=y') + } else { + [void]$out.Add('# CONFIG_QP_LOG is not set') + } + $done = $true + } + } + if (-not $done) { + if ($qpLogOn) { + [void]$out.Add('CONFIG_QP_LOG=y') + } else { + [void]$out.Add('# CONFIG_QP_LOG is not set') + } + } + [System.IO.File]::WriteAllLines($path, $out.ToArray()) +} + +function Patch-H([string]$path) { + if (-not (Test-Path -LiteralPath $path)) { + Write-Error "missing $path" + exit 2 + } + $lines = @(Get-Content -LiteralPath $path | Where-Object { $_ -notmatch 'CONFIG_QP_LOG' }) + $out = New-Object System.Collections.Generic.List[string] + $done = $false + foreach ($line in $lines) { + [void]$out.Add($line) + if (-not $done -and $line -match '^#define CONFIG_VAD 1') { + if ($qpLogOn) { + [void]$out.Add('#define CONFIG_QP_LOG 1') + } + $done = $true + } + } + if ($qpLogOn -and -not $done) { + [void]$out.Add('#define CONFIG_QP_LOG 1') + } + [System.IO.File]::WriteAllLines($path, $out.ToArray()) +} + +$boardCfg = [System.IO.Path]::Combine( + $Root, 'project', $Project, + 'sdk', 'system', 'platform', 'ASR_1606', 'boards', $Board, 'config' +) + +$mk = @( + (Join-Path $Root 'Helios_SDK\config\config.mk'), + (Join-Path $boardCfg 'config.mk') +) +$hk = @( + (Join-Path $Root 'Helios_SDK\config\autoconf.h'), + (Join-Path $boardCfg 'autoconf.h') +) + +Write-Host "Project=$Project Board=$Board" + +foreach ($p in $mk) { Patch-Mk $p } +foreach ($p in $hk) { Patch-H $p } + +if ($qpLogOn) { + Write-Host "CONFIG_QP_LOG enabled (qp_log.mpy in frozen_mpy_list)" +} else { + Write-Host "CONFIG_QP_LOG disabled (no qp_log in frozen_mpy_list)" +}