Browse Source

Removed dependency on C++ runtime on iOS

Sam Lantinga 6 years ago
parent
commit
e9f6805fc6
2 changed files with 122 additions and 94 deletions
  1. 6 4
      Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
  2. 116 90
      src/hidapi/ios/hid.m

+ 6 - 4
Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj

@@ -203,7 +203,8 @@
 		F30D9CA5212CD0BF0047DF2E /* SDL_coremotionsensor.m in Sources */ = {isa = PBXBuildFile; fileRef = F30D9CA3212CD0BF0047DF2E /* SDL_coremotionsensor.m */; };
 		F30D9CA6212CD0BF0047DF2E /* SDL_coremotionsensor.m in Sources */ = {isa = PBXBuildFile; fileRef = F30D9CA3212CD0BF0047DF2E /* SDL_coremotionsensor.m */; };
 		F30D9CA7212CD0BF0047DF2E /* SDL_coremotionsensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F30D9CA4212CD0BF0047DF2E /* SDL_coremotionsensor.h */; };
-		F3BDD77620F51C3C004ECBF3 /* hid.mm in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD77520F51C3C004ECBF3 /* hid.mm */; };
+		F30D9CC6212CE92C0047DF2E /* hid.m in Sources */ = {isa = PBXBuildFile; fileRef = F30D9CC5212CE92C0047DF2E /* hid.m */; };
+		F30D9CC7212CE92C0047DF2E /* hid.m in Sources */ = {isa = PBXBuildFile; fileRef = F30D9CC5212CE92C0047DF2E /* hid.m */; };
 		F3BDD79220F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */; };
 		F3BDD79320F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */; };
 		F3BDD79420F51CB8004ECBF3 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */; };
@@ -535,7 +536,7 @@
 		F30D9C9D212CD0990047DF2E /* SDL_sensor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_sensor.c; sourceTree = "<group>"; };
 		F30D9CA3212CD0BF0047DF2E /* SDL_coremotionsensor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_coremotionsensor.m; sourceTree = "<group>"; };
 		F30D9CA4212CD0BF0047DF2E /* SDL_coremotionsensor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_coremotionsensor.h; sourceTree = "<group>"; };
-		F3BDD77520F51C3C004ECBF3 /* hid.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = hid.mm; sourceTree = "<group>"; };
+		F30D9CC5212CE92C0047DF2E /* hid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = hid.m; sourceTree = "<group>"; };
 		F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xbox360.c; sourceTree = "<group>"; };
 		F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_switch.c; sourceTree = "<group>"; };
 		F3BDD78D20F51CB8004ECBF3 /* SDL_hidapi_xboxone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xboxone.c; sourceTree = "<group>"; };
@@ -859,7 +860,7 @@
 		F3BDD77420F51C18004ECBF3 /* ios */ = {
 			isa = PBXGroup;
 			children = (
-				F3BDD77520F51C3C004ECBF3 /* hid.mm */,
+				F30D9CC5212CE92C0047DF2E /* hid.m */,
 			);
 			path = ios;
 			sourceTree = "<group>";
@@ -1520,6 +1521,7 @@
 				FAB598421BB5C31500BE72C5 /* SDL_quit.c in Sources */,
 				FAB598441BB5C31500BE72C5 /* SDL_touch.c in Sources */,
 				FAB598461BB5C31500BE72C5 /* SDL_windowevents.c in Sources */,
+				F30D9CC7212CE92C0047DF2E /* hid.m in Sources */,
 				FAB598491BB5C31600BE72C5 /* SDL_rwopsbundlesupport.m in Sources */,
 				FAB5984A1BB5C31600BE72C5 /* SDL_rwops.c in Sources */,
 				FAB5984B1BB5C31600BE72C5 /* SDL_sysfilesystem.m in Sources */,
@@ -1631,6 +1633,7 @@
 				FD6526750DE8FCDD002AD96B /* SDL_windowevents.c in Sources */,
 				4D7516FB1EE1C28A00820EEA /* SDL_uikitmetalview.m in Sources */,
 				FD6526760DE8FCDD002AD96B /* SDL_rwops.c in Sources */,
+				F30D9CC6212CE92C0047DF2E /* hid.m in Sources */,
 				4D7517201EE1D98200820EEA /* SDL_vulkan_utils.c in Sources */,
 				FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */,
 				FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */,
@@ -1716,7 +1719,6 @@
 				AA628ADB159369E3005138DD /* SDL_rotate.c in Sources */,
 				AA126AD51617C5E7005ABC8F /* SDL_uikitmodes.m in Sources */,
 				AA704DD7162AA90A0076D1C1 /* SDL_dropevents.c in Sources */,
-				F3BDD77620F51C3C004ECBF3 /* hid.mm in Sources */,
 				AABCC3951640643D00AB8930 /* SDL_uikitmessagebox.m in Sources */,
 				AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */,
 				AA0F8495178D5F1A00823F9D /* SDL_systls.c in Sources */,

+ 116 - 90
src/hidapi/ios/hid.mm → src/hidapi/ios/hid.m

@@ -36,7 +36,9 @@ typedef uint64_t uint64;
 // TODO: create CBUUID's in __attribute__((constructor)) rather than doing [CBUUID UUIDWithString:...] everywhere
 
 #pragma pack(push,1)
-struct bluetoothSegment {
+
+typedef struct
+{
 	uint8_t		segmentHeader;
 	uint8_t		featureReportMessageID;
 	uint8_t		length;
@@ -47,11 +49,9 @@ struct bluetoothSegment {
 		uint64_t	ulPayload;
 		uint8_t		ucPayload[15];
 	};
-	
-	size_t size() { return length + 3; }
-};
+} bluetoothSegment;
 
-struct hidFeatureReport {
+typedef struct {
 	uint8_t		id;
 	union {
 		bluetoothSegment segment;
@@ -68,71 +68,83 @@ struct hidFeatureReport {
 			};
 		};
 	};
-};
+} hidFeatureReport;
+
 #pragma pack(pop)
 
-template <typename T, size_t cbElem, size_t nElem>
-struct RingBuffer {
+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[ ( nElem * cbElem ) ];
+	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 );
+}
 	
-	RingBuffer() { _first = -1; _last = 0; pthread_mutex_init( &accessLock, 0 ); }
-	
-	bool write( const T *src )
-	{
-		pthread_mutex_lock( &accessLock );
-		memcpy( &_data[ _last ], src, cbElem );
-		if ( _first == -1 )
-		{
-			_first = _last;
-		}
-		_last = ( _last + cbElem ) % (nElem * cbElem);
-		if ( _last == _first )
-		{
-			_first = ( _first + cbElem ) % (nElem * cbElem);
-			pthread_mutex_unlock( &accessLock );
-			return false;
-		}
-		pthread_mutex_unlock( &accessLock );
-		return true;
-	}
-	
-	bool read( T *dst )
-	{
-		pthread_mutex_lock( &accessLock );
-		if ( _first == -1 )
-		{
-			pthread_mutex_unlock( &accessLock );
-			return false;
-		}
-		memcpy( dst, &_data[ _first ], cbElem );
-		_first = ( _first + cbElem ) % (nElem * cbElem);
-		if ( _first == _last )
-		{
-			_first = -1;
-		}
-		pthread_mutex_unlock( &accessLock );
-		return true;
-	}
-	
-};
+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
 
-enum BLEDeviceWaitState
+typedef enum
 {
-	None,
-	Waiting,
-	Complete,
-	Error
-};
+	BLEDeviceWaitState_None,
+	BLEDeviceWaitState_Waiting,
+	BLEDeviceWaitState_Complete,
+	BLEDeviceWaitState_Error
+} BLEDeviceWaitState;
 
 @interface HIDBLEDevice : NSObject <CBPeripheralDelegate>
 {
-	RingBuffer<uint8_t, 19, 4096> _inputReports;
-	uint8_t		_featureReport[20];
+	RingBuffer _inputReports;
+	uint8_t	_featureReport[20];
 	BLEDeviceWaitState	_waitStateForReadFeatureReport;
 	BLEDeviceWaitState	_waitStateForWriteFeatureReport;
 }
@@ -419,6 +431,7 @@ static void process_pending_events()
 {
 	if ( self = [super init] )
 	{
+        RingBuffer_init( &_inputReports );
 		self.bleSteamController = nil;
 		self.bleCharacteristicInput = nil;
 		self.bleCharacteristicReport = nil;
@@ -432,6 +445,7 @@ static void process_pending_events()
 {
 	if ( self = [super init] )
 	{
+        RingBuffer_init( &_inputReports );
 		_connected = NO;
 		_ready = NO;
 		self.bleSteamController = peripheral;
@@ -460,7 +474,7 @@ static void process_pending_events()
 
 - (size_t)read_input_report:(uint8_t *)dst
 {
-	if ( _inputReports.read( dst+1 ) )
+	if ( RingBuffer_read( &_inputReports, dst+1 ) )
 	{
 		*dst = 0x03;
 		return 20;
@@ -479,14 +493,14 @@ static void process_pending_events()
 #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]", report->segment.size(),
+	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)report->segment.size();
+	int sendSize = (int)GetBluetoothSegmentSize( &report->segment );
 	if ( sendSize > 20 )
 		sendSize = 20;
 
@@ -501,43 +515,43 @@ static void process_pending_events()
 #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;
+	_waitStateForWriteFeatureReport = BLEDeviceWaitState_Waiting;
 	[_bleSteamController writeValue:[NSData dataWithBytes:&report->segment length:sendSize
 									 ] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse];
 	
-	while ( _waitStateForWriteFeatureReport == BLEDeviceWaitState::Waiting )
+	while ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Waiting )
 	{
 		process_pending_events();
 	}
 	
-	if ( _waitStateForWriteFeatureReport == BLEDeviceWaitState::Error )
+	if ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Error )
 	{
-		_waitStateForWriteFeatureReport = BLEDeviceWaitState::None;
+		_waitStateForWriteFeatureReport = BLEDeviceWaitState_None;
 		return -1;
 	}
 	
-	_waitStateForWriteFeatureReport = BLEDeviceWaitState::None;
+	_waitStateForWriteFeatureReport = BLEDeviceWaitState_None;
 	return 19;
 #endif
 }
 
 - (int)get_feature_report:(uint8_t)feature into:(uint8_t *)buffer
 {
-	_waitStateForReadFeatureReport = BLEDeviceWaitState::Waiting;
+	_waitStateForReadFeatureReport = BLEDeviceWaitState_Waiting;
 	[_bleSteamController readValueForCharacteristic:_bleCharacteristicReport];
 	
-	while ( _waitStateForReadFeatureReport == BLEDeviceWaitState::Waiting )
+	while ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Waiting )
 		process_pending_events();
 	
-	if ( _waitStateForReadFeatureReport == BLEDeviceWaitState::Error )
+	if ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Error )
 	{
-		_waitStateForReadFeatureReport = BLEDeviceWaitState::None;
+		_waitStateForReadFeatureReport = BLEDeviceWaitState_None;
 		return -1;
 	}
 	
 	memcpy( buffer, _featureReport, sizeof(_featureReport) );
 	
-	_waitStateForReadFeatureReport = BLEDeviceWaitState::None;
+	_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]",
@@ -617,7 +631,7 @@ static void process_pending_events()
 		{
 			NSLog( @"HIDBLE: incoming data is %lu bytes should be exactly 19", (unsigned long)data.length );
 		}
-		if ( !_inputReports.write( (const uint8_t *)data.bytes ) )
+		if ( !RingBuffer_write( &_inputReports, (const uint8_t *)data.bytes ) )
 		{
 			uint64_t ticksNow = mach_approximate_time();
 			if ( ticksNow - s_ticksLastOverflowReport > (5ull * NSEC_PER_SEC / 10) )
@@ -634,7 +648,7 @@ static void process_pending_events()
 		if ( error != nil )
 		{
 			NSLog( @"HIDBLE: get_feature_report error: %@", error );
-			_waitStateForReadFeatureReport = BLEDeviceWaitState::Error;
+			_waitStateForReadFeatureReport = BLEDeviceWaitState_Error;
 		}
 		else
 		{
@@ -644,7 +658,7 @@ static void process_pending_events()
 				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;
+			_waitStateForReadFeatureReport = BLEDeviceWaitState_Complete;
 		}
 	}
 }
@@ -656,11 +670,11 @@ static void process_pending_events()
 		if ( error != nil )
 		{
 			NSLog( @"HIDBLE: write_feature_report error: %@", error );
-			_waitStateForWriteFeatureReport = BLEDeviceWaitState::Error;
+			_waitStateForWriteFeatureReport = BLEDeviceWaitState_Error;
 		}
 		else
 		{
-			_waitStateForWriteFeatureReport = BLEDeviceWaitState::Complete;
+			_waitStateForWriteFeatureReport = BLEDeviceWaitState_Complete;
 		}
 	}
 }
@@ -676,7 +690,7 @@ static void process_pending_events()
 #pragma mark hid_api implementation
 
 struct hid_device_ {
-	HIDBLEDevice *device_handle;
+	void *device_handle;
 	int blocking;
 	hid_device *next;
 };
@@ -721,7 +735,7 @@ hid_device * HID_API_EXPORT hid_open_path( const char *path, int bExclusive /* =
 		{
 			result = (hid_device *)malloc( sizeof( hid_device ) );
 			memset( result, 0, sizeof( hid_device ) );
-			result->device_handle = device;
+			result->device_handle = (void*)CFBridgingRetain( device );
 			result->blocking = NO;
 			// enable reporting input events on the characteristic
 			[device.bleSteamController setNotifyValue:YES forCharacteristic:device.bleCharacteristicInput];
@@ -783,8 +797,8 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 				}
 				continue;
 			}
-			hid_device_info *device_info = (hid_device_info *)malloc( sizeof(hid_device_info) );
-			memset( device_info, 0, sizeof(hid_device_info) );
+			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 );
@@ -820,17 +834,21 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s
 
 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
 {
-	if ( !dev->device_handle.connected )
+    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
+
+	if ( !device_handle.connected )
 		return -1;
 
-	return [dev->device_handle send_report:data length:length];
+	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 ( dev->device_handle.connected ) {
-		[dev->device_handle.bleSteamController setNotifyValue:NO forCharacteristic:dev->device_handle.bleCharacteristicInput];
+	if ( device_handle.connected ) {
+		[device_handle.bleSteamController setNotifyValue:NO forCharacteristic:device_handle.bleCharacteristicInput];
 	}
 
 	free( dev );
@@ -838,25 +856,31 @@ void HID_API_EXPORT hid_close(hid_device *dev)
 
 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
 {
-	if ( !dev->device_handle.connected )
+    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
+
+	if ( !device_handle.connected )
 		return -1;
 
-	return [dev->device_handle send_feature_report:(hidFeatureReport *)(void *)data];
+	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)
 {
-	if ( !dev->device_handle.connected )
+    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
+
+	if ( !device_handle.connected )
 		return -1;
 
-	size_t written = [dev->device_handle get_feature_report:data[0] into:data];
+	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)
 {
-	if ( !dev->device_handle.connected )
+    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
+
+	if ( !device_handle.connected )
 		return -1;
 
 	return hid_read_timeout(dev, data, length, 0);
@@ -864,14 +888,16 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
 
 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 {
-	if ( !dev->device_handle.connected )
+    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)[dev->device_handle read_input_report:data];
+	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],