Improve PWM quality, fix a crash

This commit is contained in:
Lior Halphon 2020-05-01 18:08:44 +03:00
parent 5a56c3b882
commit 4bf252800e
4 changed files with 40 additions and 28 deletions

View File

@ -5,6 +5,8 @@
#import "JOYEmulatedButton.h" #import "JOYEmulatedButton.h"
#include <IOKit/hid/IOHIDLib.h> #include <IOKit/hid/IOHIDLib.h>
#define PWM_RESOLUTION 16
static NSString const *JOYAxisGroups = @"JOYAxisGroups"; static NSString const *JOYAxisGroups = @"JOYAxisGroups";
static NSString const *JOYReportIDFilters = @"JOYReportIDFilters"; static NSString const *JOYReportIDFilters = @"JOYReportIDFilters";
static NSString const *JOYButtonUsageMapping = @"JOYButtonUsageMapping"; static NSString const *JOYButtonUsageMapping = @"JOYButtonUsageMapping";
@ -130,7 +132,7 @@ typedef struct __attribute__((packed)) {
_physicallyConnected = true; _physicallyConnected = true;
_logicallyConnected = true; _logicallyConnected = true;
_device = device; _device = (IOHIDDeviceRef)CFRetain(device);
_serialSuffix = suffix; _serialSuffix = suffix;
IOHIDDeviceRegisterInputValueCallback(device, HIDInput, (void *)self); IOHIDDeviceRegisterInputValueCallback(device, HIDInput, (void *)self);
@ -603,11 +605,17 @@ typedef struct __attribute__((packed)) {
- (void)pwmThread - (void)pwmThread
{ {
while (_rumblePWMRatio != 0) { /* TODO: This does not handle correctly the case of having a multi-port controller where more than one controller
[_rumbleElement setValue:1]; uses rumble. */
[NSThread sleepForTimeInterval:_rumblePWMRatio / 10]; unsigned rumbleCounter = 0;
[_rumbleElement setValue:0]; while (self.connected) {
[NSThread sleepForTimeInterval:(1 - _rumblePWMRatio) / 10]; if ([_rumbleElement setValue:rumbleCounter < round(_rumblePWMRatio * PWM_RESOLUTION)]) {
break;
}
rumbleCounter += round(_rumblePWMRatio * PWM_RESOLUTION);
if (rumbleCounter >= PWM_RESOLUTION) {
rumbleCounter -= PWM_RESOLUTION;
}
} }
[_rumblePWMThreadLock lock]; [_rumblePWMThreadLock lock];
_rumblePWMThreadRunning = false; _rumblePWMThreadRunning = false;
@ -659,6 +667,7 @@ typedef struct __attribute__((packed)) {
else { else {
if (_rumbleElement.max == 1 && _rumbleElement.min == 0) { if (_rumbleElement.max == 1 && _rumbleElement.min == 0) {
[_rumblePWMThreadLock lock]; [_rumblePWMThreadLock lock];
_rumblePWMRatio = amp;
if (!_rumblePWMThreadRunning) { // PWM thread not running, start it. if (!_rumblePWMThreadRunning) { // PWM thread not running, start it.
if (amp != 0) { if (amp != 0) {
_rumblePWMRatio = amp; _rumblePWMRatio = amp;
@ -666,14 +675,6 @@ typedef struct __attribute__((packed)) {
[self performSelectorInBackground:@selector(pwmThread) withObject:nil]; [self performSelectorInBackground:@selector(pwmThread) withObject:nil];
} }
} }
else {
if (amp == 0) { // Thread is running, signal it to stop
_rumblePWMRatio = 0;
}
else {
_rumblePWMRatio = amp;
}
}
[_rumblePWMThreadLock unlock]; [_rumblePWMThreadLock unlock];
} }
else { else {
@ -771,4 +772,12 @@ typedef struct __attribute__((packed)) {
IOHIDManagerRegisterDeviceRemovalCallback(manager, HIDDeviceRemoved, NULL); IOHIDManagerRegisterDeviceRemovalCallback(manager, HIDDeviceRemoved, NULL);
IOHIDManagerScheduleWithRunLoop(manager, [runloop getCFRunLoop], kCFRunLoopDefaultMode); IOHIDManagerScheduleWithRunLoop(manager, [runloop getCFRunLoop], kCFRunLoopDefaultMode);
} }
- (void)dealloc
{
if (_device) {
CFRelease(_device);
_device = NULL;
}
}
@end @end

View File

@ -5,8 +5,8 @@
- (instancetype)initWithElement:(IOHIDElementRef)element; - (instancetype)initWithElement:(IOHIDElementRef)element;
- (int32_t)value; - (int32_t)value;
- (NSData *)dataValue; - (NSData *)dataValue;
- (void)setValue:(uint32_t)value; - (IOReturn)setValue:(uint32_t)value;
- (void)setDataValue:(NSData *)value; - (IOReturn)setDataValue:(NSData *)value;
@property (readonly) uint16_t usage; @property (readonly) uint16_t usage;
@property (readonly) uint16_t usagePage; @property (readonly) uint16_t usagePage;
@property (readonly) uint32_t uniqueID; @property (readonly) uint32_t uniqueID;

View File

@ -81,18 +81,20 @@
return [NSData dataWithBytes:IOHIDValueGetBytePtr(value) length:IOHIDValueGetLength(value)]; return [NSData dataWithBytes:IOHIDValueGetBytePtr(value) length:IOHIDValueGetLength(value)];
} }
- (void)setValue:(uint32_t)value - (IOReturn)setValue:(uint32_t)value
{ {
IOHIDValueRef ivalue = IOHIDValueCreateWithIntegerValue(NULL, (__bridge IOHIDElementRef)_element, 0, value); IOHIDValueRef ivalue = IOHIDValueCreateWithIntegerValue(NULL, (__bridge IOHIDElementRef)_element, 0, value);
IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue); IOReturn ret = IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue);
CFRelease(ivalue); CFRelease(ivalue);
return ret;
} }
- (void)setDataValue:(NSData *)value - (IOReturn)setDataValue:(NSData *)value
{ {
IOHIDValueRef ivalue = IOHIDValueCreateWithBytes(NULL, (__bridge IOHIDElementRef)_element, 0, value.bytes, value.length); IOHIDValueRef ivalue = IOHIDValueCreateWithBytes(NULL, (__bridge IOHIDElementRef)_element, 0, value.bytes, value.length);
IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue); IOReturn ret = IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue);
CFRelease(ivalue); CFRelease(ivalue);
return ret;
} }
/* For use as a dictionary key */ /* For use as a dictionary key */

View File

@ -65,15 +65,15 @@
return ret; return ret;
} }
- (void)setValue: (uint32_t) value - (IOReturn)setValue: (uint32_t) value
{ {
NSMutableData *dataValue = [[_parent dataValue] mutableCopy]; NSMutableData *dataValue = [[_parent dataValue] mutableCopy];
if (!dataValue) return; if (!dataValue) return -1;
if (_size > 32) return; if (_size > 32) return -1;
if (_size + (_offset % 8) > 32) return; if (_size + (_offset % 8) > 32) return -1;
size_t parentLength = dataValue.length; size_t parentLength = dataValue.length;
if (_size > parentLength * 8) return; if (_size > parentLength * 8) return -1;
if (_size + _offset >= parentLength * 8) return; if (_size + _offset >= parentLength * 8) return -1;
uint8_t *bytes = dataValue.mutableBytes; uint8_t *bytes = dataValue.mutableBytes;
uint8_t temp[4] = {0,}; uint8_t temp[4] = {0,};
@ -81,7 +81,7 @@
(*(uint32_t *)temp) &= ~((1 << (_size - 1)) << (_offset % 8)); (*(uint32_t *)temp) &= ~((1 << (_size - 1)) << (_offset % 8));
(*(uint32_t *)temp) |= (value) << (_offset % 8); (*(uint32_t *)temp) |= (value) << (_offset % 8);
memcpy(bytes + _offset / 8, temp, (_offset + _size - 1) / 8 - _offset / 8 + 1); memcpy(bytes + _offset / 8, temp, (_offset + _size - 1) / 8 - _offset / 8 + 1);
[_parent setDataValue:dataValue]; return [_parent setDataValue:dataValue];
} }
- (NSData *)dataValue - (NSData *)dataValue
@ -90,9 +90,10 @@
return nil; return nil;
} }
- (void)setDataValue:(NSData *)data - (IOReturn)setDataValue:(NSData *)data
{ {
[self doesNotRecognizeSelector:_cmd]; [self doesNotRecognizeSelector:_cmd];
return -1;
} }