Receiving "Interrupts" (OS X)

This is the English forum for all topics related to IO-Warrior. Please post in English only

Moderator: Guido Körber

Post Reply
Erik
Posts: 7
Joined: Wed Aug 24, 2005 1:58 am
Location: San Diego, CA, USA

Receiving "Interrupts" (OS X)

Post by Erik »

Greetings,

( I'm using an IOWarrior 40 Kit, Mac OS X.3.9, XCode "C" application )

I'm having a great time with my IO-Warrior! It's a very handy device. I've adapted the IOWarriorLibTest application so as to bounce a "ball" back and forth on the LEDs, reversing early if one presses a button. It listens to Port A bits 0 & 1 as "buttons". A0 is of course, the button included with the kit, and I've got A1 going to a capacitance proximity switch (the real objective).

I'm currently having decent success with polling for data changes so the kit and switches are working fine. Anyway, I'd be much happier getting input data via "Interrupts" than with polling and it seems like it should be possible.

Section 5.2 of the datasheet mentions that "For input data IO-Warrior is using endpoint 1 as an interrupt-in endpoint." in the sense of a USB "interrupt". I am attempting to register a callback with IOWarriorSetInterruptCallback, but am neither getting an error nor any action in my callback! Actually, I did have to change the callback parameters to match Apple's spec initially to compile, but all the calls inside IOWarriorSetInterruptCallback succeed. I have tried it on "interface0" and "interface1" as well.

The callback has this signature so as to compile (which is different than the sample in IOWarriorLibTest but matches apples spec):

Code: Select all

void myCallback (void *target, IOReturn result, void *refcon, void *sender, UInt32 bufferSize)
At this point I just have a printf and a breakpoint in my callback, but no action.

Do I need to enable something first somehow? What am I doing incorrectly here?


TIA,

Erik
Guido Mocken
Posts: 13
Joined: Sun Sep 26, 2004 7:57 pm

Re: Receiving "Interrupts" (OS X)

Post by Guido Mocken »

Erik wrote: I am attempting to register a callback with IOWarriorSetInterruptCallback, but am neither getting an error nor any action in my callback!
A rather long time ago I experienced similar problems:
I couldn't get the IR-Remote application working and traced the problem back to the callback routine never being called.
IIRC the solution was to remove the (non-Apple) "USB Overdrive" driver from the system, which was somehow interfering with IOWarrior.

Guido
Erik
Posts: 7
Joined: Wed Aug 24, 2005 1:58 am
Location: San Diego, CA, USA

Re: Receiving "Interrupts" (OS X)

Post by Erik »

Guido Mocken wrote:
Erik wrote: I am attempting to register a callback with IOWarriorSetInterruptCallback, but am neither getting an error nor any action in my callback!
A rather long time ago I experienced similar problems:
I couldn't get the IR-Remote application working and traced the problem back to the callback routine never being called.
IIRC the solution was to remove the (non-Apple) "USB Overdrive" driver from the system, which was somehow interfering with IOWarrior.

Guido
I'm glad to hear that the "Interrupt" feature is possible at least!

I am not finding anything by that name on my machine, I'm looking in System/Library/Extensions manually, and also searching the entire drive. Is there another place or way to look that I should try? I don't know of any third-patry USB drivers on my machine, but I'll double check and try a virgin machine too...

Is your working code available somewhere that I might look it over, or the key portions of it relating to the interrupt registration?

I am going to try puting the Warrior into keyboard matrix reading mode (a special mode rather than regular data line reading which I am really after) and see if that makes a difference... Perhaps it is only the special modes that send interrupts (though the docs seem to indicate otherwise)...
Guido Mocken
Posts: 13
Joined: Sun Sep 26, 2004 7:57 pm

Re: Receiving "Interrupts" (OS X)

Post by Guido Mocken »

Erik wrote: I am not finding anything by that name on my machine, I'm looking in System/Library/Extensions manually, and also searching the entire drive. Is there another place or way to look that I should try? I don't know of any third-patry USB drivers on my machine, but I'll double check and try a virgin machine too...
I don't know where it is installed, but if you haven't deliberately installed it, then it shouldn't be on your system. Just in case: I'm talking about this http://www.usboverdrive.com/ driver. IIRC its installer also contains an uninstaller.
Is your working code available somewhere that I might look it over, or the key portions of it relating to the interrupt registration?
I have not written any working code myself - I just tried to do so and failed in the same way as you (my callback function was never being called). However, when I removed that extra driver, the thing that I actually wanted to get working ("IOWarrior24IRTest" from the SDK) suddenly succeeded in catching those interrupts. Therefore I stopped working on my own code at that point.
Look at IOWarrior24IRTest's "MainController.m" source code file to see how it's done. Note that all this is for an IOW24 and that I don't know how it applies to an IOW40.

- Guido
Erik
Posts: 7
Joined: Wed Aug 24, 2005 1:58 am
Location: San Diego, CA, USA

Re: Receiving "Interrupts" (OS X)

Post by Erik »

Guido Mocken wrote:Look at IOWarrior24IRTest's "MainController.m" source code file to see how it's done. Note that all this is for an IOW24 and that I don't know how it applies to an IOW40.
Will do. I'll use that as the template and adapt it for my porpoise. :) Hopefully that will clear it up. Maybe it's something to do with the "RunLoop" stuff that I'm not so familiar with yet...

-E
Erik
Posts: 7
Joined: Wed Aug 24, 2005 1:58 am
Location: San Diego, CA, USA

Thank you

Post by Erik »

Thank you for the IOWarrior24IRTest application recommendation. I adapted it quickly and it is successfully receiving interrupts! Even managed to learn a little Objective-C which is a great language. :P

When using Endpoint1 (special mode stuff) it works just as expected. For example, I put the IOW40 into key matrix mode and faked a keypress and got the expected 2 interrupts on key-down, then key-up.

When using Endpoint0 (regular data) the interrupts fire continuously, but I just detect changes myself and all is OK. Using "top" the app still reports virtually no usage so I'm not worried at all about the frequency. I guess ideally, there'd be a way to set the rate -- and there may be -- but I'm not worried about that.

Thanks again,

-E
spyro
Posts: 23
Joined: Fri Apr 14, 2006 8:13 pm

Post by spyro »

hi erik,

is it possible to post a running code, with the call of the IOWarriorSetInterruptCallback function
and the deklaration of your callback??

i think it would help me a lot.

especially the void* inRefCon makes me crazy. what exact have i to place there?
i st that a value defined in my main function, transferred to my callback as a parameter on invocation,
or ist it a return value of my callback transferred to the reference in my main??
i tryed both and it doesn't work. i get a bus error if running my projekt.

thanks spyro
Erik
Posts: 7
Joined: Wed Aug 24, 2005 1:58 am
Location: San Diego, CA, USA

Excerpt of my sample code

Post by Erik »

spyro wrote:is it possible to post a running code, with the call of the IOWarriorSetInterruptCallback function
and the deklaration of your callback??
Here's the portion that I adapted from the IOWarrior24IRTest sample code. The "inRefCon" is used to pass a pointer to the object that receives the actual callback. This is not strictly necessary in all cases, but is very handy. For example, if the cbIOWarriorEndpoint0() function were able to do everything it needed by itself, there would be no need for the refCon value. However, this scheme works nicely here. The cbIOWarriorEndpoint0() function is just acting as a little glue to call back to a method of a "class" or "object" -- that way the callback can access member variables, call user interface elements, etc. It is also filtering out the callbacks that don't represent a changed state. That way the real callback handler (on the object) is only bothered when something changes.

This was a while ago, I'm certainly not an Objective C expert, and I ended up using a device with USB interface and PIC microcontroller for my project instead of the IOWarrior -- that allowed me to put a lot of the processing in the device rather than the application though development was certainly more tricky. There would be more proper ways to handle the pluggin in and unplugging of the USB device, etc. This was just a quick adaptation of the sample code to make it look for the IOWarrior 40 rather than 24.

Hopefully it will help you get started and see where to inject the IOWarrior related stuff amongst a fresh or existing XCode project. Probably you could create a fresh project, copy and paste much of this into it, and trim it down to just send some messages to the console (a.k.a. printf).

Erik

Code: Select all

//  IOWatch.m
//
//  Created by E on 8/26/05.
//

#import "IOWatch.h"

#import <WebKit/WebFrame.h>
#import <WebKit/WebView.h>
#import <AppKit/NSSound.h>

#import "IOWarriorLib.h"

UInt32 gInterruptBuf0 = 0;
UInt32 gInterruptBuf0Prior = 0;
IOWarriorHIDDeviceInterface** gWarrior = NULL;

void cbIOWarriorEndpoint0 (void *target, IOReturn result, void *refcon, void *sender, UInt32 bufSize) {    
	if ((result != kIOReturnSuccess) || (bufSize != 4)) return;
	if ( *((UInt32*)target) == gInterruptBuf0Prior) return;	// No change
	gInterruptBuf0Prior = *((UInt32*)target);
	[(IOWatch*)refcon cbEndpoint0:(*((UInt32*)target))];
}

void cbIOWarriorAddRemove(void *inRefCon) {
	IOWatch*	controller = inRefCon;
	short		interfaceCount, i;

	gWarrior = NULL;

	interfaceCount = IOWarriorCountInterfaces ();
	for (i = 0; i < interfaceCount; i++) {
		IOWarriorListNode* theNode;

		theNode = IOWarriorInterfaceListNodeAtIndex(i); 
		if (kIOWarrior40Interface0 ==  theNode->interfaceType) {
			IOWarriorSetInterruptCallback(theNode->ioWarriorHIDInterface, &gInterruptBuf0, 4, cbIOWarriorEndpoint0, controller);

			UInt32 pout = 0x7F0000FF;	// Pull unused outputs low to avoid "flutter"
			IOWarriorWriteToInterface(theNode->ioWarriorHIDInterface, 4, &pout);
			
			gWarrior = theNode->ioWarriorHIDInterface;
			break;
		}
	}
}   

@implementation IOWatch

- (void) awakeFromNib
{
	mButtPrior = 0;
}

- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
	//... other init stuff!
	
    // Init IOWarrior stuff
    IOWarriorInit();
    IOWarriorSetDeviceCallback(cbIOWarriorAddRemove, self);
    cbIOWarriorAddRemove(self);
}

- (void) cbEndpoint0:(UInt32)inVal
{
	UInt8 buttons = (inVal >> 24) ^ 0x01;	// Invert first button
	UInt8 changes = buttons ^ mButtPrior;
	short b;
	
	//printf("INT: %d\n", buttons);
	for (b = 0 ; b < 8 ; b++) {
		if (changes >> b & 0x01) {
			printf("*", b);
		} else {
			printf(" ");
		}
		if (buttons >> b & 0x01) {
			printf("%d", b);
		} else {
			printf(".");
		}
	}
	printf("\n");
	
	for (b = 0 ; b < 8 ; b++) {
		NSButtonCell *daCell = [buttMatrix cellWithTag:b];
		if (!daCell) continue;

		[daCell setHighlighted:((buttons >> b & 0x01) ? YES : NO)];
		//[buttMatrix highlightCell:(buttons >> b & 0x01) atRow:0 column:(b-1)];
		if (changes >> b & 0x01) {
			if (buttons >> b & 0x01) {
				NSSound *daSound = [NSSound soundNamed:@"Tink"];
				if (daSound) [daSound play];
				[daCell performClick:self];
			} else {
				NSSound *daSound = [NSSound soundNamed:@"Morse"];
				if (daSound) [daSound play];
			}
		}
	}
	
	UInt32 pout = 0x7F000080 | (0x0000007F & ~buttons);	// Pull unused outputs low to avoid "flutter"
	IOWarriorWriteToInterface(gWarrior, 4, &pout);

	[buttMatrix setHidden:NO];
	[buttMatrix setNeedsDisplay:YES];
//	[buttMatrix displayIfNeeded];
	
	mButtPrior = buttons;
}

@end
...and...

Code: Select all

/* IOWatch.h */

#import <Cocoa/Cocoa.h>

@class WebView;

@interface IOWatch : NSObject
{
    IBOutlet NSWindow				*mainWindow;
    IBOutlet NSProgressIndicator	*progress;
    IBOutlet NSMatrix				*buttMatrix;
    IBOutlet NSImageView			*waitImage;
    IBOutlet WebView				*mainWeb;
	
	UInt8			mButtPrior;
}

- (IBAction)doButtMatrix:(id)sender;

- (void) cbEndpoint0:(UInt32)inVal;

@end
spyro
Posts: 23
Joined: Fri Apr 14, 2006 8:13 pm

Post by spyro »

thank you very much,
i will study it and i post my results.

bye
10.3.9 iow40 enthusiasmus
spyro
Posts: 23
Joined: Fri Apr 14, 2006 8:13 pm

Post by spyro »

hi,

i've mailed my not working code to mr. marquard, but he is ill. maybe can one of you take a look and can tell me, why myirqroutine is not called, when i pull some pins down.

thanks spyro

Code: Select all


#include <stdio.h>		
#include <IOWarriorLib.h>
#define kIOWarrior40Interface0 0
#define kIOWarrior40Interface1 1
#include <CoreFoundation/CoreFoundation.h>

void myirqroutine (void *	 		target,
					IOReturn 		result,
					void * 			refcon,
					void * 			sender,
					UInt32		 	bufferSize);

int main (int argc, const char * argv[]) 
{
char port[4];
int i,interfaceCount;
IOWarriorListNode* info=NULL;
IOWarriorHIDDeviceInterface** gWarrior=NULL;

if(!IOWarriorInit())
printf("Initialisierung erfolgreich\n\n");

	 
	 

	if(IOWarriorIsPresent())
		{
		info=IOWarriorInterfaceListNodeAtIndex(0);
		if(info)
			{
			printf("is the Seriennummer");
			CFShow(info->serialNumber);
			getchar();
			}
		}

   interfaceCount = IOWarriorCountInterfaces (); 
   
   printf("\n%d interfaces",interfaceCount);
  
   
   for (i = 0; i < interfaceCount; i++)
		{ 
		printf("\n%d. Durchgang der Schleife am Anfang\n",i+1);
		info = IOWarriorInterfaceListNodeAtIndex(i); 
		if (kIOWarrior40Interface0 ==  info->interfaceType)
			{ 
			printf("\nuebergabe der callback-funktion am iowarriorsetinterruptcallback\n");
			IOWarriorSetInterruptCallback(info->ioWarriorHIDInterface, (void*) port, 4, myirqroutine, NULL); 
			printf("\niowarriorsetinterruptcallback wurde aufgerufen");
			port[0]= 0xFD;   // Pull unused outputs low to avoid "flutter" 
			port[1]= 0xFF;
			port[2]= 0xFF;
			port[3]= 0xFF;
			IOWarriorWriteToInterface(info->ioWarriorHIDInterface, 4,(void*) port); 
            gWarrior = info->ioWarriorHIDInterface; 
			break; 
			} 
		printf("\n%d. Durchgang der Schleife am Ende\n",i+1);
		}

   getchar();
   printf("\n\nende");
	
	getchar();
	return 0;
}


void myirqroutine   (void *	 		target,
					IOReturn 		result,
					void * 			refcon,
					void * 			sender,
					UInt32		 	bufferSize)
	{
	printf("\n\ninterruppt wurde aufgerufen");
	}



10.3.9 iow40 enthusiasmus
Ilja A. Iwas
Posts: 7
Joined: Tue Dec 02, 2003 10:55 am

Post by Ilja A. Iwas »

spyro wrote:hi,

i've mailed my not working code to mr. marquard, but he is ill. maybe can one of you take a look and can tell me, why myirqroutine is not called, when i pull some pins down.

thanks spyro
Your code is probably failing because you don't have a run loop in place when you register for callbacks. Calling getchar might block the execution of an existing run loop, too.
Normally you can add several sources to a run loop (that's what I think Apple's USB lib does when you register for an USB callback) and it will dispatch incoming data and events.

Full blown Cocoa and Carbon applications get all that stuff for free. Maybe you should just hack one of Apple's Cocoa examples and put your code snipnet behind a button or a windows awakeFromNib method. Or try modifying on of the IOWarrior Cocoa example apps.

Or checkout Apple's documentation on CFRunLoop.

Hope this helps,
Ilja
spyro
Posts: 23
Joined: Fri Apr 14, 2006 8:13 pm

Post by spyro »

Code: Select all


///////////////////////header :

#include <stdio.h>		
#include <IOWarriorLib.h>
#include <CoreFoundation/CoreFoundation.h>

#define kIOWarrior40Interface0 0
#define kIOWarrior40Interface1 1


void callback		(void *	 		target,
					IOReturn 		result,
					void * 			refcon,
					void * 			sender,
					UInt32		 	bufferSize);

////////////////// main:


#include "restore_project.h"

char port[4];
int schritt,interfaceCount;
bool rechts, links,go,stop;
IOWarriorListNode* info=NULL;

extern void callback    (void *	 		target,
					IOReturn 		result,
					void * 			refcon,
					void * 			sender,
					UInt32		 	bufferSize);

int main (int argc, const char * argv[]) 
{

if(!IOWarriorInit())
printf("\n\nInitialisierung erfolgreich\n\n");

if (IOWarriorIsPresent ())
    {
        printf("Es wurde ein IOWarrior gefunden.\n\n");
        
        info = IOWarriorInterfaceListNodeAtIndex (0);
        if (info)
			{
			printf("is the Serial");
			CFShow(info->serialNumber);
			interfaceCount = IOWarriorCountInterfaces (); 
			printf("\n%d Interfaces.",interfaceCount);
			info = IOWarriorInterfaceListNodeAtIndex(0); 
			if (kIOWarrior40Interface0 ==  info->interfaceType)
				{
				port[0]= 0xFD;   //initialisierung der io-pins
				port[1]= 0xFF;
				port[2]= 0xFF;
				port[3]= 0xFF;
				printf("\nUebergabe der Callback an IOWarriorSetInterruptCallback"); 
				IOWarriorWriteToInterface(info->ioWarriorHIDInterface, 4,(void*) port); 
				IOWarriorSetInterruptCallback(info->ioWarriorHIDInterface, (void*) port, 4, callback, NULL);
				printf("\nCallback an IOWarriorSetInterruptCallback uebergeben!!");
				printf("\nCFRunLoopRun wird gestartet");
				CFRunLoopRun();
				}				 
			else
				{
				printf("\nZuweisung der Callback für Interruptaufruf nicht moeglich!!\n\n");
				}
			}
		else	
			{
			printf("\nKein IOWarriorInterfaceListNodeAtIndex vorhanden!!");
			exit (1);
			}
	}
else
	{
	printf("\nEs konnte kein IOWarrior am USB gefunden werden\n\n");
	exit (1);
	}
return 0;
}

///////////////  callback:



#include "restore_project.h"

extern char port[4];
extern int schritt;
extern bool rechts, links,go,stop;

void callback    (void *	 		target,
					IOReturn 		result,
					void * 			refcon,
					void * 			sender,
					UInt32		 	bufferSize)
	{   
		int portnr,bit;
		
		printf("Callback aufgerufen. Portinhalt:   ");
		for (portnr=0;portnr<4;portnr++)
		{
		for(bit=7;bit>=0;bit--)
			{
			printf("%d",(port[portnr]>>bit)&0x1);
			}
		printf(" ");
		}
	}

Ausgabe:


Initialisierung erfolgreich

Es wurde ein IOWarrior gefunden.

000030C6
is the Serial
2 Interfaces.
Uebergabe der Callback an IOWarriorSetInterruptCallback
Callback an IOWarriorSetInterruptCallback uebergeben!!
10.3.9 iow40 enthusiasmus
Post Reply