HIDRemoteDeviceServer.m [plain text]
//
// HIDRemoeSimpleServer.m
// RemoteHID
//
// Created by yg on 1/14/18.
//
#import <Foundation/Foundation.h>
#import "HIDRemoteDeviceServer.h"
#import "HIDRemoteSimpleProtocol.h"
//#import <HID/HID.h>
#import "RemoteHIDPrivate.h"
#import <IOKit/IOKitLib.h>
@interface HIDRemoteDevice ()
@property dispatch_semaphore_t semaphore;
@property NSData * lastGetReport;
@property BOOL waitForReport;
@end
@implementation HIDRemoteDevice
-(nullable instancetype)initWithProperties:(nonnull NSDictionary *)properties
{
self = [super initWithProperties:properties];
if (!self) {
return self;
}
self.semaphore = dispatch_semaphore_create(0);
return self;
}
-(IOReturn) getReportHandler:(__unused IOHIDReportType) type
reportID:(__unused uint8_t) reportID
report:( uint8_t * _Nonnull ) report
reportLength:(NSUInteger) reportLength
{
IOReturn status = kIOReturnAborted;
if (self.waitForReport) {
self.lastGetReport = [NSData dataWithBytes:report length:reportLength];
dispatch_semaphore_signal(self.semaphore);
status = kIOReturnSuccess;
}
return status;
}
- (NSString *)description {
uint64_t serviceID = 0;
IORegistryEntryGetRegistryEntryID(self.service, &serviceID);
return [NSString stringWithFormat:@"<HIDRemoteHIDUserDevice:}
@end
@interface HIDRemoteDeviceServer ()
@end
@implementation HIDRemoteDeviceServer
-(nullable instancetype) initWithQueue:(dispatch_queue_t) queue
{
self = [super init];
if (!self) {
return self;
}
self->_queue = queue;
self->_devices = [[NSMutableDictionary alloc] init];
return self;
}
-(BOOL) connectEndpoint:(__nonnull id) endpoint
{
NSMutableDictionary * endpointDevices = [[NSMutableDictionary alloc] init];
self.devices [endpoint] = endpointDevices;
return TRUE;
}
-(void) disconnectEndpoint:(__nonnull id) endpoint
{
NSMutableDictionary * endpointDevices = self.devices [endpoint];
[endpointDevices enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key __unused, id _Nonnull obj, BOOL * _Nonnull stop __unused) {
HIDUserDevice * device = (HIDUserDevice *)obj;
[device cancel];
}];
self.devices [endpoint] = nil;
os_log_debug (RemoteHIDLog (), "DisconnectEP devices:}
-(BOOL) createRemoteDevice:(__nonnull id) endpoint deviceID:(uint64_t) deviceID property:( NSMutableDictionary * __nonnull) property
{
HIDRemoteDevice * device = [[HIDRemoteDevice alloc] initWithProperties:property];
if (!device) {
os_log_error (RemoteHIDLog (), "HIDUserDevice failed, property: return NO;
}
os_log (RemoteHIDLog (), "Create device:
__weak HIDRemoteDevice *weakDevice = device;
[device setSetReportHandler:^IOReturn(IOHIDReportType type, uint32_t reportID, uint8_t * _Nullable report, NSUInteger reportLength) {
__strong HIDRemoteDevice * strongDevice = weakDevice;
if (!strongDevice) {
return kIOReturnNoDevice;
}
IOReturn status = [self remoteDeviceSetReport:strongDevice type:type reportID:reportID report:report reportLength:reportLength];
return status;
}];
[device setGetReportHandler:^IOReturn(IOHIDReportType type, uint32_t reportID, uint8_t * _Nullable report, NSUInteger * reportLength) {
__strong HIDRemoteDevice * strongDevice = weakDevice;
if (!strongDevice) {
return kIOReturnNoDevice;
}
os_log_debug (RemoteHIDLog (), "[device:
NSData * reportData;
long semaStatus;
IOReturn status;
strongDevice.lastGetReport = nil;
strongDevice.waitForReport = YES;
status = [self remoteDeviceGetReport:strongDevice type:type reportID:reportID report:report reportLength:reportLength];
require_action_quiet(status == kIOReturnSuccess, exit, os_log_error (RemoteHIDLog (), "[device:
semaStatus = dispatch_semaphore_wait(strongDevice.semaphore, dispatch_time(DISPATCH_TIME_NOW, kRemoteHIDDeviceTimeout * NSEC_PER_SEC));
require_action_quiet(semaStatus == 0, exit, status = kIOReturnTimeout; os_log_error (RemoteHIDLog (), "[device:
reportData = strongDevice.lastGetReport;
require_action_quiet(reportData, exit, status = kIOReturnError; os_log_error (RemoteHIDLog (), "[device:
memcpy(report, ((NSData *)reportData).bytes, ((NSData *)reportData).length);
*reportLength = ((NSData *)reportData).length;
exit:
strongDevice.waitForReport = NO;
return status;
}];
[device setDispatchQueue:self.queue];
device.endpoint = endpoint;
device.deviceID = deviceID;
[device activate];
NSMutableDictionary * endpointDevices = self.devices [endpoint];
HIDRemoteDevice * tmpDevice = endpointDevices [@(deviceID)];
if (tmpDevice) {
[tmpDevice cancel];
}
endpointDevices [@(deviceID)] = device;
return YES;
}
-(IOReturn) remoteDeviceSetReport:(__unused HIDRemoteDevice *) device type:(__unused IOHIDReportType) type reportID:(__unused uint8_t) reportID report:(__unused uint8_t *) report reportLength:(__unused NSUInteger) reportLength
{
return kIOReturnUnsupported;
}
-(IOReturn) remoteDeviceGetReport:(__unused HIDRemoteDevice *) device type:(__unused IOHIDReportType) type reportID:(__unused uint8_t) reportID report:(__unused uint8_t *) report reportLength:(__unused NSUInteger *) reportLength
{
return kIOReturnUnsupported;
}
-(void) removeRemoteDevice:(__nonnull id) endpoint deviceID:(uint64_t) deviceID
{
NSMutableDictionary * endpointDevices = self.devices [endpoint];
HIDUserDevice * device = endpointDevices [@(deviceID)];
if (device) {
os_log (RemoteHIDLog (), "Remove device: [device cancel];
} else {
os_log_error (RemoteHIDLog (), "Device: }
endpointDevices [@(deviceID)] = nil;
os_log_debug (RemoteHIDLog (), "Remaining devices:
}
-(BOOL) remoteDeviceReportHandler:(__nonnull id) endpoint packet:(HIDDeviceReport *) packet
{
if (packet->header.length <= sizeof(HIDDeviceReport)) {
os_log_error (RemoteHIDLog (), "Invalid report size: return NO;
}
NSMutableDictionary * devices = self.devices[endpoint];
HIDUserDevice * device = devices[@(packet->header.deviceID)];
if (!device) {
os_log_error (RemoteHIDLog (), "HID Device for deviceID: return NO;
}
IOReturn status = [device handleReport:&(packet->data[0]) reportLength:(packet->header.length - sizeof(HIDDeviceReport))];
if (status) {
os_log_error (RemoteHIDLog (), "handleReport: return NO;
}
return YES;
}
-(BOOL) remoteDeviceGetReportHandler:(__nonnull id) endpoint packet:(HIDDeviceReport *) packet
{
if (packet->header.length <= sizeof(HIDDeviceReport)) {
os_log_error (RemoteHIDLog (), "Invalid report size: return NO;
}
NSMutableDictionary * devices = self.devices[endpoint];
HIDRemoteDevice * device = devices[@(packet->header.deviceID)];
if (!device) {
os_log_error (RemoteHIDLog (), "HID Device for deviceID: return NO;
}
return [device getReportHandler:packet->reportType reportID:packet->data[0] report:packet->data reportLength:(packet->header.length - sizeof(HIDDeviceReport))] == kIOReturnSuccess;
}
-(void) remoteDeviceConnectHandler:(__nonnull id) endpoint packet:(HIDDeviceControl *) packet
{
NSData * deviceDescriptionData = [NSData dataWithBytes:&packet->data length:packet->header.length];
NSError * err = nil;
id deviceDescription = [NSPropertyListSerialization propertyListWithData:deviceDescriptionData options:NSPropertyListMutableContainersAndLeaves format:NULL error:&err];
if (err) {
os_log_error (RemoteHIDLog (), "HIDPacketDevice de-serialization error: os_log_debug (RemoteHIDLog (), "HIDPacketDevice config data: return;
}
[self createRemoteDevice: endpoint deviceID:packet->header.deviceID property:deviceDescription];
}
-(void) endpointMessageHandler:(__nonnull id) endpoint data:(uint8_t*) data size:(size_t) dataSize
{
if (!_devices[endpoint]) {
os_log_info (RemoteHIDLog (), "Unknown accesory: return;
}
require_quiet(dataSize >= (sizeof(HIDTransportHeader) + sizeof(HIDDeviceHeader)), error);
HIDDeviceHeader * packet = (HIDDeviceHeader *) (data + sizeof(HIDTransportHeader));
do {
require_quiet((((uint8_t *)packet + sizeof(HIDDeviceHeader)) <= (data + dataSize)) &&
(packet->length >= sizeof (HIDDeviceHeader)) &&
(((uint8_t *)packet + packet->length) <= (data + dataSize)) , error);
[self endpointPacketHandler: endpoint packet:packet];
packet = (HIDDeviceHeader *)((uint8_t *)packet + packet->length);
} while ((uint8_t *)packet < (data + dataSize));
return;
error:
os_log_error (RemoteHIDLog (), "Invalid message length:}
-(void) endpointPacketHandler:(__nonnull id) endpoint packet:(HIDDeviceHeader *) packet
{
os_log_debug (RemoteHIDLog (), "endpointPacketHandler deviceid:
switch (packet->packetType) {
case HIDPacketTypeDeviceConnect:
[self remoteDeviceConnectHandler:endpoint packet:(HIDDeviceControl*) packet];
break;
case HIDPacketTypeDeviceDisconnect:
[self removeRemoteDevice:endpoint deviceID:packet->deviceID];
break;
case HIDPacketTypeHandleReport:
[self remoteDeviceReportHandler:endpoint packet:(HIDDeviceReport *)packet];
break;
case HIDPacketTypeGetReport:
[self remoteDeviceGetReportHandler:endpoint packet:(HIDDeviceReport *)packet];
break;
default:
os_log_error (RemoteHIDLog (), "Unsupported packet type: break;
}
}
-(void) activate
{
}
-(void) cancel
{
}
-(void) disconnectAll
{
[self.devices removeAllObjects];
}
@end