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的页面配置图: