• Linux蓝牙驱动模拟HID设备(把Linux系统模拟成蓝牙鼠标和蓝牙键盘)


    by fanxiushu 2024-04-24 转载或引用请注明原始作者。

    在经过windows的蓝牙驱动开发模拟成HID设备的大风大浪之后,
    现在回到linux下实现相同功能,简直就是如小孩嬉闹一样的轻松。
    但无论如何,作为模拟蓝牙HID设备的windows,linux一系列的解决方案,本文还是简单阐述出来。

    在windows中的蓝牙驱动,那才叫真正的驱动,而且是内核运行的,必须使用c/c++语言开发。
    而在linux中,蓝牙的基础底层(blueZ)帮我们完成了大部分的工作,
    而且连带应用层也留下非常简便的接口来使用。
    因此linux的开发模拟HID设备的蓝牙驱动,只能叫简单调用应用层的接口而已,
    不仅可以使用c/c++, 各种开发语言都可以,脚本也行,只要支持blueZ导出的接口。
    所以,在windows必须实现内核驱动才能完成的功能,在linux就跟玩似的,怎么搞都行。

    开始之前,我们依然需要一些准备知识:
    linux主要是熟悉blueZ,至少需要熟悉它的接口以及如何调用接口以及工具程序,比如hciconfig,bluetoothctl等如何使用。
    需要熟悉HID相关知识。当然包括最基本的socket套接字编程知识。

    前面两篇文章阐述了windows下的蓝牙驱动模拟HID设备,也总体说明了模拟蓝牙HID设备的流程:
    1,初始化,
    2 ,注册0x11和0x13 的PSM,
    3,设置listen l2cap侦听
    4,accept,然后收发数据

    其实linux下基本流程也是一样的,但是linux的更像普通的socket编程,
    因为 blueZ 集成了AF_BLUETOOTH 的 socket,
    所以可以使用 socket 来进行蓝牙通讯。

    首先我们初始化,只需要简单的创建套接字:
        int sockint = socket ( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP );
        int sockctl = socket ( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP );
    一个用于0x11(控制,传输控制命令),一个用于0x13(中断,用于数据传输)

    接着就是注册0x11和0x13 的PSM, 在linux中,直接 bind 绑定即可,如下:
    static int    bth_bind(int sockfd, unsigned short port) {
        struct sockaddr_l2 l2a;
        memset(&l2a, 0, sizeof(l2a));
        l2a.l2_family = AF_BLUETOOTH;
        bacpy(&l2a.l2_bdaddr, &bdaddr_any);
        l2a.l2_psm = htobs(port);
        int ret = bind(sockfd, (struct sockaddr *)&l2a, sizeof(l2a));
        if (ret < 0)
        {
            printf( "** Bluetooth: Bind error (PSM 0x%X): %s\n", port, strerror(errno));      
        }
        return    ret;
    }
    //
    bth_bind(sockctl, 0x11); /注册0x11
    bth_bind  (sockint, 0x13 );  /注册0x13

    而且不像windows那样,注册这两个值会失败,必须做PATCH才能成功;
    linux下始终都会成功的,
    当然要正常运行起来,还得保证bluetoothd 带 -P input 参数运行,意思是blueZ忽略input的处理,
    这样才能把HID的处理转到我们的程序上。

    像在windows中开发的模拟HID设备的蓝牙驱动那样,linux中也需要发布属于我们的HID 的SDP描述信息。
    生成HID SDP信息,这个可能是linux下唯一有点麻烦的地方了,
    但是如果你事先就做好一个 profile hid文件,文件内容就是sdp信息,然后直接导入进来的话,也挺简单。
    不过我这里是自己在程序中生成sdp。
    主要使用 blueZ导出的 一大堆sdp_xxx接口函数来生成,生成的SDP格式都是标准的格式,
    所以这里也不再赘述。

    生成 sdp之后,调用 sdp_record_register 注册 sdp,不使用的时候,调用 sdp_device_record_unregister 注销。
    这两个函数调用都需要调用sdp_connect函数 连接到本地 SDP Server上。

    还需注意的是,要确保sdp_connect连接成功,
    bluetoothd服务必须带 -C或者--compat参数运行。

    所以总结起来,需要bluetoothd带两个参数运行:
    bluetoothd -C -P input

    接着就是调用accept函数来接收新连接上来的蓝牙客户端了。
    连接成功之后,直接调用系统函数 send,recv 收发数据了。

    所以。。。。。
    非常的简单,比起windows下实现相同功能不知道简单到哪里去了!

    研究蓝牙模拟HID设备的目的,其实在上面两篇文章中说过了,其实就为了能控制iOS手机,
    而现在这个目的终于达成了。
    下面是我的xdisp_virt程序实现的效果。

    新版本的xdisp_virt实现了 AirPlay,
    是的,用来镜像苹果设备的屏幕到xdisp_virt程序中,再通过xdisp_virt强大延展功能,
    能把苹果设备(iOS,iPad,macOS)的屏幕带到更遥远的地方。

    下面是演示视频:
     

    xdisp_virt程序的AirPlay且蓝牙控制苹果手机


    下面是AirPlay的页面配置图:

  • 相关阅读:
    面试题:分布式锁用了 Redis 的什么数据结构
    性能测试,app怎么做性能测试?app性能测试指标有哪些?测试点?
    蓝桥杯算法题——暴力枚举法
    skywalking展示http请求和响应
    Java命令行形式将程序打包成jar包,防止报错:没有主清单属性
    【CircuitPython】RaspberryPi Pico RP2040 自定义机械键盘实例
    MySQL中的锁机制
    Linux系统运行时参数命令
    大师偷学:vue-cli构建SPA项目和SPA项目结构
    linux自定义开机自启多个服务的脚本
  • 原文地址:https://blog.csdn.net/fanxiushu/article/details/138161953