Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C Library that can be incorporated into other apps #15

Open
krackers opened this issue Jul 12, 2022 · 1 comment
Open

C Library that can be incorporated into other apps #15

krackers opened this issue Jul 12, 2022 · 1 comment

Comments

@krackers
Copy link

krackers commented Jul 12, 2022

Thanks for the logic. I wanted to incorporate this as part of another app, so I removed all the CLI parsing parts from the monolithic main function to get something more library like. I think I also made sure to handle iokit free... Maybe this can be useful to someone.

#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>



typedef CFTypeRef IOAVServiceRef;
extern IOAVServiceRef IOAVServiceCreate(CFAllocatorRef allocator);
extern IOAVServiceRef IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service);
extern IOReturn IOAVServiceReadI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t offset, void* outputBuffer, uint32_t outputBufferSize);
extern IOReturn IOAVServiceWriteI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t dataAddress, void* inputBuffer, uint32_t inputBufferSize);

#define LUMINANCE 0x10
#define CONTRAST 0x12
#define VOLUME 0x62
#define MUTE 0x8D
#define INPUT 0x60
#define STANDBY 0xD6
#define RED 0x16 // VCP Code - Video Gain (Drive): Red
#define GREEN 0x18 // VCP Code - Video Gain (Drive): Green
#define BLUE 0x1A // VCP Code - Video Gain (Drive): Blue

#define MUTE_ON 1
#define MUTE_OFF 2

#define DDC_WAIT 10000 // depending on display this must be set to as high as 50000
#define DDC_ITERATIONS 2 // depending on display this must be set higher

void free_ioobject(io_object_t *value) { if (*value != NULL) {IOObjectRelease(*value);} }
void free_cftype(CFTypeRef *value) { if (*value != NULL) {CFRelease(*value);} }

NSArray* getDisplayList() {
    NSMutableArray *ret = [NSMutableArray array];

    __attribute__((cleanup(free_ioobject))) io_iterator_t iter;
    __attribute__((cleanup(free_ioobject))) io_service_t service = 0;
    __attribute__((cleanup(free_ioobject))) io_registry_entry_t root = IORegistryGetRootEntry(kIOMainPortDefault);
    kern_return_t kerr = IORegistryEntryCreateIterator(root, "IOService", kIORegistryIterateRecursively, &iter);
    
    if (kerr != KERN_SUCCESS) {
        return NULL;
    }

    int i=1;
    
    while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
        io_name_t name;
        IORegistryEntryGetName(service, name);
        if ( !strcmp(name, "AppleCLCD2") ) {
            
            NSString *edidUUID =  (__bridge_transfer NSString*) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("EDID UUID"), kCFAllocatorDefault, kIORegistryIterateRecursively);
            
            if ( !(edidUUID == NULL) ) {
                CFDictionaryRef displayAttrs = (CFDictionaryRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("DisplayAttributes"), kCFAllocatorDefault, kIORegistryIterateRecursively);
                
                if (displayAttrs ) {
                    NSDictionary* displayAttrsNS = (__bridge NSDictionary*) displayAttrs;
                    NSDictionary* productAttrs = [displayAttrsNS objectForKey:@"ProductAttributes"];
                    if (productAttrs) {
                        [ret addObject: [NSString stringWithFormat:@"%d %@ %@", i, [productAttrs objectForKey:@"ProductName"], edidUUID]];
                    }
                    CFRelease(displayAttrs);
                }
                i++;
            }
        }
    }
    return ret;
}



IOAVServiceRef getAvService(int display) {
    
    if (display == 0) {
        return IOAVServiceCreate(kCFAllocatorDefault);
    }
    
    IOAVServiceRef ret;
    __attribute__((cleanup(free_ioobject))) io_iterator_t iter;
    __attribute__((cleanup(free_ioobject))) io_service_t service = 0;
    __attribute__((cleanup(free_ioobject))) io_registry_entry_t root = IORegistryGetRootEntry(kIOMainPortDefault);
    kern_return_t kerr = IORegistryEntryCreateIterator(root, "IOService", kIORegistryIterateRecursively, &iter);
    
    if (kerr != KERN_SUCCESS) {
        return NULL;
    }
    
    int i=1;
    bool noMatch = true;
    
    while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
        io_name_t name;
        IORegistryEntryGetName(service, name);
        if ( !strcmp(name, "AppleCLCD2") ) {
            
            CFStringRef edidUUID = (CFStringRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("EDID UUID"), kCFAllocatorDefault, kIORegistryIterateRecursively);
            
            if ( !(edidUUID == NULL) ) {
                if ( display == i ) {
                    while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
                        io_name_t name;
                        IORegistryEntryGetName(service, name);
                        if ( !strcmp(name, "DCPAVServiceProxy") ) {
                            
                            ret = IOAVServiceCreateWithService(kCFAllocatorDefault, service);
                            CFStringRef location = (CFStringRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("Location"), kCFAllocatorDefault, kIORegistryIterateRecursively);
                            
                            if ( !( location == NULL || !ret || CFStringCompare(CFSTR("External"), location, 0) ) ) {
                                noMatch = false;
                                break;
                            }
                            CFRelease(location);
                        }
                    }
                }
                
                i++;
                CFRelease(edidUUID);
                
            }
        }
    }
     if ( noMatch ) {
        printf("The specified display does not exist. Use 'display list' to list displays and use it's number (1, 2...) to specify display!\n");
        return NULL;
    }
    return ret;
}

IOReturn readDDC(IOAVServiceRef avService, UInt8 action, signed char *curValue, signed char *maxValue) {
    // Get ready for DDC operations
    
    UInt8 data[256];
    memset(data, 0, sizeof(data));
    data[2] = action;

    *curValue=-1;
    *maxValue=-1;
    
    data[0] = 0x82;
    data[1] = 0x01;
    data[3] = 0x6e ^ data[0] ^ data[1] ^ data[2] ^ data[3];
    
    IOReturn err;
    for (int i = 0; i < DDC_ITERATIONS; ++i) {
        
        usleep(DDC_WAIT);
        err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 4);
        
        if (err) {
            NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
            return err;
        }
        
    }
    
    char i2cBytes[12];
    memset(i2cBytes, 0, sizeof(i2cBytes));
    
    usleep(DDC_WAIT);
    err = IOAVServiceReadI2C(avService, 0x37, 0x51, i2cBytes, 12);
    
    if (err) {
        NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
        return err;
    }
    
    NSData *readData = [NSData dataWithBytes:(const void *)i2cBytes length:(NSUInteger)11];
    
    NSRange maxValueRange = {7, 1};
    NSRange currentValueRange = {9, 1};
    
    [[readData subdataWithRange:maxValueRange] getBytes:maxValue length:sizeof(1)];
    [[readData subdataWithRange:currentValueRange] getBytes:curValue length:sizeof(1)];
    return 0;
}

IOReturn setDDC( IOAVServiceRef avService, UInt8 action, int setValue) {
    UInt8 data[256];

    
    data[0] = 0x84;
    data[1] = 0x03;
    data[2] = action;
    data[3] = (setValue) >> 8;
    data[4] = setValue & 255;
    data[5] = 0x6E ^ 0x51 ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4];
    
    IOReturn err;
    for (int i = 0; i <= DDC_ITERATIONS; i++) {
        
        usleep(DDC_WAIT);
        err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 6);
        
        if (err) {
            NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
            return err;
            
        }
        
    }
    return 0;
}

int main(int argc, char** argv) {
    NSLog(@"%@", getDisplayList());
    IOAVServiceRef ref = getAvService(1);
    signed char current = 0;
    signed char max = 0;
//  readDDC(ref, VOLUME, &current, &max);
//  printf("Current %d %d\n", current, max);
//  setDDC(ref, VOLUME, 10);
    readDDC(ref, VOLUME, &current, &max);
    printf("Current %d %d\n", current, max);
    CFRelease(ref);
}
@waydabber
Copy link
Owner

Great, thank you! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants