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版驱动)相关推荐

  1. <2021SC@SDUSC>开源游戏引擎Overload代码分析三(OvWindowing结束):OvWindowing——Dialogs

    2021SC@SDUSC Overload代码分析三:OvWindowing--Dialogs 前言 Dialogs 一.FileDialog FileDialog.h FileDialog.cpp ...

  2. 开源知识付费APP代码分析

    如今,传统的学校已经不能满足大众多元化的需求,各种教育培训机构落地生根.随着时间的推移,互联网与传统教育的结合也开拓了一种新的教育方式,这就是广为人知的知识付费.在线教育的突然崛起多半是因为疫情的&q ...

  3. ARM generic timer驱动代码分析

     转自 蜗窝科技 http://www.wowotech.net/linux_kenrel/arm-generic-timer.html 一.前言 关注ARM平台上timer driver(clo ...

  4. linux v4l2系统详解,Linux摄像头驱动学习之:(一)V4L2_框架分析

    这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2). 一. V4L2框架: video for linux ...

  5. python开源代码-这7个开源的Python库,让你轻松代码分析

    原标题:这7个开源的Python库,让你轻松代码分析 开源最前线(ID:OpenSourceTop) 猿妹编译 来源:https://opensource.com/article/18/7/7-pyt ...

  6. 开源项目kcws代码分析--基于深度学习的分词技术

    http://blog.csdn.net/pirage/article/details/53424544 分词原理 本小节内容参考待字闺中的两篇博文: 97.5%准确率的深度学习中文分词(字嵌入+Bi ...

  7. 开源代码分析技巧之——打印调用逻辑

    开源代码分析技巧之--打印调用逻辑 在研究开源代码时,大家或许都有这样的感慨: (1)代码太庞大,少则几万行代码,多则几百万行代码,不知道如何入手: (2)相关的帮助文档有限,很难短时间内理清头绪: ...

  8. 开源代码分析研究 之 BugNet (2008年1月14日更新 第一章BugNet 简介 已完成)

    开源代码分析研究 之 BugNet  http://www.bugnetproject.com/ 写作目的:BugNet是一个不错的C#开源项目和我最近研究ASP.NET和AJAX的实现,非常的匹配, ...

  9. Facebook 开源代码分析工具 —— Mariana Trench

    Facebook 的安全团队本周向开源社区揭晓了一个新的开源项目 --Mariana Trench,这是一个用于识别 Android 和 Java 应用程序漏洞的开源工具,Facebook 此前一直在 ...

最新文章

  1. 【Math】常见的几种最优化方法
  2. 漫画: 什么是外部排序?
  3. linux无线网卡消失,linux下wpa/wpa2的无线网卡设置 [暂时还没有证实是否能用]
  4. Android开发之ApiCloud轮播图开发
  5. 122. 买卖股票的最佳时机 II008(贪心算法+思路)
  6. leetcode 844. 比较含退格的字符串
  7. java字符串转json_java 字符串转成 json 数组并且遍历
  8. 阻塞与非阻塞 异步 与同步
  9. SQL2008数据库的备份与还原
  10. 如何使用CineMatch的伪色指南功能来帮助评估图像
  11. Asp.Net母版页元素ID不一致的体现
  12. yolov3的loss计算公式
  13. dw8html合并单元格,DW 做一个table表 对单元格进行合并
  14. 概率论 —— 条件数学期望
  15. 若邻网络结盟职友集,共创人脉网络与职位搜索结合的求职新模式
  16. 安装pywifi的坑
  17. TensorFlow TFRecords简介
  18. python读取txt文件代码-Python txt文件常用读写操作代码实例
  19. 如何统计文章中的高频词
  20. 1127. ZigZagging on a Tree (30)

热门文章

  1. 拜访客户要做的12件工作
  2. python 取反操作符(~)
  3. 用户权限匹配中英文翻译
  4. 自动阅读专业版第六次更新
  5. 基于华为Java编程规范的Eclipse checkStyle.xml
  6. Python-Django毕业设计超市销售管理系统(程序+Lw)
  7. 计算机毕业设计JAVA售后管理系统mybatis+源码+调试部署+系统+数据库+lw
  8. HUD市场探析:困顿30年后现转机,未来2-3年或迎爆发期
  9. 牛年的春节,【抢票神器】最没用的一年
  10. velocity官网介绍