Введение
Я работаю над получением полной поддержки PlayStation 4 Controller
с использованием интерфейса HID в IOKit
. Контроллер подключен через Bluetooth
. Я могу открыть соединение с контроллером и начать получать отчеты, однако, как только я отправлю ему отчет, он внезапно остановится.
Чтобы получить полный контроль над контроллером PS4 (вибрация, трекпад, светодиоды), я ссылался на страница eleccelerator.com DualShock 4, содержащая информацию об отчетах, которые могут/отправляются между PS4 и DS4.
Код
Сначала я создаю IOHIDManager
, который отвечает за обнаружение контроллеров.
self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
// Make sure we detect ANY type of 'game controller'
NSArray *criteria = [NSArray arrayWithObjects:
CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick),
CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad),
CreateCriterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController),
nil];
IOHIDManagerSetDeviceMatchingMultiple(self.hidManager, (__bridge CFArrayRef)criteria);
IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(self.hidManager, kIOHIDOptionsTypeNone);
// Register callbacks
IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, ControllerConnected, (__bridge void *)self);
IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, ControllerDisconnected, (__bridge void *)self);
Затем, получив вызов ControllerConnected
, я создаю экземпляр класса джойстика, который инициализирует класс IOHIDDeviceRef
.
- (void)registerDevice:(IOHIDDeviceRef)device {
self.device = device;
// Initialize the buffer
self.receivedPacketMaxSize = 552; // When using Bluetooth
self.receivedReport = (uint8_t *)calloc(self.receivedPacketMaxSize, sizeof(uint8_t));
// Register the device report callback
IOHIDDeviceScheduleWithRunLoop(self.device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
IOHIDDeviceRegisterInputReportCallback(self.device, self.receivedReport, self.receivedPacketMaxSize, ControllerReport, (__bridge void *)self);
self.isValid = YES;
}
Теперь я ДЕЙСТВИТЕЛЬНО получаю звонки на ControllerReport
, однако отчеты, которые я получаю, имеют тип 0x01, которые ограничены в том, что они содержат (у них нет данных трекпада или акселерометра), но я хочу получать пакеты типа 0x11, которые содержат все данные с контроллера.
Чтобы переключить, какой пакет отправляет контроллер, на веб-сайте указано This report is sent once the GET REPORT FEATURE 0x02 is received.
Поэтому я отправляю этот запрос:
CFIndex len = self.receivedPacketMaxSize;
IOReturn featureMode2RequestError = IOHIDDeviceGetReport(self.device, kIOHIDReportTypeFeature, 0x02, self.receivedReport, &len);
if (featureMode2RequestError != kIOReturnSuccess) {
NSLog(@"Could switch the controller to mode 2 :(");
}
В этот момент ControllerReport
перестает вызываться с новыми отчетами от контроллера.
Я знаю, что могу отправить данные на контроллер, потому что я могу отправить пакет, который меняет цвет светодиода или устанавливает скорость вибрации.
Вопрос
Как я могу получить более длинные отчеты 0x11 от контроллера PS4?
Что я пробовал
Я пытался использовать IOHIDDeviceGetReportWithCallback
и IOHIDDeviceGetReport
, но всегда возвращал kIOReturnUnsupported
.
Я также нашел ссылку на эту проблему в исходниках драйвера linux для контроллера в виде ... it starts sending input reports in report 17. Since report 17 is undefined ...
, однако я не знаю, как указать IOKit обрабатывать отчет 17 (0x11).