【M61蓝牙初体验】AI-M61-32S蓝牙广播--苹果设备弹出连接信息

[复制链接]
查看769 | 回复6 | 2024-12-29 18:49:30 | 显示全部楼层 |阅读模式
本帖最后由 putin 于 2025-1-6 11:07 编辑

一、前言
最近时间慢慢的多起来了,研究了一会m61的蓝牙协议栈(这边推荐莫工的这个帖子:小安派最小蓝牙)(园长我的帖子这算教程吗?

                               
登录/注册后可看大图


二、什么是BLE广播

                               
登录/注册后可看大图

BLE 广播是一种非常高效且低功耗的数据传输方式。它被广泛应用于不需要持续连接的场景,如位置定位、传感器数据采集、广告推送等。BLE 广播的特点包括:
  • 无需配对或连接:BLE 广播的最大特点是设备之间无需建立配对或连接。广播设备只需要发送一个信号,而接收设备可以在没有任何连接的情况下读取该信号。
  • 低功耗:与传统蓝牙经典模式相比,BLE 在广播时非常节能,因为它只会在短时间内发送数据,而不会维持一个持续的连接。
  • 广播间隔和数据大小:广播设备可以控制广播的间隔(即广播包发送的频率)和数据包的大小。较短的间隔意味着更频繁地发送数据,可能会导致功耗较高。
  • 广播类型:BLE 支持多种广播类型,如广告广播(Advertising)、扫描响应(Scan Response)等,能够根据需求发送不同类型的数据。(以上为GPT生成)

总的来说蓝牙广播包很牛皮就对了。

                               
登录/注册后可看大图


三、BLE广播数据包格式
BLE 广播数据的字节最高只能到 37 个(字节),而且 BLE MAC 地址默认占用了 6 个,只剩下 31 个字节给我们使用。这 31 个字节全部由"AD Structure" 结构体组成,但是不会只有一个 AD Structure,实际上会有好几个这样的结构体。

由上面的信息我们知道一个广播数据包可以用到的最长也就31个字节。
一个广播数据都是以如下格式进行传输的:一个字节长度数据+一个字节数据类型+数据。也就是a+b+c(其中a=b+c
若存在一个广播包为:
  1. 0x02 0x01 0x06 0x03 0x03 0xAA 0xFE 0x0A 0x09 0x54 0x65 0x73 0x74 0x44 0x65 0x76 0x69 0x63 0x65
复制代码
那么可以拆分为如下数据:
1. 0x02 0x01 0x06
  • 0x02:数据长度字段,表示从 0x01 到 0x06 共 2 个字节,指定了接下来的广告数据的长度。
  • 0x01:数据类型字段,标识这是一个广告标志(Advertising Flags),根据 BLE 标准定义,0x01 表示广告标志。
  • 0x06:广告标志数据,表示该设备支持 LE General Discoverable Mode(广泛可发现模式)和 LE BR/EDR Not Supported(不支持经典蓝牙)。
2. 0x03 0x03 0xAA 0xFE
  • 0x03:数据长度字段,表示接下来的数据长度为 3 个字节。
  • 0x03:数据类型字段,表示这是一个 16-bit 服务类 UUID(通用唯一标识符)。
  • 0xAA 0xFE:16-bit 服务 UUID,0xAA FE 是一个特定的 UUID,通常用于自定义服务,表示这个广播设备提供了一个与该 UUID 对应的服务。
3. 0x0A 0x09 0x54 0x65 0x73 0x74 0x44 0x65 0x76 0x69 0x63 0x65
  • 0x0A:数据长度字段,表示接下来的数据长度为 10 个字节。
  • 0x09:数据类型字段,表示这是一个设备名称(Device Name)字段。
  • 0x54 0x65 0x73 0x74 0x44 0x65 0x76 0x69 0x63 0x65:设备名称的字节数据,ASCII 编码为 "TestDevice",表示广播设备的名称为 "TestDevice"。
一些常用数据类型:
e3472996e13444bbe43296c8ccc436b8.png
同时如果1+2+3的长度是小于31个字节的话那么在发送广播数据的时候是会在后面补充0x00,因此实际上发送出去的数据是:
  1. 0x02 0x01 0x06 0x03 0x03 0xAA 0xFE 0x0A 0x09 0x54 0x65 0x73 0x74 0x44 0x65 0x76 0x69 0x63 0x65 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
复制代码
四、代码解析
1、请先看看莫工的帖子学会启动蓝牙崽
2、修改bt_enable_cb(int err)函数,代码如下
  1. void bt_enable_cb(int err)
  2. {
  3.     static const uint8_t *bldata;
  4.     static uint8_t num;
  5.     struct bt_le_adv_param param;

  6.     if (!err) {
  7.         print_configured_identities();
  8.         memset(&param, 0, sizeof(param));
  9.         // 设置广告间隔
  10.         param.interval_min = BT_GAP_ADV_FAST_INT_MIN_1;
  11.         param.interval_max = BT_GAP_ADV_FAST_INT_MAX_1;
  12.         /* 设置广告选项 */
  13.         param.options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME);
  14.         while (1) {
  15.             
  16.             bflb_gpio_reset(gpio,GPIO_PIN_14);
  17.             bldata = ble_data(num % 18);
  18.             if ((num % 27) < 18) {
  19.                 struct bt_data salve_adv1[] = {

  20.                     BT_DATA(BT_DATA_MANUFACTURER_DATA, bldata + 2, 29),
  21.                 };
  22.                 bt_le_adv_start(&param, salve_adv1, ARRAY_SIZE(salve_adv1), NULL, 0);
  23.             } else {
  24.                 struct bt_data salve_adv2[] = {

  25.                     BT_DATA(BT_DATA_MANUFACTURER_DATA, bldata + 2, 21),
  26.                 };
  27.                 bt_le_adv_start(&param, salve_adv2, ARRAY_SIZE(salve_adv2), NULL, 0);
  28.             }
  29.             num++;
  30.             printf("AD YES!\r\n"); /* code */
  31.             Delay_ms(1000);
  32.             int err = bt_le_adv_stop();
  33.             printf("err=%d,num=%d\r\n", err, (num - 1) % 27);
  34.             bflb_gpio_set(gpio,GPIO_PIN_14);
  35.             Delay_ms(200);
  36.         }
  37.     }
  38. }
复制代码
(熟悉上面代码在哪的人可以自己去对应sdk位置改)
只需要调用ble_stack_start() 函数就能让 Ai-M61 的 BLE 发送广播,同时当下一次广播需要更换数据时需要调用bt_le_adv_stop();才能更改广播数据。
由于本次项目是不停的更换蓝牙广播数据,小安派这里的蓝牙栈每次广播一组数据后我们需要先关闭广播才能更换,所以代码里我加了一个延时1000毫秒的代码,在广播数据后先等待1000毫秒然后停止广播,同时为了避免来不及换还加了一个200毫秒的延时。
使用到的广播数据如下(Apple juice开源项目里的):
  1. uint8_t dataAirpods[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x02, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  2. uint8_t dataAirpodsPro[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0e, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  3. uint8_t dataAirpodsMax[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0a, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  4. uint8_t dataAirpodsGen2[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0f, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  5. uint8_t dataAirpodsGen3[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x13, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  6. uint8_t dataAirpodsProGen2[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x14, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  7. uint8_t dataPowerBeats[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x03, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  8. uint8_t dataPowerBeatsPro[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0b, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  9. uint8_t dataBeatsSoloPro[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0c, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  10. uint8_t dataBeatsStudioBuds[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x11, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  11. uint8_t dataBeatsFlex[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x10, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  12. uint8_t dataBeatsX[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x05, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  13. uint8_t dataBeatsSolo3[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x06, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  14. uint8_t dataBeatsStudio3[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x09, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  15. uint8_t dataBeatsStudioPro[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x17, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  16. uint8_t dataBeatsFitPro[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x12, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  17. uint8_t dataBeatsStudioBudsPlus[31] = { 0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x16, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

  18. uint8_t dataAppleTVSetup[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x01, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  19. uint8_t dataAppleTVPair[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x06, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  20. uint8_t dataAppleTVNewUser[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x20, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  21. uint8_t dataAppleTVAppleIDSetup[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x2b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  22. uint8_t dataAppleTVWirelessAudioSync[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0xc0, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  23. uint8_t dataAppleTVHomekitSetup[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0d, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  24. uint8_t dataAppleTVKeyboard[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x13, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  25. uint8_t dataAppleTVConnectingToNetwork[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x27, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  26. uint8_t dataHomepodSetup[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  27. uint8_t dataSetupNewPhone[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x09, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  28. uint8_t dataTransferNumber[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x02, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
  29. uint8_t dataTVColorBalance[23] = { 0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x1e, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
复制代码
聪明的小伙伴可能已经看到又不同了为什么数据长度是31但是BT_DATA(BT_DATA_MANUFACTURER_DATA, bldata + 2, 29),这个代码里写的是29,同时还对数据进行了偏移2位而不指向首地址?原来这是因为AI-M61-32S蓝牙协议栈中对于数据的长度他是会自动的加在数据的前面的,同时对于数据的类型在我们使用BT_DATA这个宏函数的时候第一个参数就是数据类型,需要我们手动填进去,小安派这里支持如下参数:
  1. /* EIR/AD 数据类型定义 */
  2. /* 广播标志 */
  3. #define BT_DATA_FLAGS                   0x01 /* AD 标志 */
  4. /* 16 位 UUID,更多可用 */
  5. #define BT_DATA_UUID16_SOME             0x02 /* 16 位 UUID,更多可用 */
  6. /* 16 位 UUID,全部列出 */
  7. #define BT_DATA_UUID16_ALL              0x03 /* 16 位 UUID,全部列出 */
  8. /* 32 位 UUID,更多可用 */
  9. #define BT_DATA_UUID32_SOME             0x04 /* 32 位 UUID,更多可用 */
  10. /* 32 位 UUID,全部列出 */
  11. #define BT_DATA_UUID32_ALL              0x05 /* 32 位 UUID,全部列出 */
  12. /* 128 位 UUID,更多可用 */
  13. #define BT_DATA_UUID128_SOME            0x06 /* 128 位 UUID,更多可用 */
  14. /* 128 位 UUID,全部列出 */
  15. #define BT_DATA_UUID128_ALL             0x07 /* 128 位 UUID,全部列出 */
  16. /* 简短的设备名称 */
  17. #define BT_DATA_NAME_SHORTENED          0x08 /* 简短名称 */
  18. /* 完整的设备名称 */
  19. #define BT_DATA_NAME_COMPLETE           0x09 /* 完整名称 */
  20. /* 发射功率 */
  21. #define BT_DATA_TX_POWER                0x0a /* 发射功率 */
  22. /* 安全管理器 TK 值 */
  23. #define BT_DATA_SM_TK_VALUE             0x10 /* 安全管理器 TK 值 */
  24. /* 安全管理器 OOB 标志 */
  25. #define BT_DATA_SM_OOB_FLAGS            0x11 /* 安全管理器 OOB 标志 */
  26. /* 16 位 UUID 请求 */
  27. #define BT_DATA_SOLICIT16               0x14 /* 请求 UUIDs,16 位 */
  28. /* 128 位 UUID 请求 */
  29. #define BT_DATA_SOLICIT128              0x15 /* 请求 UUIDs,128 位 */
  30. /* 服务数据,16 位 UUID */
  31. #define BT_DATA_SVC_DATA16              0x16 /* 服务数据,16 位 UUID */
  32. /* GAP 外观(设备外观类型) */
  33. #define BT_DATA_GAP_APPEARANCE          0x19 /* GAP 外观 */
  34. /* LE 蓝牙设备地址 */
  35. #define BT_DATA_LE_BT_DEVICE_ADDRESS    0x1b /* LE 蓝牙设备地址 */
  36. /* LE 角色 */
  37. #define BT_DATA_LE_ROLE                 0x1c /* LE 角色 */
  38. /* 32 位 UUID 请求 */
  39. #define BT_DATA_SOLICIT32               0x1f /* 请求 UUIDs,32 位 */
  40. /* 服务数据,32 位 UUID */
  41. #define BT_DATA_SVC_DATA32              0x20 /* 服务数据,32 位 UUID */
  42. /* 服务数据,128 位 UUID */
  43. #define BT_DATA_SVC_DATA128             0x21 /* 服务数据,128 位 UUID */
  44. /* LE SC 确认值 */
  45. #define BT_DATA_LE_SC_CONFIRM_VALUE     0x22 /* LE SC 确认值 */
  46. /* LE SC 随机值 */
  47. #define BT_DATA_LE_SC_RANDOM_VALUE      0x23 /* LE SC 随机值 */
  48. /* URI */
  49. #define BT_DATA_URI                     0x24 /* URI */
  50. /* 网状网络配置 PDU */
  51. #define BT_DATA_MESH_PROV               0x29 /* 网状配置 PDU */
  52. /* 网状网络消息 PDU */
  53. #define BT_DATA_MESH_MESSAGE            0x2a /* 网状网络消息 PDU */
  54. /* 网状网络信标 */
  55. #define BT_DATA_MESH_BEACON             0x2b /* 网状网络信标 */
  56. /* 厂商特定数据 */
  57. #define BT_DATA_MANUFACTURER_DATA       0xff /* 厂商特定数据 */
复制代码
我们可以看到AirPods的数据开头第一位为0x1e,也就是数据长度为31位,第二个字节写的是0xFF对应常用数据类型也就是厂商特定数据,所以我们第一个参数选BT_DATA_MANUFACTURER_DATA。当我们填好后他也会加在数据的前面也就是说数据长度和数据类型小安排已经给我们自动加上去了,我们不用自己加,也就是说当我们需要广播其他数据的时候,同时也要注意一下避免数据超长(超过31字节)。
更多详细代码介绍可以看看视频。

                               
登录/注册后可看大图


五、实验现象
视频链接:哔哩哔哩

唯一的遗憾就是不能够像之前ESP32的那种蓝牙广播风暴能够一直弹。

ps:以上内容仅供学习切勿用于非法用途





新建文件夹.zip

3.73 KB, 下载次数: 2

回复

使用道具 举报

沈夜 | 2024-12-29 19:14:46 | 显示全部楼层
太厉害了。蓝牙风暴
回复 支持 反对

使用道具 举报

putin | 2024-12-29 21:35:23 | 显示全部楼层
沈夜 发表于 2024-12-29 19:14
太厉害了。蓝牙风暴

风暴还谈不上但是可以利用这个特性模拟其他设备而且还可以进行弹窗
回复 支持 反对

使用道具 举报

hrqwe | 2024-12-30 00:10:53 | 显示全部楼层
高质量帖子
日拱一卒,功不唐捐
回复 支持 反对

使用道具 举报

爱笑 | 2024-12-30 09:29:05 | 显示全部楼层
nice boy~
用心做好保姆工作
回复

使用道具 举报

HaydenHu | 2024-12-30 15:14:39 | 显示全部楼层
这要是一直弹窗,不成了攻击手段了?
回复 支持 反对

使用道具 举报

成为嵌入式高手 | 2024-12-30 17:08:00 | 显示全部楼层
学习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则