diff options
author | chai <chaifix@163.com> | 2019-03-19 23:06:27 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-03-19 23:06:27 +0800 |
commit | 1497dccd63a84b7ee2b229b1ad9c5c02718f2a78 (patch) | |
tree | f8d1bff50da13e126d08c7345653e002e293202d /Source/3rdParty/SDL2/src/hidapi/ios | |
parent | 5e2a973516e0729b225da9de0b03015dc5854ac4 (diff) |
*rename
Diffstat (limited to 'Source/3rdParty/SDL2/src/hidapi/ios')
-rw-r--r-- | Source/3rdParty/SDL2/src/hidapi/ios/Makefile-manual | 32 | ||||
-rw-r--r-- | Source/3rdParty/SDL2/src/hidapi/ios/Makefile.am | 9 | ||||
-rw-r--r-- | Source/3rdParty/SDL2/src/hidapi/ios/hid.m | 914 |
3 files changed, 0 insertions, 955 deletions
diff --git a/Source/3rdParty/SDL2/src/hidapi/ios/Makefile-manual b/Source/3rdParty/SDL2/src/hidapi/ios/Makefile-manual deleted file mode 100644 index 939a077..0000000 --- a/Source/3rdParty/SDL2/src/hidapi/ios/Makefile-manual +++ /dev/null @@ -1,32 +0,0 @@ -########################################### -# Simple Makefile for HIDAPI test program -# -# Alan Ott -# Signal 11 Software -# 2010-07-03 -########################################### - -all: hidtest - -CC=gcc -CXX=g++ -COBJS=hid.o -CPPOBJS=../hidtest/hidtest.o -OBJS=$(COBJS) $(CPPOBJS) -CFLAGS+=-I../hidapi -Wall -g -c -LIBS=-framework CoreBluetooth -framework CoreFoundation - - -hidtest: $(OBJS) - g++ -Wall -g $^ $(LIBS) -o hidtest - -$(COBJS): %.o: %.c - $(CC) $(CFLAGS) $< -o $@ - -$(CPPOBJS): %.o: %.cpp - $(CXX) $(CFLAGS) $< -o $@ - -clean: - rm -f *.o hidtest $(CPPOBJS) - -.PHONY: clean diff --git a/Source/3rdParty/SDL2/src/hidapi/ios/Makefile.am b/Source/3rdParty/SDL2/src/hidapi/ios/Makefile.am deleted file mode 100644 index 1f8f2ce..0000000 --- a/Source/3rdParty/SDL2/src/hidapi/ios/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -lib_LTLIBRARIES = libhidapi.la -libhidapi_la_SOURCES = hid.m -libhidapi_la_LDFLAGS = $(LTLDFLAGS) -AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ - -hdrdir = $(includedir)/hidapi -hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h - -EXTRA_DIST = Makefile-manual diff --git a/Source/3rdParty/SDL2/src/hidapi/ios/hid.m b/Source/3rdParty/SDL2/src/hidapi/ios/hid.m deleted file mode 100644 index a0ca7cd..0000000 --- a/Source/3rdParty/SDL2/src/hidapi/ios/hid.m +++ /dev/null @@ -1,914 +0,0 @@ -//======== Copyright (c) 2017 Valve Corporation, All rights reserved. ========= -// -// Purpose: HID device abstraction temporary stub -// -//============================================================================= -#include "../../SDL_internal.h" - -#ifdef SDL_JOYSTICK_HIDAPI - -#include <CoreBluetooth/CoreBluetooth.h> -#include <QuartzCore/QuartzCore.h> -#import <UIKit/UIKit.h> -#import <mach/mach_time.h> -#include <pthread.h> -#include <sys/time.h> -#include <unistd.h> -#include "../hidapi/hidapi.h" - -#define VALVE_USB_VID 0x28DE -#define D0G_BLE2_PID 0x1106 - -typedef uint32_t uint32; -typedef uint64_t uint64; - -// enables detailed NSLog logging of feature reports -#define FEATURE_REPORT_LOGGING 0 - -#define REPORT_SEGMENT_DATA_FLAG 0x80 -#define REPORT_SEGMENT_LAST_FLAG 0x40 - -#define VALVE_SERVICE @"100F6C32-1735-4313-B402-38567131E5F3" - -// (READ/NOTIFICATIONS) -#define VALVE_INPUT_CHAR @"100F6C33-1735-4313-B402-38567131E5F3" - -// (READ/WRITE) -#define VALVE_REPORT_CHAR @"100F6C34-1735-4313-B402-38567131E5F3" - -// TODO: create CBUUID's in __attribute__((constructor)) rather than doing [CBUUID UUIDWithString:...] everywhere - -#pragma pack(push,1) - -typedef struct -{ - uint8_t segmentHeader; - uint8_t featureReportMessageID; - uint8_t length; - uint8_t settingIdentifier; - union { - uint16_t usPayload; - uint32_t uPayload; - uint64_t ulPayload; - uint8_t ucPayload[15]; - }; -} bluetoothSegment; - -typedef struct { - uint8_t id; - union { - bluetoothSegment segment; - struct { - uint8_t segmentHeader; - uint8_t featureReportMessageID; - uint8_t length; - uint8_t settingIdentifier; - union { - uint16_t usPayload; - uint32_t uPayload; - uint64_t ulPayload; - uint8_t ucPayload[15]; - }; - }; - }; -} hidFeatureReport; - -#pragma pack(pop) - -size_t GetBluetoothSegmentSize(bluetoothSegment *segment) -{ - return segment->length + 3; -} - -#define RingBuffer_cbElem 19 -#define RingBuffer_nElem 4096 - -typedef struct { - int _first, _last; - uint8_t _data[ ( RingBuffer_nElem * RingBuffer_cbElem ) ]; - pthread_mutex_t accessLock; -} RingBuffer; - -static void RingBuffer_init( RingBuffer *this ) -{ - this->_first = -1; - this->_last = 0; - pthread_mutex_init( &this->accessLock, 0 ); -} - -static bool RingBuffer_write( RingBuffer *this, const uint8_t *src ) -{ - pthread_mutex_lock( &this->accessLock ); - memcpy( &this->_data[ this->_last ], src, RingBuffer_cbElem ); - if ( this->_first == -1 ) - { - this->_first = this->_last; - } - this->_last = ( this->_last + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem); - if ( this->_last == this->_first ) - { - this->_first = ( this->_first + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem); - pthread_mutex_unlock( &this->accessLock ); - return false; - } - pthread_mutex_unlock( &this->accessLock ); - return true; -} - -static bool RingBuffer_read( RingBuffer *this, uint8_t *dst ) -{ - pthread_mutex_lock( &this->accessLock ); - if ( this->_first == -1 ) - { - pthread_mutex_unlock( &this->accessLock ); - return false; - } - memcpy( dst, &this->_data[ this->_first ], RingBuffer_cbElem ); - this->_first = ( this->_first + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem); - if ( this->_first == this->_last ) - { - this->_first = -1; - } - pthread_mutex_unlock( &this->accessLock ); - return true; -} - - -#pragma mark HIDBLEDevice Definition - -typedef enum -{ - BLEDeviceWaitState_None, - BLEDeviceWaitState_Waiting, - BLEDeviceWaitState_Complete, - BLEDeviceWaitState_Error -} BLEDeviceWaitState; - -@interface HIDBLEDevice : NSObject <CBPeripheralDelegate> -{ - RingBuffer _inputReports; - uint8_t _featureReport[20]; - BLEDeviceWaitState _waitStateForReadFeatureReport; - BLEDeviceWaitState _waitStateForWriteFeatureReport; -} - -@property (nonatomic, readwrite) bool connected; -@property (nonatomic, readwrite) bool ready; - -@property (nonatomic, strong) CBPeripheral *bleSteamController; -@property (nonatomic, strong) CBCharacteristic *bleCharacteristicInput; -@property (nonatomic, strong) CBCharacteristic *bleCharacteristicReport; - -- (id)initWithPeripheral:(CBPeripheral *)peripheral; - -@end - - -@interface HIDBLEManager : NSObject <CBCentralManagerDelegate> - -@property (nonatomic) int nPendingScans; -@property (nonatomic) int nPendingPairs; -@property (nonatomic, strong) CBCentralManager *centralManager; -@property (nonatomic, strong) NSMapTable<CBPeripheral *, HIDBLEDevice *> *deviceMap; -@property (nonatomic, retain) dispatch_queue_t bleSerialQueue; - -+ (instancetype)sharedInstance; -- (void)startScan:(int)duration; -- (void)stopScan; -- (int)updateConnectedSteamControllers:(BOOL) bForce; -- (void)appWillResignActiveNotification:(NSNotification *)note; -- (void)appDidBecomeActiveNotification:(NSNotification *)note; - -@end - - -// singleton class - access using HIDBLEManager.sharedInstance -@implementation HIDBLEManager - -+ (instancetype)sharedInstance -{ - static HIDBLEManager *sharedInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [HIDBLEManager new]; - sharedInstance.nPendingScans = 0; - sharedInstance.nPendingPairs = 0; - - [[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(appWillResignActiveNotification:) name: UIApplicationWillResignActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(appDidBecomeActiveNotification:) name:UIApplicationDidBecomeActiveNotification object:nil]; - - // receive reports on a high-priority serial-queue. optionally put writes on the serial queue to avoid logical - // race conditions talking to the controller from multiple threads, although BLE fragmentation/assembly means - // that we can still screw this up. - // most importantly we need to consume reports at a high priority to avoid the OS thinking we aren't really - // listening to the BLE device, as iOS on slower devices may stop delivery of packets to the app WITHOUT ACTUALLY - // DISCONNECTING FROM THE DEVICE if we don't react quickly enough to their delivery. - // see also the error-handling states in the peripheral delegate to re-open the device if it gets closed - sharedInstance.bleSerialQueue = dispatch_queue_create( "com.valvesoftware.steamcontroller.ble", DISPATCH_QUEUE_SERIAL ); - dispatch_set_target_queue( sharedInstance.bleSerialQueue, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ) ); - - // creating a CBCentralManager will always trigger a future centralManagerDidUpdateState: - // where any scanning gets started or connecting to existing peripherals happens, it's never already in a - // powered-on state for a newly launched application. - sharedInstance.centralManager = [[CBCentralManager alloc] initWithDelegate:sharedInstance queue:sharedInstance.bleSerialQueue]; - sharedInstance.deviceMap = [[NSMapTable alloc] initWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableStrongMemory capacity:4]; - }); - return sharedInstance; -} - -// called for NSNotification UIApplicationWillResignActiveNotification -- (void)appWillResignActiveNotification:(NSNotification *)note -{ - // we'll get resign-active notification if pairing is happening. - if ( self.nPendingPairs > 0 ) - return; - - for ( CBPeripheral *peripheral in self.deviceMap ) - { - HIDBLEDevice *steamController = [self.deviceMap objectForKey:peripheral]; - if ( steamController ) - { - steamController.connected = NO; - steamController.ready = NO; - [self.centralManager cancelPeripheralConnection:peripheral]; - } - } - [self.deviceMap removeAllObjects]; -} - -// called for NSNotification UIApplicationDidBecomeActiveNotification -// whenever the application comes back from being inactive, trigger a 20s pairing scan and reconnect -// any devices that may have paired while we were inactive. -- (void)appDidBecomeActiveNotification:(NSNotification *)note -{ - [self updateConnectedSteamControllers:true]; - [self startScan:20]; -} - -- (int)updateConnectedSteamControllers:(BOOL) bForce -{ - static uint64_t s_unLastUpdateTick = 0; - static mach_timebase_info_data_t s_timebase_info; - - if (s_timebase_info.denom == 0) - { - mach_timebase_info( &s_timebase_info ); - } - - uint64_t ticksNow = mach_approximate_time(); - if ( !bForce && ( ( (ticksNow - s_unLastUpdateTick) * s_timebase_info.numer ) / s_timebase_info.denom ) < (5ull * NSEC_PER_SEC) ) - return (int)self.deviceMap.count; - - // we can see previously connected BLE peripherals but can't connect until the CBCentralManager - // is fully powered up - only do work when we are in that state - if ( self.centralManager.state != CBManagerStatePoweredOn ) - return (int)self.deviceMap.count; - - // only update our last-check-time if we actually did work, otherwise there can be a long delay during initial power-up - s_unLastUpdateTick = mach_approximate_time(); - - // if a pair is in-flight, the central manager may still give it back via retrieveConnected... and - // cause the SDL layer to attempt to initialize it while some of its endpoints haven't yet been established - if ( self.nPendingPairs > 0 ) - return (int)self.deviceMap.count; - - NSArray<CBPeripheral *> *peripherals = [self.centralManager retrieveConnectedPeripheralsWithServices: @[ [CBUUID UUIDWithString:@"180A"]]]; - for ( CBPeripheral *peripheral in peripherals ) - { - // we already know this peripheral - if ( [self.deviceMap objectForKey: peripheral] != nil ) - continue; - - NSLog( @"connected peripheral: %@", peripheral ); - if ( [peripheral.name isEqualToString:@"SteamController"] ) - { - HIDBLEDevice *steamController = [[HIDBLEDevice alloc] initWithPeripheral:peripheral]; - [self.deviceMap setObject:steamController forKey:peripheral]; - [self.centralManager connectPeripheral:peripheral options:nil]; - } - } - - return (int)self.deviceMap.count; -} - -// manual API for folks to start & stop scanning -- (void)startScan:(int)duration -{ - NSLog( @"BLE: requesting scan for %d seconds", duration ); - @synchronized (self) - { - if ( _nPendingScans++ == 0 ) - { - [self.centralManager scanForPeripheralsWithServices:nil options:nil]; - } - } - - if ( duration != 0 ) - { - dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self stopScan]; - }); - } -} - -- (void)stopScan -{ - NSLog( @"BLE: stopping scan" ); - @synchronized (self) - { - if ( --_nPendingScans <= 0 ) - { - _nPendingScans = 0; - [self.centralManager stopScan]; - } - } -} - - -#pragma mark CBCentralManagerDelegate Implementation - -// called whenever the BLE hardware state changes. -- (void)centralManagerDidUpdateState:(CBCentralManager *)central -{ - switch ( central.state ) - { - case CBCentralManagerStatePoweredOn: - { - NSLog( @"CoreBluetooth BLE hardware is powered on and ready" ); - - // at startup, if we have no already attached peripherals, do a 20s scan for new unpaired devices, - // otherwise callers should occaisionally do additional scans. we don't want to continuously be - // scanning because it drains battery, causes other nearby people to have a hard time pairing their - // Steam Controllers, and may also trigger firmware weirdness when a device attempts to start - // the pairing sequence multiple times concurrently - if ( [self updateConnectedSteamControllers:false] == 0 ) - { - // TODO: we could limit our scan to only peripherals supporting the SteamController service, but - // that service doesn't currently fit in the base advertising packet, we'd need to put it into an - // extended scan packet. Useful optimization downstream, but not currently necessary - // NSArray *services = @[[CBUUID UUIDWithString:VALVE_SERVICE]]; - [self startScan:20]; - } - break; - } - - case CBCentralManagerStatePoweredOff: - NSLog( @"CoreBluetooth BLE hardware is powered off" ); - break; - - case CBCentralManagerStateUnauthorized: - NSLog( @"CoreBluetooth BLE state is unauthorized" ); - break; - - case CBCentralManagerStateUnknown: - NSLog( @"CoreBluetooth BLE state is unknown" ); - break; - - case CBCentralManagerStateUnsupported: - NSLog( @"CoreBluetooth BLE hardware is unsupported on this platform" ); - break; - - case CBCentralManagerStateResetting: - NSLog( @"CoreBluetooth BLE manager is resetting" ); - break; - } -} - -- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral -{ - HIDBLEDevice *steamController = [_deviceMap objectForKey:peripheral]; - steamController.connected = YES; - self.nPendingPairs -= 1; -} - -- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - NSLog( @"Failed to connect: %@", error ); - [_deviceMap removeObjectForKey:peripheral]; - self.nPendingPairs -= 1; -} - -- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI -{ - NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; - NSString *log = [NSString stringWithFormat:@"Found '%@'", localName]; - - if ( [localName isEqualToString:@"SteamController"] ) - { - NSLog( @"%@ : %@ - %@", log, peripheral, advertisementData ); - self.nPendingPairs += 1; - HIDBLEDevice *steamController = [[HIDBLEDevice alloc] initWithPeripheral:peripheral]; - [self.deviceMap setObject:steamController forKey:peripheral]; - [self.centralManager connectPeripheral:peripheral options:nil]; - } -} - -- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error -{ - HIDBLEDevice *steamController = [self.deviceMap objectForKey:peripheral]; - if ( steamController ) - { - steamController.connected = NO; - steamController.ready = NO; - [self.deviceMap removeObjectForKey:peripheral]; - } -} - -@end - - -// Core Bluetooth devices calling back on event boundaries of their run-loops. so annoying. -static void process_pending_events() -{ - CFRunLoopRunResult res; - do - { - res = CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.001, FALSE ); - } - while( res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut ); -} - -@implementation HIDBLEDevice - -- (id)init -{ - if ( self = [super init] ) - { - RingBuffer_init( &_inputReports ); - self.bleSteamController = nil; - self.bleCharacteristicInput = nil; - self.bleCharacteristicReport = nil; - _connected = NO; - _ready = NO; - } - return self; -} - -- (id)initWithPeripheral:(CBPeripheral *)peripheral -{ - if ( self = [super init] ) - { - RingBuffer_init( &_inputReports ); - _connected = NO; - _ready = NO; - self.bleSteamController = peripheral; - if ( peripheral ) - { - peripheral.delegate = self; - } - self.bleCharacteristicInput = nil; - self.bleCharacteristicReport = nil; - } - return self; -} - -- (void)setConnected:(bool)connected -{ - _connected = connected; - if ( _connected ) - { - [_bleSteamController discoverServices:nil]; - } - else - { - NSLog( @"Disconnected" ); - } -} - -- (size_t)read_input_report:(uint8_t *)dst -{ - if ( RingBuffer_read( &_inputReports, dst+1 ) ) - { - *dst = 0x03; - return 20; - } - return 0; -} - -- (int)send_report:(const uint8_t *)data length:(size_t)length -{ - [_bleSteamController writeValue:[NSData dataWithBytes:data length:length] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse]; - return (int)length; -} - -- (int)send_feature_report:(hidFeatureReport *)report -{ -#if FEATURE_REPORT_LOGGING - uint8_t *reportBytes = (uint8_t *)report; - - NSLog( @"HIDBLE:send_feature_report (%02zu/19) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", GetBluetoothSegmentSize( report->segment ), - reportBytes[1], reportBytes[2], reportBytes[3], reportBytes[4], reportBytes[5], reportBytes[6], - reportBytes[7], reportBytes[8], reportBytes[9], reportBytes[10], reportBytes[11], reportBytes[12], - reportBytes[13], reportBytes[14], reportBytes[15], reportBytes[16], reportBytes[17], reportBytes[18], - reportBytes[19] ); -#endif - - int sendSize = (int)GetBluetoothSegmentSize( &report->segment ); - if ( sendSize > 20 ) - sendSize = 20; - -#if 1 - // fire-and-forget - we are going to not wait for the response here because all Steam Controller BLE send_feature_report's are ignored, - // except errors. - [_bleSteamController writeValue:[NSData dataWithBytes:&report->segment length:sendSize] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse]; - - // pretend we received a result anybody cares about - return 19; - -#else - // this is technically the correct send_feature_report logic if you want to make sure it gets through and is - // acknowledged or errors out - _waitStateForWriteFeatureReport = BLEDeviceWaitState_Waiting; - [_bleSteamController writeValue:[NSData dataWithBytes:&report->segment length:sendSize - ] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse]; - - while ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Waiting ) - { - process_pending_events(); - } - - if ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Error ) - { - _waitStateForWriteFeatureReport = BLEDeviceWaitState_None; - return -1; - } - - _waitStateForWriteFeatureReport = BLEDeviceWaitState_None; - return 19; -#endif -} - -- (int)get_feature_report:(uint8_t)feature into:(uint8_t *)buffer -{ - _waitStateForReadFeatureReport = BLEDeviceWaitState_Waiting; - [_bleSteamController readValueForCharacteristic:_bleCharacteristicReport]; - - while ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Waiting ) - process_pending_events(); - - if ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Error ) - { - _waitStateForReadFeatureReport = BLEDeviceWaitState_None; - return -1; - } - - memcpy( buffer, _featureReport, sizeof(_featureReport) ); - - _waitStateForReadFeatureReport = BLEDeviceWaitState_None; - -#if FEATURE_REPORT_LOGGING - NSLog( @"HIDBLE:get_feature_report (19) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", - buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], - buffer[7], buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], - buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], - buffer[19] ); -#endif - - return 19; -} - -#pragma mark CBPeripheralDelegate Implementation - -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error -{ - for (CBService *service in peripheral.services) - { - NSLog( @"Found Service: %@", service ); - if ( [service.UUID isEqual:[CBUUID UUIDWithString:VALVE_SERVICE]] ) - { - [peripheral discoverCharacteristics:nil forService:service]; - } - } -} - -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - // nothing yet needed here, enable for logging - if ( /* DISABLES CODE */ (0) ) - { - for ( CBDescriptor *descriptor in characteristic.descriptors ) - { - NSLog( @" - Descriptor '%@'", descriptor ); - } - } -} - -- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error -{ - if ([service.UUID isEqual:[CBUUID UUIDWithString:VALVE_SERVICE]]) - { - for (CBCharacteristic *aChar in service.characteristics) - { - NSLog( @"Found Characteristic %@", aChar ); - - if ( [aChar.UUID isEqual:[CBUUID UUIDWithString:VALVE_INPUT_CHAR]] ) - { - self.bleCharacteristicInput = aChar; - } - else if ( [aChar.UUID isEqual:[CBUUID UUIDWithString:VALVE_REPORT_CHAR]] ) - { - self.bleCharacteristicReport = aChar; - [self.bleSteamController discoverDescriptorsForCharacteristic: aChar]; - } - } - } -} - -- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - static uint64_t s_ticksLastOverflowReport = 0; - - // receiving an input report is the final indicator that the user accepted a pairing - // request and that we successfully established notification. CoreBluetooth has no - // notification of the pairing acknowledgement, which is a bad oversight. - if ( self.ready == NO ) - { - self.ready = YES; - HIDBLEManager.sharedInstance.nPendingPairs -= 1; - } - - if ( [characteristic.UUID isEqual:_bleCharacteristicInput.UUID] ) - { - NSData *data = [characteristic value]; - if ( data.length != 19 ) - { - NSLog( @"HIDBLE: incoming data is %lu bytes should be exactly 19", (unsigned long)data.length ); - } - if ( !RingBuffer_write( &_inputReports, (const uint8_t *)data.bytes ) ) - { - uint64_t ticksNow = mach_approximate_time(); - if ( ticksNow - s_ticksLastOverflowReport > (5ull * NSEC_PER_SEC / 10) ) - { - NSLog( @"HIDBLE: input report buffer overflow" ); - s_ticksLastOverflowReport = ticksNow; - } - } - } - else if ( [characteristic.UUID isEqual:_bleCharacteristicReport.UUID] ) - { - memset( _featureReport, 0, sizeof(_featureReport) ); - - if ( error != nil ) - { - NSLog( @"HIDBLE: get_feature_report error: %@", error ); - _waitStateForReadFeatureReport = BLEDeviceWaitState_Error; - } - else - { - NSData *data = [characteristic value]; - if ( data.length != 20 ) - { - NSLog( @"HIDBLE: incoming data is %lu bytes should be exactly 20", (unsigned long)data.length ); - } - memcpy( _featureReport, data.bytes, MIN( data.length, sizeof(_featureReport) ) ); - _waitStateForReadFeatureReport = BLEDeviceWaitState_Complete; - } - } -} - -- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - if ( [characteristic.UUID isEqual:[CBUUID UUIDWithString:VALVE_REPORT_CHAR]] ) - { - if ( error != nil ) - { - NSLog( @"HIDBLE: write_feature_report error: %@", error ); - _waitStateForWriteFeatureReport = BLEDeviceWaitState_Error; - } - else - { - _waitStateForWriteFeatureReport = BLEDeviceWaitState_Complete; - } - } -} - -- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error -{ - NSLog( @"didUpdateNotifcationStateForCharacteristic %@ (%@)", characteristic, error ); -} - -@end - - -#pragma mark hid_api implementation - -struct hid_device_ { - void *device_handle; - int blocking; - hid_device *next; -}; - -int HID_API_EXPORT HID_API_CALL hid_init(void) -{ - return ( HIDBLEManager.sharedInstance == nil ) ? -1 : 0; -} - -int HID_API_EXPORT HID_API_CALL hid_exit(void) -{ - return 0; -} - -void HID_API_EXPORT HID_API_CALL hid_ble_scan( bool bStart ) -{ - HIDBLEManager *bleManager = HIDBLEManager.sharedInstance; - if ( bStart ) - { - [bleManager startScan:0]; - } - else - { - [bleManager stopScan]; - } -} - -hid_device * HID_API_EXPORT hid_open_path( const char *path, int bExclusive /* = false */ ) -{ - hid_device *result = NULL; - NSString *nssPath = [NSString stringWithUTF8String:path]; - HIDBLEManager *bleManager = HIDBLEManager.sharedInstance; - NSEnumerator<HIDBLEDevice *> *devices = [bleManager.deviceMap objectEnumerator]; - - for ( HIDBLEDevice *device in devices ) - { - // we have the device but it hasn't found its service or characteristics until it is connected - if ( !device.ready || !device.connected || !device.bleCharacteristicInput ) - continue; - - if ( [device.bleSteamController.identifier.UUIDString isEqualToString:nssPath] ) - { - result = (hid_device *)malloc( sizeof( hid_device ) ); - memset( result, 0, sizeof( hid_device ) ); - result->device_handle = (void*)CFBridgingRetain( device ); - result->blocking = NO; - // enable reporting input events on the characteristic - [device.bleSteamController setNotifyValue:YES forCharacteristic:device.bleCharacteristicInput]; - return result; - } - } - return result; -} - -void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) -{ - /* This function is identical to the Linux version. Platform independent. */ - struct hid_device_info *d = devs; - while (d) { - struct hid_device_info *next = d->next; - free(d->path); - free(d->serial_number); - free(d->manufacturer_string); - free(d->product_string); - free(d); - d = next; - } -} - -int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) -{ - /* All Nonblocking operation is handled by the library. */ - dev->blocking = !nonblock; - - return 0; -} - -struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) -{ @autoreleasepool { - struct hid_device_info *root = NULL; - - if ( ( vendor_id == 0 && product_id == 0 ) || - ( vendor_id == VALVE_USB_VID && product_id == D0G_BLE2_PID ) ) - { - HIDBLEManager *bleManager = HIDBLEManager.sharedInstance; - [bleManager updateConnectedSteamControllers:false]; - NSEnumerator<HIDBLEDevice *> *devices = [bleManager.deviceMap objectEnumerator]; - for ( HIDBLEDevice *device in devices ) - { - // there are several brief windows in connecting to an already paired device and - // one long window waiting for users to confirm pairing where we don't want - // to consider a device ready - if we hand it back to SDL or another - // Steam Controller consumer, their additional SC setup work will fail - // in unusual/silent ways and we can actually corrupt the BLE stack for - // the entire system and kill the appletv remote's Menu button (!) - if ( device.bleSteamController.state != CBPeripheralStateConnected || - device.connected == NO || device.ready == NO ) - { - if ( device.ready == NO && device.bleCharacteristicInput != nil ) - { - // attempt to register for input reports. this call will silently fail - // until the pairing finalizes with user acceptance. oh, apple. - [device.bleSteamController setNotifyValue:YES forCharacteristic:device.bleCharacteristicInput]; - } - continue; - } - struct hid_device_info *device_info = (struct hid_device_info *)malloc( sizeof(struct hid_device_info) ); - memset( device_info, 0, sizeof(struct hid_device_info) ); - device_info->next = root; - root = device_info; - device_info->path = strdup( device.bleSteamController.identifier.UUIDString.UTF8String ); - device_info->vendor_id = VALVE_USB_VID; - device_info->product_id = D0G_BLE2_PID; - device_info->product_string = wcsdup( L"Steam Controller" ); - device_info->manufacturer_string = wcsdup( L"Valve Corporation" ); - } - } - return root; -}} - -int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - static wchar_t s_wszManufacturer[] = L"Valve Corporation"; - wcsncpy( string, s_wszManufacturer, sizeof(s_wszManufacturer)/sizeof(s_wszManufacturer[0]) ); - return 0; -} - -int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - static wchar_t s_wszProduct[] = L"Steam Controller"; - wcsncpy( string, s_wszProduct, sizeof(s_wszProduct)/sizeof(s_wszProduct[0]) ); - return 0; -} - -int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) -{ - static wchar_t s_wszSerial[] = L"12345"; - wcsncpy( string, s_wszSerial, sizeof(s_wszSerial)/sizeof(s_wszSerial[0]) ); - return 0; -} - -int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) -{ - HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle; - - if ( !device_handle.connected ) - return -1; - - return [device_handle send_report:data length:length]; -} - -void HID_API_EXPORT hid_close(hid_device *dev) -{ - HIDBLEDevice *device_handle = CFBridgingRelease( dev->device_handle ); - - // disable reporting input events on the characteristic - if ( device_handle.connected ) { - [device_handle.bleSteamController setNotifyValue:NO forCharacteristic:device_handle.bleCharacteristicInput]; - } - - free( dev ); -} - -int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) -{ - HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle; - - if ( !device_handle.connected ) - return -1; - - return [device_handle send_feature_report:(hidFeatureReport *)(void *)data]; -} - -int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) -{ - HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle; - - if ( !device_handle.connected ) - return -1; - - size_t written = [device_handle get_feature_report:data[0] into:data]; - - return written == length-1 ? (int)length : (int)written; -} - -int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) -{ - HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle; - - if ( !device_handle.connected ) - return -1; - - return hid_read_timeout(dev, data, length, 0); -} - -int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) -{ - HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle; - - if ( !device_handle.connected ) - return -1; - - if ( milliseconds != 0 ) - { - NSLog( @"hid_read_timeout with non-zero wait" ); - } - int result = (int)[device_handle read_input_report:data]; -#if FEATURE_REPORT_LOGGING - NSLog( @"HIDBLE:hid_read_timeout (%d) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", result, - data[1], data[2], data[3], data[4], data[5], data[6], - data[7], data[8], data[9], data[10], data[11], data[12], - data[13], data[14], data[15], data[16], data[17], data[18], - data[19] ); -#endif - return result; -} - -#endif /* SDL_JOYSTICK_HIDAPI */ |