跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组
皮肤
  • 浅色
  • 深色

折叠

半部电台

administrators

私有

帖子


  • 半部电台还能做什么?16 个应用创意(附实现路径,欢迎认领)
    N niuguanchong
    综合讨论 应用场景 半部电台 头脑风暴

    「半部电台」现在能做的事情已经不少了:附近消息、摩斯、十款桌游、电子宠物、遥控和扫描。但一块 ESP32-C6 + 128×32 OLED + 一颗旋钮 的小板子,能做的事远不止这些。

    这个帖子想干两件事:把能用的硬件和它的边界摊开,然后抛一批具体的创意——每条都写清楚用哪块资源、大概什么难度。看中哪条,直接在下面认领。


    先把"武器库"摊开

    创意的上限是硬件决定的,所以先看这张表。左列是能力,右列是必须先接受的限制——限制不是劝退,是筛选器。

    能力 能做什么 必须知道的边界
    BLE 广播收发 不建连接、不等配对,几十米内发消息 单包载荷 128 字节,广播间隔 100–300 ms,扫描 5 s / 100 ms 窗口
    私有协议 v3 18 种消息类型、回执、重试、会话 ID CRC 不是认证,抓包就能读,别放敏感内容
    频道 1–16 天然的"房间"划分 同频道才互相可见,跨频道要靠公告
    三跳中继 A→B→C 转发的自组网实验 实验特性,默认关闭,需三台同版设备实测
    128×32 OLED 四行、每行约 21 字符 中文用精简字库,别指望全字库
    旋钮 + 两键 A/B 正交编码 + 按下 / 返回 都是低电平有效,必须去抖,别把半步当一圈
    WS2812 + 压电蜂鸣器 颜色 + 4 kHz 短音 灯和屏共用 GPIO4 供电;蜂鸣器差分驱动,静音是两端都 LOW
    USB HID 键盘 / 媒体键、CDC 串口投屏 遥控期间 BLE 射频要暂停,主机和从机抢同一个天线
    4 MB Flash / NVS 存草稿、好友、最高分、宠物 没有 OTA 槽,更新只能插 USB
    深睡 5 s 周期 电池供电的长期在场 扫描占空比 2%,延迟最坏一个周期

    再看两件"硬件有、固件还没用"的东西:ESP32-C6 的 802.15.4 射频(Thread / Zigbee 那一套),和 Wi-Fi 6。它们不在当前功能里,但意味着这门硬件还有没打开的门。


    A. 校园与实验室

    1. 课堂匿名表决器 ★

    讲师手里一台开"主机",学生设备当终端。广播里塞 题目号 + 选项 A/B/C/D,回执方向反过来收统计。

    • 用到的:MESH_TYPE_COLLAB(协作类型)+ 回执机制
    • 关键设计:匿名——只发选项,不发 MAC,汇总时按计数而不是按人
    • 差异点:不用连校园网、不用扫码、不用手机

    2. 工位求助灯 ★

    一台设备挂工位。旋钮选「借仪器 / 找人 / 帮忙看看代码」,广播出去,附近所有电台的 RGB 同时变色 + 短响。

    • 用到的:广播 + RGB + 蜂鸣(都是现成的)
    • 比微信群强在哪:不需要对方在看手机,抬头就能看见
    • 加一条:收到的人按一下"我过去",发送端 OLED 显示"×× 在路上"

    3. 多台同步番茄钟 ★

    自习室里几台设备同时进入 25 分钟。有人提前走,其余设备显示"少了一人"。

    • 用到的:广播校时(session_id + 时间戳)
    • 难点不是计时,是漂移:每轮开始广播一次基准时间,剩下的靠本地计数
    • 彩蛋:结束前 1 分钟蜂鸣器变成慢滴答

    4. 答辩现场提词器 + 倒计时 ★★

    PPT 遥控(已有 HID)扩展成三合一:翻页、看剩余时间、超时震动/短响提醒。

    • 用到的:HID 遥控 + 本地倒计时 + 蜂鸣
    • 顺手解决真痛点:评委说"还有 1 分钟"的时候,台上的人根本听不见
    • 注意:HID 期间电台通信暂停,别指望边遥控边收消息

    5. 设备借用登记 ★★

    "万用表谁借走了?"——旋钮选设备(示波器 / 万用表 / 逻辑分析仪 / 开发板),按一下借出;归还时再按一下。

    • 用到的:NVS 记账 + 广播同步(谁在场谁记账)
    • 好处:不依赖网络,也不需要谁去维护一张表
    • 开放问题:冲突时以谁为准?建议"最后一次操作赢",并在 OLED 上明示时间

    6. 断网应急广播 ★★

    实验室 Wi-Fi 挂了、群里刷不出去的时候,一台设备写公告、其余设备滚动显示。

    • 用到的:ANNOUNCEMENT 标志(协议里已经有)
    • 这是"半部电台"这个名字最贴切的现代用法:当所有依赖基础设施的通道都失效时,点对点广播还在

    B. 玩与社交

    7. 物理漂流瓶 ★★

    写一句话,广播给最近的一台(hop = 1,只发一次)。收到的人可以再转发一次(hop + 1),形成一条真实的投递链。

    • 用到的:MESH_HOP_MASK + 只读转发
    • 妙处:你不知道它会飘到谁手上;hop 到 3 就停,天然有"寿命"
    • 必须说明:内容不加密,别写悄悄话

    8. 桌游"发牌器 + 裁判" ★★

    谁是卧底、狼人杀这类游戏,最麻烦的是主持人发牌和数票。让一台设备当裁判:它广播你的身份,只有你能长按查看。

    • 用到的:私密信息长按查看(现在已有)+ 投票类型
    • 价值:把手机从桌面上拿走,一桌人真的面对面
    • 边界:没有密码学防作弊,坐你旁边的人拆开抓包也能看到——这是自觉游戏

    9. 四声部无声合奏 ★★

    四台设备分低音 / 中音 / 高音 / 打击,指挥用旋钮打拍。所有人都戴耳机或干脆只听蜂鸣。

    • 用到的:灯光蜂鸣合奏(已有)+ 广播校时
    • 难点:蜂鸣器只有方波,音准靠分频,同步误差要压在几十毫秒内
    • 这是最"表演性"的一条,开放日/迎新晚会上很抓人

    10. 摩斯电报局(校史展项)★★

    两个人各拿一台,一人发报、一人抄收,中间可以加"加密本"(凯撒位移、简单替换表)。配一块展板讲 1931 年那半部电台。

    • 用到的:摩斯收发 + 好友定向
    • 为什么适合展览:它有故事。观众按下的不是按钮,是 90 多年前的通信方式
    • 加个成就:连续抄收 20 组不出错,屏幕放一小段"报务员认证"

    11. 宠物"面基"联赛 ★★

    两台设备靠近交换宠物名片(拜访已有),周末在实验室摆个擂台:相扑、顶球、赛跑三局两胜,结果上墙。

    • 用到的:宠物联机(已有)+ 本地排行榜
    • 唯一要新写的是"赛事流程":报名 → 配对 → 三局 → 记分 → 下一位

    12. 匿名"今天实验室有人吗" ★

    进门按一下,出门按一下。设备广播"3 楼有人",其余设备 OLED 显示人数和最早到的人。

    • 用到的:广播 + NVS
    • 限制:只是个粗略在场感,不做考勤,别拿它算工时

    C. 工具与实验

    13. 通用 HID 宏旋钮 ★★

    把旋钮做成电脑上的实体旋钮:调音量、切窗口、撤销/重做、Figma 里改数值、剪辑软件里逐帧。

    • 用到的:现有 HID 遥控(PPT / 媒体 / 拍照三套已经跑通了)
    • 为什么值得做:这是最容易被同学带走使用的一条——不玩电台的人也会想要一个旋钮
    • 注意:键位映射要可配置,否则只能给一个人用

    14. 实验室信号热力图 ★★

    拿着设备走一圈,按位置记 RSSI,USB 导出 CSV,最后画成一张覆盖图。

    • 用到的:BLE/RSSI 扫描 + CDC 串口
    • 必须写清楚的边界:RSSI 只表示信号冷热,不给方向、不给距离。 热力图是"走出来的",不是"测出来的"
    • 用途:找实验室哪里 BLE 死角、哪个角落 Wi-Fi 弱

    15. 三跳中继的实物教具 ★★★

    三台设备摆成 A—B—C,OLED 显示每一跳的转发次数和延迟。让学生亲眼看到"为什么多一跳就慢"。

    • 用到的:实验性自组网(已有,默认关闭)
    • 教学价值:把"自组网"从名词变成三块板子之间的距离
    • 诚实:这不是标准 Bluetooth Mesh,只是个三层转发的实验

    16. 802.15.4 低功耗传感节点 ★★★

    C6 芯片里有一套 802.15.4 射频,配个 I2C 温湿度传感器,做成每 5 分钟醒一次的信标。

    • 用到的:硬件的 802.15.4 + 深睡(当前固件完全没用到前者)
    • 这是"新开一扇门"的选项,不是改几行代码
    • 对比实验很有说服力:同样一块板,BLE 广播 vs 802.15.4,谁更省电

    D. 三条"需要先突破"的方向

    这三条不是不好,是卡在现有边界外,写出来是想看看有没有人愿意一起啃:

    1. 加密私聊。协议里 mesh_crypto.c 的位置已经留好了,但现在是明文广播。要做就得先想清楚密钥怎么换——两台的设备换密钥,本身就是个可以写论文的问题。
    2. OTA。现在只能插 USB 更新,因为 2 MiB 单应用槽吃掉了两个 OTA 槽。想恢复 OTA,得在"功能密度"和"可更新性"之间重新分配 Flash。
    3. 打电话给云端。Wi-Fi + 云同步已经有骨架,"线下见面 → 线上留痕"这件事(比如线下对战后自动上传排行榜)可以做得更顺,但要注意:云排行榜是设备自报的,不是防作弊比赛。

    怎么把一条创意变成能演示的东西

    不管选中哪条,建议都走这三步(也是我读官方手册时最认同的节奏):

    1. 先做一个外设,别做一整个应用。 比如做"工位求助灯",先只做"按一下,另一台的 RGB 变红"。能跑通再谈界面。
    2. 让 OLED 说实话。 状态、错误码、收到的原始包长度,全打在屏幕上。128×32 的四行字,是你唯一的调试窗口。
    3. 先两台,再三台。 两台之间通了只证明"能发",三台才证明"能转发"。

    另外给用 AI 写代码的同学一条:把引脚和边界写成契约再让它写。GPIO4 共享电源、I2C 0x3C、蜂鸣器差分、GPIO12/13 留 USB——这些说清楚了,生成的代码才不是"看起来像"。


    最后

    上面 16 条,难度从"一个下午"到"一个学期"都有。我个人的三个心头好是:

    • #6 断网应急广播 —— 它让这个名字重新变得有意义;
    • #10 摩斯电报局 —— 它把一个装置变成一段历史;
    • #13 通用 HID 宏旋钮 —— 它能让不玩电台的人也想要一台。

    欢迎在下面补充、认领、或者直接说"这条不行,因为××"——被否掉的创意也是有用的,至少省了下一个人一周。

    补充格式建议(方便以后整理):

    【创意名】一句话说明
    【用到的】哪些引脚 / 协议类型 / 现有功能
    【最小可行版】只做哪一件事就算成功
    【难点 / 边界】我卡在哪
    

    如果哪条你觉得该先做,投个票,或者直接开一贴贴代码。


  • 从空白工程点亮一块小电台:BLUE LONG 独立硬件开发手册导读
    N niuguanchong
    博客 ESP-IDF ESP32-C6 硬件开发 上手教程

    本文是《BLUE LONG 独立硬件开发手册》的导读与提炼。原手册 23 页,面向 Windows + VS Code + ESP-IDF 5.5.4,用四个例程把一台带外壳的小电台当成开发板来用。

    先说一个前提,这是整本手册反复强调的第一句话:

    这台带外壳的小电台,本身也是一块可以编程的开发板。 但你要驱动它,不需要启动原产品那套消息、好友、菜单和 Mesh 系统——从一个全新的空白 ESP-IDF 工程开始就够了。手册的副标题写得很清楚:"从空白工程开始,写下第一行自己的程序。"


    一、为什么"新开一个工程"比自己改原系统更好

    拿到一台能跑的产品设备,很多人的第一反应是"把源码改改再烧回去"。手册选择了相反的路:

    • 原产品的源码里有一整套业务:消息、好友、训练、Mesh、菜单、分区迁移。任何一行你还没读懂的业务代码,都是你第一次点亮屏幕时的噪音。
    • 独立工程只依赖板级硬件,编译产物小、启动路径短,出错时错误来源唯一。
    • 原产品是"三槽 OTA 分区",独立工程用的是普通开发分区。混着来的结果是:独立示例的 partition-table 和原版 app 拼在一起,谁也不认谁。

    所以手册的目录结构就是一条最短路径:先在 Windows 上把工具链跑通 → 建空白工程 → 编译 → 再谈烧录 → 最后逐个点亮外设。

    注意手册自己的说法:本册没有烧录。 文中所有"上板后预期"都是需要用户自己逐项核对的预期值,不是已完成的实机记录。这个态度值得先记住,后面还会反复出现。


    二、先分清三个"版本",这是新手最容易掉的第一坑

    VS Code 是编辑器;ESP-IDF 扩展 2.3.0 是编辑器里的操作界面;ESP-IDF 5.5.4 是真正参与编译的 SDK 和工具链。

    三件东西、三个版本号,互相独立:

    东西 版本 作用
    VS Code 随官方下载 编辑器
    官方 ESP-IDF 扩展 2.3.0 提供 ESP-IDF: 开头的命令、状态栏、Build/Flash 按钮
    ESP-IDF SDK 5.5.4 真正编译的 SDK 与 RISC-V 工具链

    装了扩展 ≠ 装了 SDK ≠ 当前工程选中了那个 SDK。 手册里那条对仗很好记:"扩展 2.3.0 不等于 SDK 2.3.0"。

    正确的顺序是四步:

    1. 装 VS Code,用"打开文件夹"打开一个新建的空目录(示例 C:\BLUE_LONG_DEV)。

    2. Ctrl+Shift+X 搜 @id:espressif.esp-idf-extension,核对发布者是 Espressif Systems,再 Install。要复现手册界面,在齿轮菜单里选 Install Another Version → 2.3.0。找不到图标时优先按 F1 搜命令名,而不是照抄别人的截图位置。

    3. F1 → ESP-IDF: Open ESP-IDF Installation Manager,走 New Installation → Custom Installation 向导,把版本固定成 v5.5.4、芯片选 ESP32-C6、安装位置 C:\Espressif、勾选 IDE 集成。

      这里有个细节:不要用 Easy Installation,它是"装最新稳定版"。手册要固定 5.5.4,因为后面所有"编译通过"的结论都只对这个版本成立。国内网络可以直接用管理器自带的 Espressif 官方下载源。

    4. 回到 VS Code:F1 → ESP-IDF: Select Current ESP-IDF Version 选中 5.5.4 → ESP-IDF: Doctor Command 看诊断 → 最后在 ESP-IDF: Open ESP-IDF Terminal 里敲一句 idf.py --version 独立确认。

    第 4 步那个 idf.py --version 非常重要:Doctor 说选对了不算数,命令行能跑出 ESP-IDF v5.5.4 才算数。 如果提示找不到 idf.py,说明你开的是普通 PowerShell 而不是 ESP-IDF 专用终端——环境变量根本没加载,这时候再怎么重装 SDK 都没用。

    还有一个很具体的坑:SDK 明明装了,但"选择版本"的列表里看不到。原因通常是扩展没读到 EIM(安装管理器)的登记文件。解法是让管理器重新识别该安装;还不行就在设置里搜 idf.eimIdfJsonPath,指向本机真实存在的 eim_idf.json。不要把版本号手填成路径,也不要照抄别人的用户目录。


    三、三条容易被忽略的硬约束

    1. 路径必须是纯英文、短

    手册把开发目录固定成 C:\BLUE_LONG_DEV,并且明确写了一条实测结论:

    如果资料包解压在中文目录,先把完整 examples 文件夹复制到 C:\BLUE_LONG_DEV\examples,再从那里打开编号工程。本轮 ESP-IDF 5.5.4 在中文源码路径出现过 ccache/objdump 路径错误。

    这不是玄学。ccache 和工具链的路径处理在 Windows 上对非 ASCII 字符一直不太稳,.bat 能双击跑通,不代表官方工具链能处理同一条中文路径。能省掉的排查,就别留给运气。

    2. 芯片要选 esp32c6,不是 esp32c61

    ESP-IDF: Set Espressif Device Target 的列表里两者相邻。手册特意给了放大图,标题就是"选择第一行 esp32c6,不是 esp32c61"。

    选错的后果不是"稍微有点问题",而是整个工具链换成另一颗芯片的,后面所有错误都会是假错误。而且换 target 会重配工程,所以顺序必须是:先选 target,再写代码,最后编译。

    3. 4 MB Flash + 原生 USB 控制台

    在 SDK Configuration Editor 里两处要改:

    • Serial flasher config → Flash size → 4 MB
    • Component config → ESP System Settings → Channel for console output → USB Serial/JTAG

    第二项决定了你的日志从哪里出来。手册补了一句很关键的边界:GPIO12/13 就是原生 USB 的 D-/D+,不要拿去点灯、接按键或当调试方波用。 烧录成功但 Monitor 一片空白时,先查控制台选项和 COM 是不是同一台设备,不要因此去改 USB 引脚。


    四、第一段代码:越短越好

    空白工程创建完(ESP-IDF: Create New Empty Project,项目名 blue_long_blank,父目录 C:\BLUE_LONG_DEV),手册让它先只做一件事——打日志:

    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "esp_log.h"
    
    void app_main(void) {
        unsigned count = 0;
        while (1) {
            ESP_LOGI("hello", "Hello BLUE LONG %u", count++);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
    

    两个细节:

    • app_main 是应用入口,不是 main。
    • vTaskDelay 是把 CPU 交还给系统,不是"睡一会儿"。用死循环空转等一秒,会把空闲任务饿死,看门狗和电源管理都会出问题。

    初学阶段最容易误判的一件事:红色波浪线不等于编译失败。 先把 SDK 和 target 选对,再以 Build 输出的第一条真实错误为准。


    五、引脚速查表:这张表决定了你后面所有代码

    功能 GPIO / 关系 开发时要记住
    OLED 与 RGB 供电使能 GPIO4,高电平使能 共享电源,先拉高等 150 ms 再用
    OLED I2C SDA GPIO5、SCL GPIO6 SSD1306,128×32,7 位地址 0x3C
    WS2812 RGB GPIO7 数字单线时序,不是普通 PWM RGB
    编码器 A / B GPIO2 / GPIO3 两路交错相位,完整旋转要解码
    编码器按下 GPIO18 按下为 LOW,独立事件 + 去抖
    独立返回键 GPIO19 按下为 LOW,先处理按下沿
    压电蜂鸣器 GPIO20 / GPIO21 差分输出,静音 LOW/LOW,只做短提示
    原生 USB D- / D+ GPIO12 / GPIO13 保留给 USB,不改普通 GPIO
    GPIO0 本轮禁止使用 不配置、不采样、不套旧板 BOOT 接法

    这张表里有三个设计点值得单独说:

    ① 为什么 GPIO4 是"共享电源使能"。 OLED 和 RGB 灯珠挂在同一路开关后面。所以只往 GPIO7 灌 WS2812 数据、却没开 GPIO4,屏幕不亮、灯也不亮——这不是代码错,是没通电。手册把"先 GPIO4 拉高,等 150 ms,再初始化 I2C 和发数据"写成了固定动作,150 ms 是给电源爬升和 OLED 内部复位留的余量。

    ② 为什么蜂鸣器是差分驱动。 压电片两端接 GPIO20/21,同相 = 不振动 = 静音,反相 = 有电位差 = 发声。静音时两端都是 LOW,所以千万不要把任意一端当成固定接地——那样你只有一个推挽脚,还得额外加直流偏置。差分的好处是驱动电压翻倍、无直流偏置、音量更大。手册要求"约 80 ms、4 kHz 短提示,长按不延长",是怕一直响把蜂鸣器烧了。

    ③ 为什么 GPIO0 被划成禁区。 老 ESP32 教程里"进下载模式就 GPIO0 接地"是个条件反射,但这块板上 GPIO0 不用。手册专门写了一句:下载模式连不上时,不要套用旧 ESP32 教程把 GPIO0 接地;先查数据线、USB 驱动和端口占用。

    还有一个概念要分清,手册第 10 章专门讲了:芯片 GPIO 编号 ≠ 模组焊盘号 ≠ 现有测试点(TP)。 功能图上的彩色标签是"软件信号",不是外壳边缘新增的排针。这套图说明的是现有硬件怎么用,不是一块新开发板的设计图。


    六、四个例程:把一个系统拆成四块积木

    手册最实用的部分是 examples/ 里四个互相独立的工程——不是四个源文件,是四份各自带 CMakeLists.txt、sdkconfig.defaults 和板级组件的完整工程。不要把四份 app_main 塞进同一个 main 一起编译。

    01_serial_hello:先看到一行自己的日志

    上板预期:每秒出现 HELLO BLUE LONG count=0、count=1……

    这个例程不点亮屏幕、不亮灯、不发声。所以显示器黑屏是正常的,不是失败。 它的唯一目的是验证"改代码 → 编译 → 写入 → 看到变化"这条最短路径。建议第一步就是把欢迎语改成自己的名字,确认改动真的来自你当前的工程,而不是旧镜像。

    02_oled_hello:共享电源,然后显示文字

    流程:GPIO4 拉高 → 等 150 ms → 初始化 I2C 与 SSD1306 → 写 128×32 区域。

    上板预期四行:

    HELLO BLUE LONG
    ESP-IDF 5-5-4
    128 X 32 OLED
    YOUR OWN PROGRAM
    

    两个坑写进了手册:

    • 屏幕不亮,先查 GPIO4 和电源,再查 SDA/SCL。"看到 SDA5/SCL6 就以为自己在查 I2C"——漏掉共享供电这一步,查多久都没用。
    • I2C 地址填 0x78 是把 8 位地址写法当成了 7 位参数。按例程接口应该写 0x3C。

    另外注意字库边界:这个最小工程用的是精简字库,只支持大写英文、数字和少量符号,每行最多 21 字符。直接把一串中文丢进去,显示不出来是预期行为——中文点阵字库是另一个话题(四 MB Flash 上并不便宜)。

    03_input_counter:知道是哪个操作件被触发

    旋钮 A/B 走 GPIO2/3,读两路交错相位判断旋转方向;旋钮按下 GPIO18、独立键 GPIO19,都是低电平有效。

    上板预期:屏幕显示 INPUT COUNTER、ROT:0、KNOB:0、KEY:0;转动改 ROT,短按旋钮和按独立键各自加计数。

    典型故障与正确解法:

    现象 正确做法 错误做法
    方向反了 确认实际旋钮手感与代码的方向约定 把 A/B 电平、半步、完整卡点混成一个事件
    按一次算很多次 查按下沿检测与去抖 无限加大延时

    手册还提醒了一条硬件边界:独立键还连着硬件电源开关通路。示例只用短按验证输入,没有接管电源控制芯片;"长按关机"的行为以实板为准,软件示例不承诺改变它。

    04_rgb_buzzer:颜色变化与明确的短提示

    RGB 数据脚 GPIO7,电源仍与 OLED 共用 GPIO4。按旋钮在 OFF → RED → GREEN → BLUE 之间切换;按独立键发一次 约 80 ms、4 kHz 的短提示音,然后停止;上电默认静音。

    两个"不要误解":

    • WS2812 是单线数字时序,不是三路 PWM 的模拟 RGB 灯。颜色不对先查数据格式、时序和颜色顺序,别去改 PWM 占空比。
    • 没有声音时先核对按键事件和差分输出。把"响一下"改成"一直响"不是修复,是把蜂鸣器往死里推。

    七、全册最值得抄的一段:把硬件约束写成提示词

    第 5 章装了 Codex(@id:openai.chatgpt,发布者 OpenAI),但真正有价值的是接下来这段——把硬件事实写成一段契约,整段贴给 AI:

    这是一个新的 ESP-IDF 5.5.4、ESP32-C6、4MB Flash 项目。
    我要直接开发 BLUE LONG 硬件,不依赖原小电台业务系统。
    先读当前 CMakeLists、main 和板级代码,再说明最小实现。
    OLED 是 SSD1306 128x32,7位I2C地址0x3C。
    GPIO4 是 OLED 与 RGB 的共享电源使能,先拉高并等150ms。
    I2C SDA=GPIO5,SCL=GPIO6;WS2812数据=GPIO7。
    旋钮A/B=GPIO2/3,按下=GPIO18;独立返回键=GPIO19。
    压电蜂鸣器由GPIO20/21差分驱动,默认关闭,只短响。
    GPIO0 不使用;GPIO12/13 留给原生USB,禁止重配成普通GPIO。
    不复制聊天、好友、Mesh、旧菜单或原产品分区。
    一次只实现一个外设;循环要让出CPU,输入要去抖。
    只改本项目,说明修改文件,编译并报告真实错误。
    不要自动连接串口、烧录、擦除Flash或更改eFuse。
    输出是初版代码;编译通过后由我决定是否上板验证。
    

    这段提示词好在哪:

    1. 先给事实,再给任务。 引脚、地址、时序都是硬约束,不能让模型"看外形猜"。
    2. 划定禁区。 GPIO0 不用、GPIO12/13 不许动、不碰原产品分区——把不可逆操作显式排除。
    3. 限定节奏。 "一次只实现一个外设",避免一次生成两百行跨模块代码。
    4. 要求真实错误。 "编译并报告真实错误",而不是编一个"应该可以了"。
    5. 保留决策权。 "由我决定是否上板验证"——AI 不获得烧录权限。

    配一条使用纪律:AI 改完先读 diff,确认没有多余功能、没有错引脚,再点 Build。 要让它修错,把第一条编译错误和对应代码给它,不要只说"还是不行"。

    安全上也有两句底线:只在官方认证页登录;不要把密码、验证码、API 密钥粘进项目、提示词或截图。


    八、命令列表里的"第几行",是个真问题

    F1 弹出的命令列表里有很多长得像的命令,手册几乎每一处都标了"选第几行":

    要做的事 选这条 不要选
    完整编译 ESP-IDF: Build Your Project(首行) 只构建 bootloader / partition table 的相近命令
    选串口 ESP-IDF: Select Port to Use(第二行) Select Monitor Port to Use(只改监视器端口)
    烧录 ESP-IDF: Flash (UART) Your Project(第三行) Encrypt and Flash Your Project(加密烧录,不是本教程)
    看日志 ESP-IDF: Monitor Device(第二行) Build, Flash and Start a Monitor(会顺带编译+烧录)

    搜索结果的蓝色默认项不一定是你要的那条。以完整名称为准,别按位置背。

    烧录前手册还要求停下来核对三件事:芯片是 esp32c6、Flash 是 4 MB、当前示例和 build 输出是这一份,并确认你手上有能恢复原产品的配套工厂固件。烧录本身用构建生成的完整烧录命令与偏移,不要从别人帖子里手抄一个固定 app 偏移。

    Monitor 想退出时,常见组合是 Ctrl+]。


    九、出错以后:用证据定位,不盲目擦除

    这张表是整本手册最"老工程师"的一页:

    现象 先做什么 不要误判
    列表里找不到 5.5.4 检查 EIM 登记与当前 SDK 选择,跑 Doctor 扩展 2.3.0 不等于 SDK 2.3.0
    idf.py 找不到 重开 ESP-IDF 专用终端 普通 PowerShell 没加载环境 ≠ SDK 丢了
    构建到最后一步失败 保存第一条实质错误,查依赖与路径 只把最后一行 ninja: build stopped 交给 AI,信息不足
    只有 COM1 换数据线、换 USB 口,看设备管理器 COM1 可能是电脑自带端口,只是排在列表最前
    COM 拒绝打开 关掉占用它的监视器、网页、烧录器 重装 SDK 不能释放别人占着的串口
    串口有日志但屏幕黑 先分清 01 本来就不用 OLED;02 查 GPIO4 USB 工作不代表屏幕电源已开
    按一次算很多次 查按下沿与去抖 几十毫秒轮询不等于几十次按下
    Flash 容量或芯片异常 保留完整工具日志,核验身份和读取步骤 不要关掉检查,也不要"猜"容量
    原小电台菜单不见了 这是独立固件替换产品程序后的预期 不是"开发程序必须含原系统才能跑"

    左下角那句尤其重要:全擦 Flash 不是排查手段,是最后的手段。 每次"擦一下试试",你都在丢掉现场证据。


    十、手册对自己的边界说得很清楚

    这部分我原样转述,因为它是这份文档最可信的地方:

    • 本次没有烧录。 所有"上板后预期"都待用户核对,不是已完成的实机验收。
    • 四个独立示例确实做过真实交叉编译:ESP-IDF 5.5.4 / esp32c6,四例退出码均为 0,宿主输入逻辑自检通过;源码、镜像校验值和 build.log 都留在各自 manifest 里。但四例编译通过不等于 OLED 方向、旋钮手感、RGB 颜色和声音被验收过。
    • 截图只代表对应界面被采集过,不能证明设备执行了程序。 绿色框、放大①是后加的引导层,原始截图独立保留。
    • 功能图是学习简化图,信号关系取自现有设计,但不能代替焊接定位、维修或 PCB 制造资料;图上的彩色端口不是焊点位置。
    • 不承诺跨分区无损恢复。 想回到原产品,用与实际硬件匹配的原版完整工厂发布包和它自带的烧录入口(该入口可能全擦并恢复出厂状态);恢复后名字、好友、消息、训练状态要重新核对。
    • 官方示例图(比如 Codex 面板那张 macOS 布局)会明确标注来源,不代表本机账户已登录或硬件已运行。

    十一、把整本手册压成一条路线

    装 VS Code + 官方 ESP-IDF 扩展 2.3.0
            ↓
    EIM 自定义安装 → 固定 ESP-IDF 5.5.4 / ESP32-C6 / C:\Espressif
            ↓
    Select Current ESP-IDF Version → Doctor → idf.py --version 独立确认
            ↓
    Create New Empty Project(blue_long_blank,纯英文短路径)
            ↓
    Set Target = esp32c6 · Flash = 4MB · Console = USB Serial/JTAG
            ↓
    Build Your Project(先只在电脑上闭环)
            ↓
    挨个过 01 → 02 → 03 → 04(每例独立编译、独立 build 目录)
            ↓
    自己决定是否 Flash (UART) + Monitor Device
    

    扩展外设时,手册给的下一个练习也很"教材化":在已经能显示、能读旋钮的工程里加一个六面骰子——短按开始,约 1 秒后显示 1 到 6,返回键中止;动画不阻塞按键,不用 IMU,不加网络和计分。

    这个练习的精髓不是骰子,而是:先让四个例程各自工作,再组合。 组合时如果坏了,你能确定是新加的那部分坏了。


    写在最后

    这份手册真正在教的,其实是三件事:

    1. 把"版本"和"层"分清——编辑器、扩展、SDK、target、COM、控制台,每一层都能单独坏。
    2. 把硬件约束写成文字——引脚表、时序、禁区,写清楚给人和给 AI 都一样有用。
    3. 把"没验证"说出来——没烧录就说没烧录,编译通过就只说编译通过。

    从空白工程到点亮一块 128×32 的屏幕,中间隔着几十个可以出错的地方。手册的价值,就是把那些地方一个个标出来,让你第一次就走在正确的路上。

    原手册:BLUE LONG 独立硬件开发手册(Windows / ESP32-C6 / ESP-IDF 5.5.4 / 2026.10,共 23 页)


  • 半部电台:用 ESP32-C6 做一台“附近通信”旋钮小设备——XidianFlipper 代码阅读笔记
    N niuguanchong
    博客 ESP32-C6 ESP-IDF BLE 嵌入式

    项目地址:qilaotie/XidianFlipper | 在线社区:半部小岛

    "半部电台起家"是西电校史里最常被提起的一句话。1931 年,红军第一部电台只能收、不能发,于是被叫作"半部电台"。这个项目借了这个名字,但它并不是一台真的无线电——它是一台基于 ESP32-C6 的旋钮小设备:靠 BLE 广播在几十米内和同伴互发消息、一起玩桌游、养一只电子宠物,顺便还能当 PPT 遥控器和 Wi-Fi 扫描器。

    本文是我读这个仓库源码后的笔记,重点放在它是怎么搭起来的,以及那些只有在真机上才会踩到的坑。


    一、硬件与工程基础

    项目 配置
    主控 ESP32-C6,4 MiB Flash
    屏幕 128×32 SSD1306 OLED(I2C,地址 0x78)
    交互 EC06 旋转编码器 + 独立按键 BACK
    声光 MCPWM 蜂鸣器、RMT 驱动 WS2812
    电源 GPIO4 集中管理负载开关 + ADC 电量检测
    工具链 ESP-IDF 5.5.4,CMake 工程

    工程按 firmware/(业务)与 components/(第三方与公共组件)两大块切分,业务目录再分为 app / config / drivers / protocol / radio / system / ui:

    firmware/
    ├── app/        # 消息、好友、Wi-Fi、无线工具、摩斯训练
    ├── config/     # constants.h / pins.h / defaults.h / log_config.h
    ├── drivers/    # ec06 编码器、rgb_led、rmt_ws2812、mcpwm_buzzer、adc_battery...
    ├── protocol/   # mesh_packet.c、mesh_crypto.c
    ├── radio/      # ble_radio.c、tool_hid.c
    ├── system/     # nvs_config、log_manager、power_mgmt、event_dispatcher
    └── ui/         # menu_pages、local_pages、party_pages、pet_page、dev_mode...
    components/
    ├── u8g2/                  # 图形库(含字模)
    ├── u8g2-hal-esp-idf/      # I2C bit-bang 回调
    └── oled_mirror/           # 把屏幕画面经 USB CDC 投到电脑
    

    初始化顺序是这份代码里最值得抄的部分

    firmware_init_all() 里每一步都有注释说明"为什么必须在这里",这不是装饰,是血泪:

    event_init();                 /* 1. 任何任务通信之前 */
    load_switch_init();           /* 1.5. GPIO4 总电源,任何外设之前 */
    log_manager_init();           /* 2.5. 事件之后、其他模块之前 */
    buzzer_init();  haptic_init();
    nvs_config_init();            /* 5. NVS 必须在 rgb_led 之前:
                                         否则 g_config 全零 → 亮度 0% */
    rgb_init();  rgb_led_init();
    ec06_init(&ec06_cfg);         /* 7. 编码器 ISR + 任务 */
    ...
    nvs_init();  ui_init();       /* OLED 提前亮,消除上电黑屏 */
    u8g2_Setup_ssd1306_i2c_128x32_univision_f(...);
    mesh_crypto_init();           /* 9. 加密必须在无线之前就绪 */
    ble_radio_init(mesh_notify_dispatch, NULL);  /* 10. NimBLE 主机任务 */
    quick_msg_init();  mesh_notify_init();
    

    几个细节:

    • 负载开关最先初始化。整块外设供电挂在 GPIO4 上,晚一步就是莫名其妙的 I2C 失败。
    • NVS 早于 RGB。配置从 Flash 读出来之前,结构体是零值,亮度按 0% 处理,用户看到的就是"灯不亮"。
    • OLED 抢先于 BLE。NimBLE 初始化会占用一截时间,先把屏幕点亮,用户感知到的开机时间就短了。
    • BLE 的致命错误有兜底:读 eFuse MAC 失败或设 BLE 地址失败时,红灯快闪 10 次、屏幕上画 FATAL ERR 0x01/0x02,然后死循环等看门狗。宁可停住,也不带着半残的协议栈跑。

    冷启动还有一段"开机图 2 秒 + 黑屏 1 秒"的过渡,而从 DeepSleep 按键唤醒时会跳过这段直接进 UI——g_wake_reason 判断一下就行,成本极低,体验差别很大。


    二、协议层:27 字节头 + 128 字节载荷

    firmware/protocol/mesh_packet.h 定义了整套私有协议 v3,线格式非常克制:

    #define MESH_MAGIC        0x4D45   /* 'M','E' */
    #define MESH_VERSION      3
    #define MESH_HEADER_SIZE  27
    #define MESH_PAYLOAD_MAX  128
    #define MESH_CRC_SIZE     2
    
    typedef struct {
        uint16_t magic;
        uint8_t  version;
        uint8_t  src_mac[6], dst_mac[6];   /* 用 MAC 直接寻址 */
        uint8_t  type, len, flags, channel;/* channel: 1~16 */
        uint32_t session_id, msg_id;       /* 会话 + 消息序号,做回执去重 */
        uint8_t  payload[MESH_PAYLOAD_MAX];
        uint16_t crc16;
    } mesh_packet_t;
    

    打包后最大 27 + 128 + 2 = 157 字节——刚好塞进 BLE 的传统广播/扩展广播里,不需要建连接。几个设计取舍:

    1. 用 MAC 当身份。src_mac/dst_mac 六字节,广播地址全 FF。好处是零配置、无路由表;代价是换设备就换身份,好友关系必须落 NVS(namespace = "mesh_cfg")。
    2. flags 一个字节塞了四件事:ACK_REQUEST、ROUTED、ANNOUNCEMENT、CUSTODY,再加两位跳数(MESH_HOP_MASK 0x0c,MESH_TOTAL_HOPS_MAX 3)。协议从"能通"进化到"能转发、能代存",头长度一字节没变。
    3. session_id + msg_id 撑起了回执与重试。发送状态机(已发 / 已收 / 超时)全靠这两个字段,MESH_TYPE_RECEIPT 就是回执报文。
    4. 18 种消息类型共享同一条管线:快捷消息、摩斯、好友请求、信标、回执、石头剪刀布、寻宝、反应赛、数字炸弹、宠物、协作、社交……加新玩法基本只是往枚举里加一个 MESH_TYPE_*。

    最值得称赞的是头文件第一行注释:

    /* BLE local messaging v3. Wire integers are little endian; CRC is not authentication. */

    CRC 不是认证。 这句话省掉了很多误解:这不是加密私聊,抓包就能读;游戏里也没有密码学防作弊。项目在 README、功能说明、工具说明里反复重申这一点——工程文档里肯把边界写清楚,比多堆十个功能更难得。


    三、通信载体:广播式"对讲",以及功耗的账

    设备之间不建 BLE 连接,全靠扫描广播收发。constants.h 里这几个数字决定了续航:

    #define SCAN_PERIOD_MS   5000   /* 扫描周期 5s */
    #define SCAN_WINDOW_MS   100    /* 扫描窗口 100ms → 2% 占空比 */
    #define COVER_ADV_MS     6000   /* 覆盖广播 6s ≥ 扫描周期 5s */
    #define BLE_ADV_INTERVAL_MIN_MS 100
    #define BLE_ADV_INTERVAL_MAX_MS 300
    
    • 扫描占空比只有 2%,所以平时几乎不耗电;代价是延迟——最坏要等一个扫描周期才收到消息。
    • COVER_ADV_MS > SCAN_PERIOD_MS 这条不等式是整个"对讲感"的关键:发送方要保证自己广播的持续时间覆盖住对方一整个扫描周期,否则就会出现"我明明发了对方没收到"的经典 bug。
    • DeepSleep 周期 5 秒,冷启动后留 15 秒宽限期禁止休眠——不然 USB 还没枚举完设备就睡了,串口工具上永远看不到设备。

    这套机制的能力边界也因此很明确:不需要路由器、SIM 卡或手机,但它也不是运营商短信,不是标准 Bluetooth Mesh。三跳中继是实验特性,默认关闭、重启不保留,要三台同版设备才能实测 A→B→C。


    四、界面:128×32 像素怎么装下一个系统

    屏幕只有 128×32,四行文字。项目直接移植了 WouoUI 的菜单框架(ui.layer / ui.state / ui.select[] / ui.fade),配合 u8g2 渲染。

    在这个尺寸上做 60 多个功能入口,靠的是三件事:

    • 分层菜单:主菜单按"消息 → 摩斯电台 → 学习 → 好友 → 趣玩 → 工具 → 设置 → 关于"排列,长描述走滚动。
    • 三套皮肤:经典像素、极简线框、终端,设置里切换、重启保留。
    • 中英双语开关:主菜单、设置、工具、趣玩全部双语,即时生效。中文用的是精简字库——128×32 的屏幕上,全量 CJK 点阵字模对 4 MiB Flash 来说并不划算。

    一个小而妙的组件:OLED Mirror

    components/oled_mirror 把每一帧画面通过 USB Serial/JTAG 发给电脑:

    usb_serial_jtag_driver_config_t usj_cfg = {
        .tx_buffer_size = 4096,   /* 整帧/日志/控制帧不被截断 */
        .rx_buffer_size = 256,
    };
    oled_mirror_begin(&u8g2, usb_cdc_send_callback);
    

    一帧 128×32/8 = 512 字节点阵,加 5 字节帧头正好 517 字节,所以 TX buffer 必须给到 4096 且写入超时只有 10 ms(USB 没插时静默丢弃,绝不阻塞渲染)。更妙的是它顺手 esp_log_set_vprintf() 接管了日志,让 ESP_LOGI 和画面走同一套帧格式——演示、答辩、录屏时不用举着放大镜看 128×32 的小屏。这个组件还单独做了 ENABLE_OLED_MIRROR 编译开关,不影响正式构建。


    五、功能盘点到什么程度

    不逐条罗列,只看"密度":

    • MESSAGES:快捷短语 10 条(单条上限 48 字符,见 QUICK_MESSAGE_MAX_LEN)、机身 ASCII 编辑、字符表情、六槽持久草稿箱、频道(1–16)、好友定向、收件箱与发送状态。
    • 摩斯:实时收发、自由练习、听音选字、跟练、听写。所有时序阈值都随 WPM 动态计算(morse_engine_set_wpm()),只保留固定值:20 ms 消抖、±30% 教学容差、600–900 ms 字母间隔、1500 ms 空闲自动发送、5000 ms TX 回 RX。
    • FUN 14 个入口:宠物、竖屏俄罗斯方块、贪吃蛇、答案之书、骰子、花旗骰、附近石头剪刀布、寻宝雷达、反应赛、数字炸弹、1–10 秒盲计时、玩法说明、灯光蜂鸣合奏、旅行护照。
    • 多人桌游 10 款:UNO、谁是卧底、达芬奇密码、骗子酒馆、情书、快艇骰子、阿瓦隆、一夜狼、狼人杀、井字棋。统一"创建 → 图形准备房间 → 开局进牌桌 → 结算回原房间重新准备"的流程,还支持多桌大厅、只读观战、邀请。
    • 宠物:四属性(饱食/心情/精力/清洁)、四阶段成长、三成年分支、七个内部小游戏、金币商店、背包装饰图鉴、双机拜访与对战、房间皮肤。没有死亡设定,喂食清洁睡觉全免费。
    • TOOLS 11 项:PPT/媒体/拍照 HID 遥控、Wi-Fi 连接、云同步、Wi-Fi 扫描、BLE/RSSI 扫描、内存状态、实验性自组网、网络诊断、队伍与社交。

    注意 HID 遥控期间电台通信会暂停——BLE 主机和外设角色抢同一套射频资源,这是硬约束,写在了手册里。


    六、最硬的一仗:分区迁移

    这是整个项目里我最想单独讲的部分,因为它是不可逆操作。

    原版固件的分区是老三槽布局,单个应用槽只有 1,245,184 字节。应用从 768,016 字节一路长到 1,527,808(当前发布包 1,739,152),三槽布局再也装不下:

    指标 冻结原版 迁移后
    单应用槽 1,245,184 B 2,097,152 B(2 MiB)
    应用镜像 768,016 B 1,739,152 B
    分区方案 旧三槽 + OTA factory-2m-usb-v1,取消两个 OTA 槽
    更新方式 OTA / USB 仅 USB

    关键约束是两处 NVS 的地址和大小绝对不能动:

    • nvs:0x9000 / 0x6000
    • nvs_sec:0x3b0000 / 0x6000

    因为它们存着 NVS v7 配置、storage ABI 1 的 UI 参数、宠物数据、游戏最高分和好友列表。工程里 docs/partition_migration.md 和 AGENTS.md 把流程钉死成几条:迁移前必须双读校验整片 Flash 备份 → 迁移工具必须验证设备身份、旧布局和备份 → 不能只刷分区表 → 完成后整片回读确认未授权区域没被写。

    结果也记录得很实在:COM9、COM10、COM15 三台设备分别完成双读整片备份、2 MiB 迁移和完整回读,确认 bootloader 未替换(COM15 因旧 bootloader 不同另行批准更新)、两处 NVS 及其他未授权区域不变。

    代价换取:没有 OTA 了。这很痛,但 factory 0x20000 / 0x200000 的单槽方案让应用可用空间从 1.2 MiB 涨到 2 MiB,功能密度才成为可能。工程在 README 里明确写了"迁移后仅支持 USB 更新,不支持 OTA",没有含糊。


    七、工程习惯:把"没验证"写进文档

    这份仓库最不像"学生作业"的地方,是它对自己的验收口径极其苛刻:

    • 构建产物带指纹:输出到 build/release/,包含 manifest.json、镜像、源码记录、validation/build.log 和 SHA-256,python tools/verify.py 独立核验。README 直接给应用哈希 21c39ff9...a916f3,不靠"我记得我编过"。
    • 模拟与实机分开报告:AGENTS.md 里那句"宿主模拟测试和实机验收分开报告;不得把模拟帧率、断电或回滚结果表述为实机通过",是很多项目缺的一条纪律。发布清单里 hardware_tested: false 一直保留着,哪怕已经上机测过一部分。
    • 能力边界逐条列出:RSSI 只表示信号冷热、不给方向距离;拿到 IPv4 不等于能上网;KEY SENT 不等于真的拍了照;云分享关闭不等于撤下,必须执行 REMOVE ONLINE。
    • 版本号不自作主张:扩展版固件字符串仍是 1.0.0-noautosleep,靠发行清单和 SHA-256 区分构建,明确"不把本扩展版误称为 V1.5"。

    顺带一个工程上的小坑:components/u8g2/csrc/u8g2_fonts.c 有 40 MB 源码,几万个字模。ESP-IDF 默认 -ffunction-sections -fdata-sections + 链接期 --gc-sections 会丢掉没引用的段,所以最终镜像不会爆炸,但编译时间和仓库体积是真的贵——这也是它把完整 u8g2 直接 vendor 进来要付的账。


    八、它不是什么

    作者写得很清楚,我照抄一遍,因为这几句比功能列表更有价值:

    • 没有 IR、NFC/RFID、Sub-GHz,不是完整 Flipper Zero 替代品;
    • 消息不是加密私聊,游戏没有密码学防作弊;
    • Wi-Fi 凭据未启用 NVS 加密,不要输入真实敏感信息;
    • 不是运营商短信,不是标准 Bluetooth Mesh,也不是互联网电台;
    • 云排行榜是设备自报的,不是防作弊比赛。

    一台 4 MiB Flash、128×32 屏幕、靠一颗旋钮操作的小设备,做到"附近能聊、能一起玩十款桌游、能养宠物、能当遥控器",靠的不是堆料,而是把每一字节的协议头、每一次扫描占空比、每一段 NVS 地址都算清楚。


    九、可以带走的三条经验

    1. 初始化顺序就是需求。事件系统、电源开关、NVS、屏幕、协议栈,谁在谁前面都有理由;写成注释,下一个人(或三个月后的你)会感谢自己。
    2. 协议头要预留成长空间。v3 的 27 字节头从"点对点消息"长到"三跳中继 + 代存 + 回执",头长度一次没变,全靠 flags 里的两位跳数和四种标记。前期省一点,后期就能改。
    3. 不可逆操作要有备份和验收清单。分区迁移那套"双读备份 → 验证身份/旧布局 → 只改授权区域 → 整片回读比对",比任何功能都更像一个真正的工程项目。

    如果对"半部电台"感兴趣,仓库里的 docs/ 有完整手册:功能简介、使用手册、宠物手册、桌游适配、分区迁移、发布与构建。也可以去半部小岛看看设备自报的排行榜和宠物展示柜。

    半部电台起家,靠的从来不是设备多好,而是有人愿意把能收的那一半,慢慢做成能发的那一半。


  • 半部电台的创意设计
    N niuguanchong
    综合讨论

    欢迎各位同学来进行补充!


  • 欢迎来到西电广研院学生创意分享论坛
    32961453 3296145
    公告

    这里是西电广研院人才创新高地,欢迎同学们分享自己的创意、小游戏和项目代码。发帖时请简单介绍作品内容、玩法和运行方式,也可以上传项目压缩包。
    我们将定期评选优秀作品,并给予奖励。评选标准、时间和奖品详情由管理员另行公布。


  • everybody,welcome to XDU.
    32961453 3296145
    综合讨论

    sample-code-project.zip


  • everybody,welcome to XDU.
    32961453 3296145
    综合讨论

  • Welcome to your NodeBB!
    32961453 3296145
    综合讨论

    Welcome to your brand new NodeBB forum!

    This is what a topic and post looks like. As an administrator, you can edit the post's title and content.
    To customise your forum, go to the Administrator Control Panel. You can modify all aspects of your forum there, including installation of third-party plugins.

    Additional Resources

    • NodeBB Documentation
    • Community Support Forum
    • Project repository

成员列表

32961453 3296145 群组所有者
4 帖子 0 声望
N niuguanchong 群组所有者
4 帖子 0 声望
  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组