Improve PWM quality, fix a crash
This commit is contained in:
parent
5a56c3b882
commit
4bf252800e
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user