From 72b4ace428c46962d60a1ebd7b21c716635119a0 Mon Sep 17 00:00:00 2001 From: Till Toenshoff Date: Thu, 11 Jan 2024 10:42:52 +0100 Subject: [PATCH] fix: lightguide sent to interface 0x4 endpoint 4 via bulk --- KompleteSynthesia/AppDelegate.m | 51 +++++++++++++++-------------- KompleteSynthesia/HIDController.h | 3 +- KompleteSynthesia/HIDController.m | 47 +++++++++++++++++--------- KompleteSynthesia/USBController.h | 5 ++- KompleteSynthesia/USBController.m | 42 ++++++++++++++++-------- KompleteSynthesia/VideoController.h | 2 +- KompleteSynthesia/VideoController.m | 9 ++--- 7 files changed, 96 insertions(+), 63 deletions(-) diff --git a/KompleteSynthesia/AppDelegate.m b/KompleteSynthesia/AppDelegate.m index 7258024..7520848 100644 --- a/KompleteSynthesia/AppDelegate.m +++ b/KompleteSynthesia/AppDelegate.m @@ -22,6 +22,7 @@ @interface AppDelegate () @property (nonatomic, strong) MIDI2HIDController* midi2hidController; @property (nonatomic, strong) VideoController* videoController; @property (nonatomic, strong) HIDController* hidController; +@property (nonatomic, strong) USBController* usbController; @property (nonatomic, strong) MIDIController* midiController; @property (nonatomic, strong) LogViewController* log; @property (nonatomic, strong) SynthesiaController* synthesia; @@ -163,7 +164,13 @@ - (void)applicationDidFinishInitializingWithSynthesiaRunning { NSError* error = nil; - _hidController = [[HIDController alloc] initWithLogViewController:_log]; + _usbController = [[USBController alloc] initWithLogViewController:_log]; + // Try to open a USB device interface for bulk transfer. + if ([_usbController setupWithError:&error] == NO) { + usbAvailable = NO; + } + + _hidController = [[HIDController alloc] initWithUSBController:_usbController logViewController:_log]; _midiController = [[MIDIController alloc] initWithLogViewController:_log]; @@ -177,36 +184,30 @@ - (void)applicationDidFinishInitializingWithSynthesiaRunning return; } - // We won't need any bulk USB access for MK1 controllers - they have no screens. - if (_hidController.mk == 1) { - usbAvailable = NO; - } - - // FIXME: Actively disable USB bulk transfer on MK3 until further notice... - if (_hidController.mk == 3) { - usbAvailable = NO; - } - NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults registerDefaults:@{kAppDefaultActivateSynthesia : @(YES)}]; _midi2hidController.forwardButtonsToSynthesiaOnly = [userDefaults boolForKey:kAppDefaultActivateSynthesia]; if (usbAvailable == YES) { - _videoController = [[VideoController alloc] initWithLogViewController:_log error:&error]; - if (_videoController == nil) { - [[NSAlert alertWithError:error] runModal]; - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - return; - } - - [userDefaults registerDefaults:@{kAppDefaultMirrorSynthesia : @(YES)}]; - _videoController.mirrorSynthesiaApplicationWindow = [userDefaults boolForKey:kAppDefaultMirrorSynthesia]; - - if (![_videoController reset:&error]) { - [[NSAlert alertWithError:error] runModal]; - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - return; + if (_hidController.mk == 2) { + _videoController = [[VideoController alloc] initWithUSBController:_usbController + logViewController:_log + error:&error]; + if (_videoController == nil) { + [[NSAlert alertWithError:error] runModal]; + [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; + return; + } + + [userDefaults registerDefaults:@{kAppDefaultMirrorSynthesia : @(YES)}]; + _videoController.mirrorSynthesiaApplicationWindow = [userDefaults boolForKey:kAppDefaultMirrorSynthesia]; + + if (![_videoController reset:&error]) { + [[NSAlert alertWithError:error] runModal]; + [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; + return; + } } } diff --git a/KompleteSynthesia/HIDController.h b/KompleteSynthesia/HIDController.h index 0fde9f3..76bd7ee 100644 --- a/KompleteSynthesia/HIDController.h +++ b/KompleteSynthesia/HIDController.h @@ -105,6 +105,7 @@ enum { }; @class LogViewController; +@class USBController; @protocol HIDControllerDelegate - (void)receivedEvent:(const int)event value:(int)value; @@ -123,7 +124,7 @@ enum { + (NSColor*)colorWithKeyState:(const unsigned char)keyState; -- (id)initWithLogViewController:(LogViewController*)lc; +- (id)initWithUSBController:(USBController*)uc logViewController:(LogViewController*)lc; - (BOOL)setupWithError:(NSError**)error; diff --git a/KompleteSynthesia/HIDController.m b/KompleteSynthesia/HIDController.m index 0db08f7..f7bf970 100644 --- a/KompleteSynthesia/HIDController.m +++ b/KompleteSynthesia/HIDController.m @@ -143,9 +143,12 @@ @interface HIDController () @implementation HIDController { LogViewController* log; + USBController* usb; size_t lightGuideUpdateMessageSize; unsigned char* lightGuideUpdateMessage; + NSMutableData* lightGuideStreamMK3; + unsigned char buttonLightingFeedback[kKompleteKontrolButtonsMessageSize]; unsigned char buttonLightingUpdateMessage[kKompleteKontrolButtonsMessageSize]; @@ -178,11 +181,13 @@ + (NSColor*)colorWithKeyState:(const unsigned char)keyState alpha:1.0f]; } -- (id)initWithLogViewController:(LogViewController*)lc +- (id)initWithUSBController:(USBController*)uc logViewController:(LogViewController*)lc; { self = [super init]; if (self) { log = lc; + usb = uc; + lastVolumeKnobValue = INTMAX_C(16); atomic_fetch_and(&swooshActive, 0); swooshQueue = dispatch_queue_create("KompleteSynthesia.SwooshQueue", NULL); @@ -468,21 +473,25 @@ - (IOHIDDeviceRef)detectKeyboardController:(NSError**)error lightGuideUpdateMessageSize = _mk == 3 ? kKompleteKontrolLightGuideMessageSizeMK3 : kKompleteKontrolLightGuideMessageSize; - lightGuideUpdateMessage = calloc(lightGuideUpdateMessageSize, 1); - - switch (_mk) { - case 1: - lightGuideUpdateMessage[0] = kCommandLightGuideUpdateMK1; - break; - case 2: - lightGuideUpdateMessage[0] = kCommandLightGuideUpdateMK2; - break; - case 3: - *(unsigned long*)lightGuideUpdateMessage = lightGuideUpdateMessageSize - 4; - memcpy(lightGuideUpdateMessage + 4, kKompleteKontrolLightGuidePrefixMK3, - sizeof(kKompleteKontrolLightGuidePrefixMK3)); - break; + + lightGuideStreamMK3 = nil; + + if (_mk == 3) { + lightGuideStreamMK3 = [[NSMutableData alloc] initWithCapacity:lightGuideUpdateMessageSize]; + unsigned int length = (unsigned int)lightGuideUpdateMessageSize - 4; + [lightGuideStreamMK3 appendBytes:&length length:sizeof(length)]; + [lightGuideStreamMK3 appendBytes:&kKompleteKontrolLightGuidePrefixMK3 + length:sizeof(kKompleteKontrolLightGuidePrefixMK3)]; + for (int i = 0; i < 128; i++) { + unsigned char entry[] = {0x92, 0x00, 0x00}; + [lightGuideStreamMK3 appendBytes:entry length:sizeof(entry)]; + } + lightGuideUpdateMessage = (unsigned char*)lightGuideStreamMK3.bytes; + } else { + lightGuideUpdateMessage = calloc(lightGuideUpdateMessageSize, 1); + lightGuideUpdateMessage[0] = _mk == 1 ? kCommandLightGuideUpdateMK1 : kCommandLightGuideUpdateMK2; } + // FIXME: This is likely wrong for MK1 devices! buttonLightingUpdateMessage[0] = kCommandButtonLightsUpdate; _deviceName = @@ -588,6 +597,13 @@ - (BOOL)setReport:(const unsigned char*)report length:(size_t)length error:(NSEr - (BOOL)updateLightGuideMap:(NSError**)error { + extern const double kTimeoutDelay; + + if (_mk == 3) { + BOOL ret = [usb bulkWriteData:lightGuideStreamMK3 error:error]; + [usb waitForBulkTransfer:kTimeoutDelay]; + return ret; + } return [self setReport:lightGuideUpdateMessage length:lightGuideUpdateMessageSize error:error]; } @@ -625,6 +641,7 @@ - (void)lightKeysWithColor:(unsigned char)color memset(_keys, color, kKompleteKontrolLightGuideKeyMapSize); break; case 3: + for (unsigned int i = 0; i < 128; i++) { _keys[i * 3 + 0] = kCommandLightGuideKeyCommandMK3; _keys[i * 3 + 1] = i; diff --git a/KompleteSynthesia/USBController.h b/KompleteSynthesia/USBController.h index d798131..245ffe8 100644 --- a/KompleteSynthesia/USBController.h +++ b/KompleteSynthesia/USBController.h @@ -28,6 +28,8 @@ extern const uint32_t kPID_S49MK3; extern const uint32_t kPID_S61MK3; extern const uint32_t kPID_S88MK3; +@class LogViewController; + @interface USBController : NSObject @property (nonatomic, copy) NSString* deviceName; @@ -41,7 +43,8 @@ extern const uint32_t kPID_S88MK3; + (NSString*)descriptionWithIOReturn:(IOReturn)code; -- (id)initWithError:(NSError**)error; +- (id)initWithLogViewController:(LogViewController*)lc; +- (BOOL)setupWithError:(NSError**)error; - (BOOL)bulkWriteData:(NSData*)data error:(NSError**)error; - (BOOL)waitForBulkTransfer:(NSTimeInterval)timeout; - (void)teardown; diff --git a/KompleteSynthesia/USBController.m b/KompleteSynthesia/USBController.m index 3968d15..df83728 100644 --- a/KompleteSynthesia/USBController.m +++ b/KompleteSynthesia/USBController.m @@ -13,6 +13,8 @@ #import #import +#import "LogViewController.h" + /// Detects a Komplete Kontrol S-series USB controller. Supports USB bulk write for transmitting large amounts of data /// as needed for graphics data transfer to the LCD screens. @@ -34,8 +36,12 @@ const uint32_t kPID_S61MK3 = 0x2110; // Confirmed, thanks to @Bounga. const uint32_t kPID_S88MK3 = 0x2120; // FIXME: NO IDEA - THESE ARE PLACEHOLDERS SO FAR -const uint32_t kUSBDeviceInterface = 0x03; // FIXME: Possibly MK2 specific. -const uint32_t kUSBDeviceInterfaceEndpoint = 0x03; // FIXME: Possibly MK2 specific. +// Bulk transfer interface specifications. +const uint32_t kUSBDeviceInterfaceMK2 = 0x03; +const uint32_t kUSBDeviceInterfaceEndpointMK2 = 0x03; + +const uint32_t kUSBDeviceInterfaceMK3 = 0x04; +const uint32_t kUSBDeviceInterfaceEndpointMK3 = 0x04; @implementation USBController { IOUSBDeviceInterface942** device; @@ -43,6 +49,7 @@ @implementation USBController { uint8_t endpointCount; uint8_t endpointAddresses[32]; dispatch_semaphore_t transfers; + LogViewController* log; } + (NSString*)descriptionWithIOReturn:(IOReturn)err @@ -50,25 +57,32 @@ + (NSString*)descriptionWithIOReturn:(IOReturn)err return [NSString stringWithCString:mach_error_string(err) encoding:NSStringEncodingConversionAllowLossy]; } -- (id)initWithError:(NSError**)error +- (id)initWithLogViewController:(LogViewController*)lc { self = [super init]; if (self) { _connected = NO; - _deviceInterfaceEndpoint = kUSBDeviceInterfaceEndpoint; + log = lc; transfers = dispatch_semaphore_create(0); - if ([self detectDevice:error] == NULL) { - return nil; - } - NSLog(@"detected %@ USB device", _deviceName); - if ([self openDevice:error] == NO) { - return nil; - } - NSLog(@"USB controller fully connected - up and running"); } return self; } +- (BOOL)setupWithError:(NSError**)error +{ + _connected = NO; + if ([self detectDevice:error] == NULL) { + return NO; + } + [log logLine:[NSString stringWithFormat:@"detected %@ USB device", _deviceName]]; + + if ([self openDevice:error] == NO) { + return NO; + } + NSLog(@"USB controller fully connected - up and running"); + return YES; +} + - (void)dealloc { if (interface != NULL) { @@ -430,7 +444,9 @@ - (BOOL)openDevice:(NSError**)error return NO; } - ret = [self openDeviceInterface:kUSBDeviceInterface]; + _deviceInterfaceEndpoint = _mk == 2 ? kUSBDeviceInterfaceEndpointMK2 : kUSBDeviceInterfaceEndpointMK3; + + ret = [self openDeviceInterface:_mk == 2 ? kUSBDeviceInterfaceMK2 : kUSBDeviceInterfaceMK3]; if (ret != kIOReturnSuccess) { if (error) { NSDictionary* userInfo = @{ diff --git a/KompleteSynthesia/VideoController.h b/KompleteSynthesia/VideoController.h index 156d4f2..26b6043 100644 --- a/KompleteSynthesia/VideoController.h +++ b/KompleteSynthesia/VideoController.h @@ -29,7 +29,7 @@ typedef struct { @property (nonatomic, strong) NSTextField* volumeValue; -- (id)initWithLogViewController:(LogViewController*)lc error:(NSError**)error; +- (id)initWithUSBController:(USBController*)uc logViewController:(LogViewController*)lc error:(NSError**)error; - (BOOL)reset:(NSError**)error; - (void)teardown; - (void)showOSD; diff --git a/KompleteSynthesia/VideoController.m b/KompleteSynthesia/VideoController.m index 4b7b780..74ec4db 100644 --- a/KompleteSynthesia/VideoController.m +++ b/KompleteSynthesia/VideoController.m @@ -53,7 +53,7 @@ @implementation VideoController { BOOL showValue; } -- (id)initWithLogViewController:(LogViewController*)lc error:(NSError**)error +- (id)initWithUSBController:(USBController*)uc logViewController:(LogViewController*)lc error:(NSError**)error { self = [super init]; if (self) { @@ -69,12 +69,7 @@ - (id)initWithLogViewController:(LogViewController*)lc error:(NSError**)error imageConversionScaleBuffer = NULL; log = lc; - - usb = [[USBController alloc] initWithError:error]; - if (usb == nil) { - return nil; - } - [log logLine:[NSString stringWithFormat:@"detected %@ USB device", usb.deviceName]]; + usb = uc; if (usb.mk > 1) { _screenCount = usb.mk == 2 ? 2 : 1;