<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>机盒通信 on 栈外随记</title>
    <link>https://btio.cn/tags/%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1/</link>
    <description>Recent content in 机盒通信 on 栈外随记</description>
    <image>
      <title>栈外随记</title>
      <url>https://btio.cn/images/logo-arong.svg</url>
      <link>https://btio.cn/images/logo-arong.svg</link>
    </image>
    <generator>Hugo</generator>
    <language>zh-CN</language><lastBuildDate>Sun, 16 Aug 2026 00:00:00 +0800</lastBuildDate>
    <atom:link href="https://btio.cn/tags/%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>【中科蓝讯】机盒通信问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/16/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Sun, 16 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/16/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;p&gt;本文围绕下面四类问题，整理对应的现象、问题原因和处理结果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#section-1&#34;&gt;快速开关盖后异常断连&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;左右耳回复不一致，盒子灯效频闪&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;耳机已经进入配对，盒子却不显示配对灯效&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-4&#34;&gt;配对超时后，盒子显示了错误灯效&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、快速开关盖后异常断连&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;快速开关盖时，耳机低概率断开。日志中没有完整的关盖命令，耳机却进入了充电状态。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;快速开关盖时，充电盒重新拉起供电。电平持续时间超过原来的防抖阈值，耳机提前判断为稳定入盒。状态切换由充电检测触发，不是串口丢包。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将充电电平持续检测时间从约 &lt;code&gt;600 ms&lt;/code&gt; 延长到 &lt;code&gt;1 s&lt;/code&gt;，避免短暂电平触发充电模式。连续快速开关盖验证后，未再出现异常断连。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、左右耳回复不一致，盒子灯效频闪&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机进入配对状态并放入盒内后，充电盒白灯闪烁不均匀，部分场景出现频闪或亮度异常。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;左右耳返回给充电盒的配对状态不一致。盒子先收到一只耳机的配对状态，又收到另一只耳机的非配对状态，灯效状态被反复切换。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;左耳回复：配对中
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;右耳回复：非配对
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;盒子灯效在两个状态之间反复切换
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由从耳同步主耳的配对状态，确保左右耳向充电盒返回一致的数据。双耳状态一致后，配对灯效恢复正常。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、耳机进入配对，盒子却不显示配对灯效&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机已经连接一台手机，再进入配对模式并放入盒内。充电盒只显示耳机电量，没有显示配对灯效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机同时存在“已连接”和“可发现可连接”两个状态。原来的回复逻辑优先返回已连接状态，覆盖了正在配对的状态，盒子因此没有进入配对灯效。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* 修改前 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;phone_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* 修改后 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;phone_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回复状态时优先判断配对状态，再判断手机连接状态。修改后，耳机在已连接状态下重新进入配对，盒子能够正常显示配对灯效。&lt;/p&gt;
&lt;h2 id=&#34;section-4&#34;&gt;四、配对超时后，盒子显示了错误灯效&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机在配对状态下入盒，配对超时后，充电盒显示了配对成功灯效，而不是结束灯效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机在配对超时后返回无效状态，充电盒却把这个状态按配对成功处理。数据传输正常，但两端对同一状态的含义没有统一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;统一耳机与充电盒对回复状态的定义。收到无效状态时直接结束灯效，不再进入配对成功灯效。&lt;/p&gt;
&lt;p&gt;这四类问题对应的检查入口是：&lt;strong&gt;充电电平、左右耳回复是否一致、状态判断优先级、两端状态定义。&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机机盒通信链路</title>
      <link>https://btio.cn/posts/2026/08/15/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%93%BE%E8%B7%AF/</link>
      <pubDate>Sat, 15 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/15/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%93%BE%E8%B7%AF/</guid>
      <description>&lt;p&gt;机盒通信的主链路是：UART 收包、协议解析、校验与寻址、命令分发、业务执行、应答返回。这篇记录我负责该模块时使用的应用层调用链。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、UART 收包与协议解析&lt;/h2&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart LR
    N0[&amp;#34;充电盒发送数据&amp;#34;]
    N1[&amp;#34;UART 中断接收字节&amp;lt;br/&amp;gt;并写入环形缓冲区&amp;#34;]
    N2[&amp;#34;协议状态机&amp;lt;br/&amp;gt;拼接完整数据包&amp;#34;]
    N3[&amp;#34;应用任务&amp;lt;br/&amp;gt;从缓冲区取包并校验&amp;#34;]
    N0 --&amp;gt; N1
    N1 --&amp;gt; N2
    N2 --&amp;gt; N3
    class N0,N1,N2,N3 blue;
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;UART 中断侧负责收字节和快速识别数据包：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 中断与接收回调&amp;#34;]
        direction LR
        R0N0[&amp;#34;uart1_isr()&amp;#34;]
        R0N1[&amp;#34;uart1_rx_done_cb()&amp;#34;]
        R0N0 --&amp;gt; R0N1
    end
    class R0N0,R0N1 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 解析与接收处理&amp;#34;]
        direction LR
        R1N0[&amp;#34;bsp_uart_packet_parse()&amp;#34;]
        R1N1[&amp;#34;charge_box_packet_recv()&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;中断将字节写入环形缓冲区，快速解析一次以记录收包时间及开盖、心跳等标志。&lt;code&gt;charge_box_ssw_process(charge_sta)&lt;/code&gt; 再从缓冲区取出字节，重新组包、校验并处理命令。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
