K8055 / VM110 driver for apple

Hi

Is ther any driver that works fore Mac OSX 10.6 ??
Is it possible to send data from the Terminal to the 8055, on mac osx ??

Hope someone used it on MacOSX…

Thanks
Michael

Hi Michael

I appreciate that this is an old thread.

There is a control panel by Andy Armstrong.

While the version that is online does not compile straight out of the box it can be tweaked in Xcode to run under 10.6 and 10.7.

The main flaw was something to do with
#define K8055ANALOGCOOKIE 0x04 // and 0x05

The program tries to +1 to this in places. I found you need to define two :
#define K8055ANALOGCOOKIE1 0x04
#define K8055ANALOGCOOKIE2 0x05

and then replace K8055ANALOGCOOKIE with K8055ANALOGCOOKIE1
and K8055ANALOGCOOKIE + 1 with K8055ANALOGCOOKIE2

if there’s a way to upload the CP and Xcode source I would but new to the forum (actually just joined to reply to your post) so I don’t know if you can.

The only issue I can see is Andy’s code is depreciative as it does not use the new HIDManager. So while it may work in 10.5, 10.6 and 10.7 it may not by 10.8.

I’ve been looking at rewriting for the new HIDManager API but am new to C/Obj-C and it’s a bit of a hip hill struggle.

Cheers
Steve

By the way I think (not sure) that I only changed the K8055.m file so have a go at downloading Andy’s original (sourceforge.net/projects/k8055mac/) and replacing the text in the K8055.m file with :

/* $Id: K8055.m,v 1.8 2005/09/18 14:41:23 andy Exp $
 *
 * Unless otherwise *explicitly* stated the following text
 * describes the licensed conditions under which the
 * contents of this module release may be distributed:
 *
 * --------------------------------------------------------
 * Redistribution and use in source and binary forms of
 * this module, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain any
 *    existing copyright notice, and this entire permission
 *    notice in its entirety, including the disclaimer of
 *    warranties.
 *
 * 2. Redistributions in binary form must reproduce all
 *    prior and current copyright notices, this list of
 *    conditions, and the following disclaimer in the
 *    documentation and/or other materials provided with
 *    the distribution.
 *
 * 3. The name of any author may not be used to endorse or
 *    promote products derived from this software without
 *    their specific prior written permission.
 *
 * ALTERNATIVELY, this product may be distributed under the
 * terms of the GNU General Public License, in which case
 * the provisions of the GNU GPL are required INSTEAD OF
 * the above restrictions.  (This clause is necessary due
 * to a potential conflict between the GNU GPL and the
 * restrictions contained in a BSD-style copyright.)
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --------------------------------------------------------
 *
 * Copyright Andy Armstrong, andy@hexten.net, 2005
 */

#import "K8055.h"

#import <stdio.h>
#import <unistd.h>
#import <stdlib.h>
#import <ctype.h>
#import <sys/errno.h>
#import <sysexits.h>
#import <mach/mach.h>
#import <mach/mach_error.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDLib.h>
#import <IOKit/hid/IOHIDKeys.h>
// #import <Carbon/Carbon.h>
#import <IOKit/usb/IOUSBLib.h>
#import <CoreFoundation/CFNumber.h>
#import <CoreFoundation/CoreFoundation.h>

#define K8055VENDOR         0x10CF
#define K8055PRODUCT        0x5500

#define K8055INPUTCOOKIE    0x02
#define K8055ANALOGCOOKIE1   0x04        // and 0x05
#define K8055ANALOGCOOKIE2   0x05

#define K8055OUTPUTCOOKIE   0x0A
#define K8055OUTPUTCOOKIES  0x08

#define K8055INPUTBIT0      0x10
#define K8055INPUTBIT1      0x20
#define K8055INPUTBIT2      0x01
#define K8055INPUTBIT3      0x40
#define K8055INPUTBIT4      0x80

static void queueCallback(void *target, IOReturn result, void *ref, void *sender);

@interface K8055 (Private)

+ (io_iterator_t) getIteratorForDevice: (int) device;
+ (io_iterator_t) getIterator;
- (void) syncDeviceOutput;
- (int) translateInput: (int) input;
- (void) gotEvent;
- (int) readRaw: (int) cookie;

@end

@implementation K8055 (Private)

+ (io_iterator_t) getIteratorForDevice: (int) device {
    NSMutableDictionary *matcher        = nil;
    IOReturn            rc;
    io_iterator_t       iter;

    matcher = (NSMutableDictionary *) IOServiceMatching(kIOHIDDeviceKey);
    if (matcher == nil) {
        [NSException raise: NSGenericException 
                    format: @"Can't create matching dictionary"];
    }
    
    [matcher setObject: [NSNumber numberWithInt: K8055VENDOR]
                forKey: (NSString*)CFSTR(kIOHIDVendorIDKey)];
    
    if (device != -1) {
        // If the device is specified add it to the matching dictionary. If
        // no device is specified this will return an iterator that matches
        // all devices with the Velleman vendor id.
        
        if (device < 0 || device >= MAXDEVICE) {
            [NSException raise: NSGenericException 
                        format: @"Illegal device id: %d (0 to %d allowed)",
                                device, MAXDEVICE];
        }
        
        [matcher setObject: [NSNumber numberWithInt: K8055PRODUCT + device]
                    forKey: (NSString*)CFSTR(kIOHIDProductIDKey)];
        
    }

    rc = IOServiceGetMatchingServices(kIOMasterPortDefault, (CFMutableDictionaryRef) matcher, &iter);
    if (rc != kIOReturnSuccess) {
        [NSException raise: NSGenericException 
                    format: @"Failed to get iterator (0x%lx)", (long) rc];
    }
    
    return iter;
}

+ (io_iterator_t) getIterator {
    return [self getIteratorForDevice: -1];
}

- (void) syncDeviceOutput {
    int cmd[4], i;
    IOReturn rc = kIOReturnSuccess;

    cmd[0] = 0x05;
    cmd[1] = output;
    cmd[2] = pwm[0];
    cmd[3] = pwm[1];
    
    for (i = 0; rc == kIOReturnSuccess && i < sizeof(cmd) / sizeof(cmd[0]); i++) {
        IOHIDElementCookie cookie = (IOHIDElementCookie) (i + K8055OUTPUTCOOKIE);
        IOHIDEventStruct ev;
        memset(&ev, 0, sizeof(ev));
        ev.elementCookie = cookie;
        ev.value = cmd[i];
        rc = (*transaction)->setElementValue(transaction, cookie, &ev);
    }
    
    if (rc == kIOReturnSuccess) {
        rc = (*transaction)->commit(transaction, 1000, nil, nil, nil);
    }

    if (rc != kIOReturnSuccess) {
        [NSException raise: NSGenericException 
                    format: @"Transaction failed (0x%08lx)",
            (long) rc];
    }
}

- (int) translateInput: (int) inp {
    return ((inp & K8055INPUTBIT0) ? (1 << 0) : 0) |
           ((inp & K8055INPUTBIT1) ? (1 << 1) : 0) |
           ((inp & K8055INPUTBIT2) ? (1 << 2) : 0) |
           ((inp & K8055INPUTBIT3) ? (1 << 3) : 0) |
           ((inp & K8055INPUTBIT4) ? (1 << 4) : 0);
}

- (void) gotEvent {
	IOHIDEventStruct    event;
    IOReturn            rc          = kIOReturnSuccess;
    AbsoluteTime		zeroTime    = { 0, 0 };
    int                 got         = 0;

    while (rc = (*queue)->getNextEvent(queue, &event, zeroTime, 0), rc == kIOReturnSuccess) {
        int bumped, i;
        got |= 1 << (int) event.elementCookie;
        switch ((int) event.elementCookie) {
            case K8055INPUTCOOKIE:
                bumped = input;
                input = [self translateInput: (int) event.value];
                bumped = (input ^ bumped) & input;
                for (i = 0; i < MAXINPUT; i++) {
                    if (bumped & (1 << i)) {
                        inputCount[i]++;
                    }
                }
                break;
            case K8055ANALOGCOOKIE1:
                analog[0] = (int) event.value;
                break;
            case K8055ANALOGCOOKIE2:
                analog[1] = (int) event.value;
                break;
        }
    }
    
    if (got & (1 << K8055INPUTCOOKIE)) {
        [[NSNotificationCenter defaultCenter]
            postNotificationName: @"InputChanged" object:self];
    }
        
    if (got & (3 << K8055ANALOGCOOKIE1)) {
        [[NSNotificationCenter defaultCenter]
            postNotificationName: @"AnalogChanged" object:self];
    }
        
    eventMask |= got;
}

- (int) readRaw: (int) cookie {
	IOHIDEventStruct    event;
    IOReturn            rc;
    
    rc = (*interface)->getElementValue(interface,
                       (IOHIDElementCookie) cookie, &event);

    if (rc != kIOReturnSuccess) {
        [NSException raise: NSGenericException 
                    format: @"Device read failed (0x%08lx)",
            (long) rc];
    }
    
    return (int) event.value;
}

@end

@implementation K8055

+ (int) findDevices {
    io_iterator_t iter;
    int devices = 0;
    
    iter = [self getIterator];
    if (iter != (int)nil) {
        io_object_t dev;
        while (dev = IOIteratorNext(iter), dev != (int)nil) {
            kern_return_t rc;
            NSMutableDictionary *props;

            rc = IORegistryEntryCreateCFProperties(dev, 
                                                   (CFMutableDictionaryRef *) &props,
                                                   kCFAllocatorDefault, kNilOptions); 
            if (rc != KERN_SUCCESS) {
                [NSException raise: NSGenericException 
                            format: @"Failed to get properties (0x%lx)", (long) rc];
            }
            
            if (props != nil) {
                NSString *prod = [props objectForKey: 
                    (NSString*)CFSTR(kIOHIDProductIDKey)];
                int device = [prod intValue];
                // Check that it's a K8055
                if (device >= K8055PRODUCT && device < K8055PRODUCT + MAXDEVICE) {
                    devices |= (1 << (device - K8055PRODUCT));
                }
                
                CFRelease(props);
            }
        }
        
		IOObjectRelease(iter);
    }
        
    return devices;
}

- (id) initWithDevice: (int) device {
    if ((self = [super init])) {
        IOCFPlugInInterface     **plugIn;
        CFRunLoopSourceRef 		eventSource;
        SInt32                  score       = 0;
        IOReturn                rc;
        HRESULT                 prc;
        io_iterator_t           iter;
        io_object_t             dev;
        int                     i;
        
        static IOHIDElementCookie inputCookies[] = {
            (IOHIDElementCookie) K8055INPUTCOOKIE,
            (IOHIDElementCookie) K8055ANALOGCOOKIE1,
            (IOHIDElementCookie) K8055ANALOGCOOKIE2
        };

        if (device < 0 || device >= MAXDEVICE) {
            [NSException raise: NSGenericException 
                        format: @"Illegal device id: %d (0 to %d allowed)",
                device, MAXDEVICE];
        }
        
        dev = (int)nil;
        iter = [K8055 getIteratorForDevice: device];
        if (iter != (int)nil) {
            dev = IOIteratorNext(iter);
            IOObjectRelease(iter);
        }
        
        if (dev == (int)nil) {
            [NSException raise: NSGenericException 
                        format: @"Device %d unavailable",
                        device];
        }
        
        rc = IOCreatePlugInInterfaceForService(dev,
                                               kIOHIDDeviceUserClientTypeID,
                                               kIOCFPlugInInterfaceID,
                                               &plugIn, &score);
        if (rc != kIOReturnSuccess) {
            [NSException raise: NSGenericException 
                        format: @"Failed to create plugin interface (%lx)",
                        (long) rc];
        }

        prc = (*plugIn)->QueryInterface(plugIn,
                                         CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
                                         (LPVOID) &interface);
        (*plugIn)->Release(plugIn);

        if (prc != S_OK) {
            [NSException raise: NSGenericException 
                        format: @"Failed to query plugin interface (%lx)",
                (long) prc];
        }

        rc = (*interface)->open(interface, 0);
        if (rc != kIOReturnSuccess) {
            (*interface)->Release(interface);
            interface = nil;
            [NSException raise: NSGenericException 
                        format: @"Failed to open interface (%lx)",
                        (long) rc];
        }
        
        // Since we're on a roll create the transaction too.
        transaction = (*interface)->allocOutputTransaction(interface);
        if (transaction == nil) {
            [NSException raise: NSGenericException 
                        format: @"Failed to create transaction"];
        }
        
        rc = (*transaction)->create(transaction);

        for (i = 0; rc == kIOReturnSuccess && i < K8055OUTPUTCOOKIES; i++) {
            IOHIDElementCookie cookie = (IOHIDElementCookie) (i + K8055OUTPUTCOOKIE);
            rc = (*transaction)->addElement(transaction, cookie);
            if (rc == kIOReturnSuccess) {
                IOHIDEventStruct ev;
                memset(&ev, 0, sizeof(ev));
                ev.elementCookie = cookie;
                ev.value = 0;
                rc = (*transaction)->setElementDefault(transaction, cookie, &ev);
            }
            
        }

        if (rc != kIOReturnSuccess) {
            [NSException raise: NSGenericException 
                        format: @"Failed to create transaction (%lx)",
                (long) rc];
        }
        
        // Reset the output state of the device
        [self syncDeviceOutput];
        
        // Make the queue
        queue = (*interface)->allocQueue(interface);
        if (queue == nil) {
            [NSException raise: NSGenericException 
                        format: @"Failed to create input queue"];
            
        }

        rc = (*queue)->create(queue, 0, 8);
        for (i = 0; rc == kIOReturnSuccess &&
                    i < sizeof(inputCookies) / sizeof(inputCookies[0]); i++) {
            rc = (*queue)->addElement(queue, inputCookies[i], 0);
        }
        
        if (rc == kIOReturnSuccess) {
            rc = (*queue)->start(queue);
        }

        if (rc == kIOReturnSuccess) {
            rc = (*queue)->createAsyncEventSource(queue, &eventSource);
        }

        if (rc == kIOReturnSuccess) {
            rc = (*queue)->setEventCallout(queue, queueCallback, NULL, self);
        }
        
        if (rc != kIOReturnSuccess) {
            [NSException raise: NSGenericException 
                        format: @"Failed to build input queue (%lx)",
                (long) rc];
        }
        
        CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource,
                           kCFRunLoopDefaultMode);

        // Send notifications
        [[NSNotificationCenter defaultCenter]
            postNotificationName: @"InputChanged" object:self];

        [[NSNotificationCenter defaultCenter]
            postNotificationName: @"AnalogChanged" object:self];
        
    }
    
    return self;
}

- (void) dealloc {
    
    if (queue != nil) {
        (void) (*queue)->stop(queue);
        (void) (*queue)->dispose(queue);
        (*queue)->Release(queue);
    }
    
    if (transaction != nil) {
        (*transaction)->clear(transaction);     // Necessary?
        (*transaction)->Release(transaction);
    }
    
    if (interface != nil) {
        (*interface)->close(interface);
        (*interface)->Release(interface);
    }
    
    // close device
    [super dealloc];
}

- (int) getOutput {
    return output;
}

- (void) setOutput: (int) outp {
    if (output != outp) {
        output = outp;
        [self syncDeviceOutput];
    }
}

- (int) getInput {
    if (eventMask == 0) {
        // If we haven't received any events we assume that we haven't
        // started a run loop so we read the input directly. As soon as
        // input events start we switch to event drive mode.
        input = [self translateInput: [self readRaw: K8055INPUTCOOKIE]];
    }
    
    return input;
}

- (void) setAnalog: (int) value
         onChannel: (int) channel {
    if (channel < 0 || channel >= MAXPWM) {
        [NSException raise: NSGenericException 
                    format: @"Illegal channel: %d (0 to %d allowed)",
            channel, MAXPWM];
    }
    
    if (pwm[channel] != value) {
        pwm[channel] = value;
        [self syncDeviceOutput];
    }
}

- (int) getAnalog: (int) channel {
    if (channel < 0 || channel >= MAXANALOG) {
        [NSException raise: NSGenericException 
                    format: @"Illegal channel: %d (0 to %d allowed)",
            channel, MAXPWM];
    }

    if (eventMask == 0) {
        // See comment in getInput above
        analog[channel] = [self readRaw: K8055ANALOGCOOKIE1 + channel];
    }
    
    return analog[channel];
}

- (long) getCount: (int) channel {
    if (channel < 0 || channel >= MAXINPUT) {
        [NSException raise: NSGenericException 
                    format: @"Illegal channel: %d (0 to %d allowed)",
            channel, MAXPWM];
    }

    return inputCount[channel];
}

- (long) resetCount: (int) channel {
    long v = [self getCount: channel];
    inputCount[channel] = 0;

    [[NSNotificationCenter defaultCenter]
            postNotificationName: @"InputChanged" object:self];

    return v;
}

- (void) resetCounts {
    int i;
    for (i = 0; i < MAXINPUT; i++) {
        (void) [self resetCount: i];
    }
}

- (void) switchOff {
    [self setOutput: 0];
    [self setAnalog: 0
          onChannel: 0];
    [self setAnalog: 0
          onChannel: 1];
}


@end

static void queueCallback(void *target, IOReturn result, void *ref, void *sender) {
    K8055 *k8055 = (K8055 *) ref;
    [k8055 gotEvent];
}

Hello Steve,

thank you very much for your contribution! It runs very well under Xcode 4.2.1!

I would like to use 4pcs of k8055 in parallel. Have you got please an idea or a tip how to change the program file to run 4pcs of k8055 with different addresses (SK5/SK6 settings on the board) on my iMac?

Thank you very much in advance!

Yours,
Uli

Hi Uli

With regards Andy Armstrong’s code I don’t know how to get it to work with four boards. My knowledge of Objective C is limited and even more so when it comes to USB I/O.

However that said I have been working on creating an App from the ground up using the newer API’s.

Currently I’m really in a beta stage of version one which just gives you the one board control much like Andy’s. There’s a few issues I need to resolve.

How every once I’m happy with the results I will be working on a four board version. How ever development is slow on this due to time and experience but I will upload a copy some were when it’s done and let you know via this thread.

But don’t hold your breath! LOL

Cheers
Steve

Uli

Just had a thought

The line in the above code at the top

#define K8055PRODUCT 0x5500

Is used to address board at address 0.

You could ‘build’ four versions of Andy’s App and change this line in each build to

#define K8055PRODUCT 0x5501
#define K8055PRODUCT 0x5502
#define K8055PRODUCT 0x5503

Each App would then control a different board but obviously you’d need to run the four apps in tandem to control all at once.

Does that make sense?

Steve

Hello Steve,

the idea is really good. In this case, a main controller permanently has to check the availability of the different cards on the USB-port.
If a card has been recognized by the main controller, a window will pop-up to control its inputs/outputs. If the card is removed from the USB-port, the main controller closes automatically its window.

Have you got an idea, how to program in Xcode multiple windows with the same class definition but addressing different card addresses?

Another idea:
What do you think about programming a window which contains four fields representing the four different cards. Every field has got the eight switches to turn-on/-off the LEDs and to read out the digital inputs. There is still the challenge to address the different cards.

Now I’m trying to modify the k8055Window files by defining indexed IBOutlet id variables (example: output7_0 -> output7 of card #0; output7_1-> output7 of card #1 and so on) and the MainMenu.nib while keeping the k8055 class unchanged. I’m trying for first to address only two cards in order to gain some experiences.

Did you gain some further experiences in your k8055 Xcode project?

Yours,
Uli

Hi Uli

I have recently (well early April - not done much since!) been working on this idea. What I have wanted is a main window which expanded with one to four panels (like say four of Andys apps). However this will only place a ‘panel/field’ depending on how many cards you have connected but will also expand and contract if cards are added or removed while the App is running. While I had luck creating this four card front end at the time I had not merged my driver with it. It’s something I will get round to but not had the time of late.

[quote]Did you gain some further experiences in your k8055 Xcode project?
[/quote]

Yes many but it has been a struggle. I know this is due to the fact that I moved from php to obj-C and instead of reading up on C and Obj-C/Cocca basics I’ve dived right in to programming the K8055 driver. It’s not recommended but then how wants an easy life LOL.

If your looking to write your own driver, which in my opinion is the best way to go as you learn how it works and then know how to change it for future OS’s.

I recommend looking at using Apples HIDManager:

developer.apple.com/library/mac/ … index.html

The documentation is not the easiest to read through (but then I don’t think any Apple documentation is).

However this would enable you to create a true object with limited static functions and means you can call four instances of the driver. Plus you’ll get round any depreciated code in Andy’s version.

So you can call each card like any object.

K8055driver *driver0 = [[K8055driver alloc] init];

which would default to card at address 0.

or you can specify the card on creation

K8055driver *driver2 = [[K8055driver alloc] initWithCardAddress : 2];

Which obviously creates a instance for a defined card address.

I found your best calling the card address at the init stage instead of trying to use a setCardAddress method.

Plus for the space (in RAM) the drivers use your best calling all four instances when ApplicationDidFinishLoading {} that way the app is always ready for a card even if it’s not connected at launch.

Steve

So it’s been a while since the last post in this topic, but I’m struggling with the same problem. Getting the code to compile for Leopard was one thing (for a non-programmer like me), but Lion and soon Mountain Lion is something different altogether…
Did any of you solve this and, just as important, are you willing to share your project with me?

Thanks,

Arjen

HI Arjen

I did finish a single board version (card address 0) for the mac which does run under L & ML. Which your welcome to have a copy of the app (Although I’m keeping the source code private). I don’t know if it’s possible to upload the app to the boards for general download. It is only some 700k in size.

Although please be aware (and this goes to anyone who request it or wants it). I’d regard the app as a public beta and I don’t place any guarantees that the app won’t crash your system…etc … etc… etc.

It has run fine on mine and I would ask for any feedback etc if people don’t mind.

I’ll give some thought today on how to upload it somewhere. Although if anyone can inform me how to make it downloadable from the forum then I’ll start a thread for it.

Steve

Steve,

Glad to hear you made it work! I’m thinking the problem I have with mine is the fact that Velleman made a new version of the card. The one I have here is is a K8055N, the one I worked with before is the older version without the N. I don’t know what they did but on Windows you’ll need a newer version of the DLL to make it work so I guess something changed in the code of the PIC running the board. I don’t have direct access to the old card (it’s running things in my holiday cottage) so I can’t be sure, but I do know the app running things there does not work with this card, not even on a machine running Snow Leopard.
Anyway, I’d be pleased to test your app. I created a gmail address, vellemank8055n@gmail.com, so if you would be so kind you can send it there.
I understand you don’t want to share your code, but I’m curious if you adapted Andy’s code or took the HID road. I want to use this card to turn on/off and dim some lights so a very simple interface is OK, but for my cottage I would like to be able to save the settings so when the app starts up after a power failure it will restore the settings. But that’s all for the future, first I’d like to get this card going…

Thanks,

Arjen

App has been sent on. Any feedback you wish to give would be appreciated. Also I take your point with regards remembering the settings. I did test this a bit with disconnecting the card and reconnecting it (which isn’t on the version I’ve sent) but it would be interesting to see how it would work with the machine rebooting. So I’ll stick it on my list.

My understanding was that the N board should have been a direct replacement but unfortunately I haven’t had a new N board to test. However get in touch if it fails and I’ll maybe have to look out for a cheep one on ebay.

With regards the code I didn’t adopt Andy’s as my understanding is that as the device is a HID device it should be caught by Apples HID drivers first and as the HIDManager seems to be the API to use and I wanted code I understood inside out which I didn’t with Andy’s stuff (My lack of knowledge not Andy’s code!) I opted for completely new code though it was a steep learning curve!.

I’m still looking at building a multi board version with extra features one of which is adding PS3 controller support so I can turn thing on/of etc with a control pad. Though as I mentioned to Uli it’s getting round to it.

Though I will admit if I finish the four board extended version I’d maybe think of putting it on the App Store for say £4.99. But don’t quote me on that!

Steve
:slight_smile:

Hello Seve,

congratulations to your success on creating an app controlling the k8055! Could you please send it also to me? I have got still the old one k8055, but I have switched to Mountain Lion OS. I also would check the operation of your app and give some feedback.
Thank you!

Yours,
Uli

Hi Uli

No probs in sending you the app. I will point out though that this app only works with the old k8055 vm110 and not the N version as Arjena has tried it with the N Board which results in a ‘app crash’.

if you want to email me at mymack8055controller@gmail.com with the subject of ‘K8055 Controller Request’ then I’ll email you the app back.

That goes for anyone else who would like a copy. Keeping the subject as above means I can filter out the spam that I’m sure that address will collect.

Steve

Actually on the subject of the VM110N.

If the nice people at Velleman UK wanted to send be a free board I’d look at rewriting the controller for it and sending them a copy of the app to post on their site…

Well if you don’t ask…

:slight_smile:

Hi all,

Steve and I had some communication outside this forum, but to keep others interested in this subject in the loop I’ll share what I found here too.
Steve’s application did not work for me. It crashes on both a Lion and a Snow Leopard system. This is most likely because my card is the new version, the K8055N. On Windows I found it needs an updated DLL, so there must be something different.
I did however manage to compile old code (2005) from Richard Plumridge found on Sourgeforge. The downside is you’ll need to install a .kext file in your system which does make it less user friendly. I even managed a long standing wish to implement a preferences file so it remembers the settings when quit and restores them when you open the app again. It was indeed the NSUserDefault class that did the trick quite easy I might say. Thanks for the suggestion Steve!
I’m installing Mountain Lion as I type this, so fingers crossed my app will still work after the upgrade…

Cheers,

Arjen