开源xow 实测及代码分析(xbox one S 非官方linux版驱动)
Xow是一个非官方的Linux版本Xbox one 手柄无线适配器(后续简称“适配器”)Driver,其底层基于libusb进行工作,通过Wifi与游戏手柄进行连接,其使用MT76xx的Wifi chip;
本文将以“问题点--答疑”形式展开:
问题点1:Ubuntu 编译前的相关确认
- Linux (kernel 4.5 or newer) ---通过指令“uname -r”进行确认
这里强调内核版本的原因是:因uinput在低于4.5内核版本时,其使用的uinput.h找不到相关定义;
- curl (for proprietary driver download) ---用于下载,安装指令“apt-get update -y && apt-get install curl -y”
- cabextract (for firmware extraction) ---可通过指令“apt-get install ubuntu-restricted-extras” 安装,这个是附带安装cabextract,不然会提示“cabextract: Command not found”,
- libusb (libusb-1.0-0-dev for Debian) ---通过“apt-get install libusb-1.0-0-dev”进行安装
- systemd (version 232 or newer) ---“systemctl --version”知晓当前Ubuntu中的具体版本;
编译需要使用Git command ---通过“apt install git” 安装;
实测发现,安装Ubuntu20.04,可以使得systemctl 及Kernel都能直接满足要求;
Attention:
编译时需Ubuntu 联网,因编译时会自动下载,其下载动作在makefile中有体现
问题点2:编译指令;
“make BUILD=RELEASE” 或者
**NOTE:** Please use `BUILD=DEBUG` when asked for your debug logs.
问题点3:编译过程;
->下载微软.cab文件;
->通过指令cabextract 解压为FW_ACC_00U.bin,进行校验;
->FW_ACC_00U.bin更名为firmware.bin;//实际上当第一次下载后,可以修改makefile, 使其不再每次下载、校验;
->firmware.bin 转换为firmware.o;
->firmware.o 和其他.cpp对应.o一同被编译到执行档中;
OBJECTS := $(SOURCES:.cpp=.o) firmware.o;
问题点4:xow的架构实现;
xow的代码量并不大, 其集中在以下截图的红圈部分;
Xow中,类的包含关系如下:
GipDevice类最为父类存在;
---其核心功能是定义了微软GIP 数据格式结构体,并提供了虚函数(需子类实现);
Controller类是GipDevice的子类;
---用于每一只连接手柄的管理,包括接收数据的最终解析(最后一级,体现在API handlePacket),一级震动反馈也在此管理;
Mt76类做为父类存在;
----管理适配器的初始化、设置Wifi Beacon、设置Led等状态、提供封装的data 发送接口(sendClientPacket、sendCommand、controlWrite) 以及主动读取data接口(controlRead)…
Dongle 类是Mt76的子类;
---用于多只手柄的管理,包括其连接和断开。提供Controller 类的controllers变量数组,进行多手柄的管理;提供独立线程监听USB批量传输内容(实现的API readBulkPackets);所以这里是USB 批量接收数据(一般是连接后的传送数据)在xow的入口;
UsbDevice类独立存在,没有继承关系;
--- Base class for interfacing with USB devices, provides control/bulk transfer
capabilities; 其工作原理基于libusb
InputDevice类独立存在,没有继承关系;
---这个类的实现基于linux/uinput.h,但在实测中没有发现实际效果(也没有出现UI等);
Log类独立存在,没有继承关系;
---用于xow的log打印管理;
Bytes类独立存在,没有继承关系;
---作为一个数据组织类,数据被最终组织为uint8_t的 data buffer;
Buffer类独立存在,没有继承关系;
---作为一个模板类存在,提供具体数据存储和读取的接口;一般用于数据结构体;
使用例子如:” Buffer<RumbleData> rumbleBuffer;”
InterruptibleReader类独立存在,没有继承关系;
---Interruptible reader for file descriptors
问题点5:xow中的Dongle部分;
因适配器使用USB作为与PC 、平板等连接载体,所以当其插入PC时,其通过libusb完成USB的枚举流程;通过libusb 接口与适配器中的MT76xx wifi芯片进行通讯;
Dongle部分---MT76xx的初始化;
在Source Code中定义MT76xx相关初始化以及操作接口的是mt76.cpp,其在自定义类“Mt76”的构造函数中完成 MT76xx chip的初始化动作;
其调用的读取与写入动作基于自定义类“UsbDevice”中自定义函数controlTransfer,其参数设置基于USB 控制传输的定义,具体请参考《USB开发打全(第4版)》的第5章“控制传输:用于关键数据的结构化请求”;Page78;
在整个MT76xx的操作过程中,其涉及到了USB 的两种传输方式“控制传输”和“批量传输”;
分别对应自定义API 是
“控制传输”:
“controlRead”、“controlWrite”
“批量传输”
sendCommand
具体分析:
Dongle的初始化开始于“Waiting for device...”,其阻塞在libusb_handle_events_complete(导致API getDevice也处于阻塞状态),等待注册的特定Dongle 被插入;
-->当Dongle被插入时,将退出当前while循环;API getDevice也将完成并退出,其实执行getDevice的main函数将继续往下执行;
这里需注意的是,因Dongle继承于MT76,所以当Dongle的构造函数被执行前,先执行其父类MT76的构造函数,当MT76的构造函数执行完成时,就算是完成Dongle的初始化动作;
-->所以当前Dongle的初始化实现全在Mt76的构造函数中;
Dongle部分---关于自定义类UsbDevice
其作为xow的操作基类,基于libusb, 提供了USB控制传输和批量传输两种接口实现;
其自定义结构体“ControlPacket”的参数基于USB 控制传输定义,具体请参考《USB开发打全(第4版)》的第5章“控制传输:用于关键数据的结构化请求”;Page78;
libusb的初始化函数是libusb_init;
通过API libusb_hotplug_register_callback 进行热插拔检测,并注册了当前需检测USB dongle的vendor ID 和Product ID
Dongle部分---关于自定义类Dongle;
其作为自定义类MT76的子类存在, 使用了容器类Vector;
函数readBulkPackets的作用是:通过自定义类UsbDevice,提供的批量读函数bulkRead进行周期读取,当读取到data后,调用函数handleBulkData进行数据解析;
问题点6:xow中的Controller部分;
这部分是基于Dongle部分,所以可以理解为xow的应用实现;
Controller部分---关于自定义类GipDevice(gip.h/gip.cpp)
其基于Game Input Protocol(GIP),
以下截图的
“from controller”指代当前的xow, 再具体实现就是自定义类Controller;
“from dongle”指待适配器;
Controller部分---关于自定义类Controller;
其继承于自定义类GIPDevice;用于把接收到的手柄Event 发送到xow整合的虚拟input中;同时也负责把反馈发送给手柄;
问题点7:xow中如何处理来自手柄的按键操作,以及手柄按键的数据格式;
当前讨论的数据流向是:xbox手柄->Wifi->适配器->当前Xow接收处理;
Tracing 接收Wifi packet data的数据流向是:
Attention:当以下flow开始执行时,Dongle已完成初始化。所以在此之前,xow和Dongle之间并没有进行USB批量读取;
-->自定义类Dongle的构造函数中,在其Vector容器threads中添加了两个元素readBulkPackets;
-->执行到readBulkPackets,里面周期调用自定义类的函数bulkRead,其通过USB批量传输形式进行数据读取;
-->调用方法handleBulkData进行数据解析;
Note:这里解析所有从适配器读取的data,然后基于不同类型进行处理,其中就包括WlanPacket(Wifi 数据);
-->当检测到当前端口为“WLAN_PORT”,或当前端口为“CPU_RX_PORT”&&“event类型为EVT_PACKET_RX”时,执行函数handleWlanPacket;
当满足条件“else if (type == MT_WLAN_DATA && subtype == MT_WLAN_QOS_DATA)”时,在函数内部执行函数handleControllerPacket;
-->执行函数handleControllerPacket;
Note:这里有一个细节需注意:一个适配器可同时连接多个游戏手柄,这里的管控就是controllers数组;
-->执行到对应controllers对象方法handlePacket,这里解析具体的操作数据; 其数据的操作类型是结构体Frame,先通过Frame获取到具体的command类型(FrameCommand),然后再把偏移sizeof(Frame)后的data转换为具体command对应的结构体;
实际测试发现:当手柄按键操作时,此时收到的CMD_INPUT,最终执行的API是inputReceived;
问题点8:xow如何把反馈告知手柄(如启动手柄的震动), 以及其数据格式;
关于手柄的震动实现,可在Source Code中搜索“magnitude”字样,相关API 是inputFeedbackReceived,相关结构体是RumbleData,关联的发送API 是performRumble,其内部调用的是API sendPacket;
问题点9:当前xow中附带的测试rumble(其实就是震动)的实现方式;
实现的核心是:每当连接上时,就执行“Controller::initInput” 初始化一个线程
processRumble 进行rumble 数据等待;
-->每当手柄和适配器连接上时,函数“Controller::initInput”都会被执行,里面将创建线程processRumble
-->线程processRumble内部将执行while循环,并使用“rumbleCondition.wait(lock);”进行阻塞等待;
-->当获取到data时,将执行API performRumble进行发送;
Note:发送的data基于微软的GIP格式,而并非HID, 而且还需注意的是:最终的数据发送前,其会加上frame 部分,而非直接发送GIP data;
Attention:当前xow中提供数据组织的实现API 是inputFeedbackReceived(但其目前实测没有触发),我们只要关注其里面实现的rumble数据添加以及notify_one(用于唤醒阻塞);后续我们可以自行编写测试程式进行发送震动测试;
Note:笔者自行编写测试震动程式,分别测试了xbox 的一代和二代无线适配器,均能实现手柄的4个马达震动;
问题点10:libusb中定义的宏定义具体代表的值;
LIBUSB_ENDPOINT_IN :0x80 (bit7位为1),表示设备到主机
LIBUSB_ENDPOINT_OUT: 0x00,表示主机到设备;
LIBUSB_REQUEST_TYPE_VENDOR:0x40 (bit6位为1)
LIBUSB_RECIPIENT_DEVICE:0x00
以上定义符合《USB开发大全》第4版Page78的描述;
问题点11:xow编译成功后如何操作;
安装及启动xow:
sudo make install
sudo systemctl enable xow
sudo systemctl start xow
当执行“sudo systemctl start xow”后,再执行“sudo systemctl status now”,通过log确认xow是否已经跑起来(建议使用 make BUILD=DEBUG 编译xow);
停止及卸载xow:
sudo systemctl stop xow
sudo systemctl disable xow
sudo make uninstall
Xow如何进入配对模式
在xow的描述中,其是通过在Ubuntu中敲指令发送 SIGUSR1到xow;
sudo systemctl kill -s SIGUSR1 xow
-->Xow中使用“sigaddset”进行信号设置:
当其收到信号“SIGUSR1”时,触发以下flow:
-->执行API setPairingStatus, 其使用Wifi beacon进行信息推送,并设置无线适配器的Led等闪烁;
当前为何能使用无线适配器连接的原因是:当手柄进入到搜索模式(西瓜灯闪烁),同时无线适配器灯闪烁时,无线适配器执行802.11(Wifi) Beacon帧 ,使得手柄收到了Wifi信号(目前猜测手柄本身并不广播Wifi信号,而是等待特定广播并主动连接无线适配器);
问题点12:在手柄和适配器连接后,它们之间如何保持心跳来确认当前还处于连接状态;
通过实测发现,当手柄和适配器连接后,如果不进行任何的按键操作,适配器将每20秒收到一个CMD_STATUS 指令;
问题点13:实测xow驱动下的适配器与手柄(xbox one S)的稳定连接实况;
实测:第一次连接上后15分钟内,手柄没有任何连接操作,手柄断开并自动关机;第二次连接上后在15分钟内有操作过按键,所以一直持续要>17分钟,手动关闭手柄;
发现在公司这种Wifi 环境复杂(公司N个Wifi 路由)下,断线就会容易出现(断开后手柄自动重连);在家里Wifi 环境比较干净的话,倒是不会断线;
最后,只要把xow的整个执行flow及微软bin文件解析,就能随意移植到其他平台;笔者曾经移植到STM32 测试,能正常和xbox one S 手柄进行连接,行为、功能和在Linux平台无异;
开源xow 实测及代码分析(xbox one S 非官方linux版驱动)相关推荐
- <2021SC@SDUSC>开源游戏引擎Overload代码分析三(OvWindowing结束):OvWindowing——Dialogs
2021SC@SDUSC Overload代码分析三:OvWindowing--Dialogs 前言 Dialogs 一.FileDialog FileDialog.h FileDialog.cpp ...
- 开源知识付费APP代码分析
如今,传统的学校已经不能满足大众多元化的需求,各种教育培训机构落地生根.随着时间的推移,互联网与传统教育的结合也开拓了一种新的教育方式,这就是广为人知的知识付费.在线教育的突然崛起多半是因为疫情的&q ...
- ARM generic timer驱动代码分析
转自 蜗窝科技 http://www.wowotech.net/linux_kenrel/arm-generic-timer.html 一.前言 关注ARM平台上timer driver(clo ...
- linux v4l2系统详解,Linux摄像头驱动学习之:(一)V4L2_框架分析
这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2). 一. V4L2框架: video for linux ...
- python开源代码-这7个开源的Python库,让你轻松代码分析
原标题:这7个开源的Python库,让你轻松代码分析 开源最前线(ID:OpenSourceTop) 猿妹编译 来源:https://opensource.com/article/18/7/7-pyt ...
- 开源项目kcws代码分析--基于深度学习的分词技术
http://blog.csdn.net/pirage/article/details/53424544 分词原理 本小节内容参考待字闺中的两篇博文: 97.5%准确率的深度学习中文分词(字嵌入+Bi ...
- 开源代码分析技巧之——打印调用逻辑
开源代码分析技巧之--打印调用逻辑 在研究开源代码时,大家或许都有这样的感慨: (1)代码太庞大,少则几万行代码,多则几百万行代码,不知道如何入手: (2)相关的帮助文档有限,很难短时间内理清头绪: ...
- 开源代码分析研究 之 BugNet (2008年1月14日更新 第一章BugNet 简介 已完成)
开源代码分析研究 之 BugNet http://www.bugnetproject.com/ 写作目的:BugNet是一个不错的C#开源项目和我最近研究ASP.NET和AJAX的实现,非常的匹配, ...
- Facebook 开源代码分析工具 —— Mariana Trench
Facebook 的安全团队本周向开源社区揭晓了一个新的开源项目 --Mariana Trench,这是一个用于识别 Android 和 Java 应用程序漏洞的开源工具,Facebook 此前一直在 ...
最新文章
- 【Math】常见的几种最优化方法
- 漫画: 什么是外部排序?
- linux无线网卡消失,linux下wpa/wpa2的无线网卡设置 [暂时还没有证实是否能用]
- Android开发之ApiCloud轮播图开发
- 122. 买卖股票的最佳时机 II008(贪心算法+思路)
- leetcode 844. 比较含退格的字符串
- java字符串转json_java 字符串转成 json 数组并且遍历
- 阻塞与非阻塞 异步 与同步
- SQL2008数据库的备份与还原
- 如何使用CineMatch的伪色指南功能来帮助评估图像
- Asp.Net母版页元素ID不一致的体现
- yolov3的loss计算公式
- dw8html合并单元格,DW 做一个table表 对单元格进行合并
- 概率论 —— 条件数学期望
- 若邻网络结盟职友集,共创人脉网络与职位搜索结合的求职新模式
- 安装pywifi的坑
- TensorFlow TFRecords简介
- python读取txt文件代码-Python txt文件常用读写操作代码实例
- 如何统计文章中的高频词
- 1127. ZigZagging on a Tree (30)