BlitzMax & Phidgets

BlitzMax Forums/BlitzMax Programming/BlitzMax & Phidgets

Hello,
Here is a very specific question. I don't know if anyone at this forum is familiar with Phidget interface boards.
In trying to connect my application with Phidgets electronics (sensors, controls, etc.) for an interactive mixed media installation.
I've done it before with Macromedia Director but for Director was a ready-to-use plugin (xtra) available.
Now I'm writing an interface with the Phidget21.dll.
I made a little progress, in a sence that I can make a connection with an interface board (Phidget I/O card) but I get an "Unhandled Exception: Unhandled Memory Exception Error." I learned from this forum that it has to do something with a wrong parameter definition.

Anyway, is there somebody out there who has experience with using Phidgets in BlitzMax and is he/she willing to help me writing an Phidget interface?

Here is my experiment code:
SuperStrict

'Import pub.win32

Global PhidgetGetSerialNumber:Int(phidgetHandle:Int, serialNumber:Int Var) "C"
Global PhidgetOpen:Int(phidgetHandle:Int, serialNumber:Int) "C"
Global PhidgetClose:Int(phidgetHandle:Int) "C"
Global PhidgetDelete:Int(phidgetHandle:Int) "C"

Global PhidgetInterfaceKitCreate:Int(phidgetHandle:Int Var) "C"
Global PhidgetWaitForAttachment:Int(phidgetHandle:Int, duration:Long) "C"
Global PhidgetSetOnAttachHandler:Int(phidgetHandle:Int, handler:Int(), userDataStruct:Int()) "C"
Global PhidgetSetOnDetachHandler:Int(phidgetHandle:Int, handler:Int(), userDataStruct:Int()) "C"
'Global PhidgetInterfaceKitSetOnSensorChangeHandler:Int(phidhetHandle:int, handler:Int(), userDataStruct:Int()) "C"


Global ThisDLL:Int = LoadLibraryA("c:\Program Files\Phidgets21\Phidget21.dll")

If ThisDLL = Null Then
	Print "Oops, no dll init"
	End
Else
	PhidgetGetSerialNumber = GetProcAddress(ThisDLL, "CPhidget_getSerialNumber")
	PhidgetOpen = GetProcAddress(ThisDLL, "CPhidget_open")
	PhidgetClose = GetProcAddress(ThisDLL, "CPhidget_close")
	PhidgetDelete = GetProcAddress(ThisDLL, "CPhidget_delete")
	PhidgetInterfaceKitCreate = GetProcAddress(ThisDLL, "CPhidgetInterfaceKit_create")
	PhidgetWaitForAttachment = GetProcAddress(ThisDLL, "CPhidget_waitForAttachment")
	PhidgetSetOnAttachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnAttach_Handler")
	PhidgetSetOnDetachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnDetach_Handler")
'	PhidgetInterfaceKitSetOnSensorChangeHandler = getProcAddress(ThisDLL, "CPhidgetInterfaceKit_set_OnSensorChange_Handler")
End If	

'DebugStop() 
Global errorCode:Int
Global gbAttached:Int = False

Global gPhidgetHandle:Int

Print PhidgetInterfaceKitCreate(gPhidgetHandle)
Print PhidgetSetOnAttachHandler(gPhidgetHandle, Attach, Null)
Print PhidgetSetOnDetachHandler(gPhidgetHandle, Detach, Null) 
'Print PhidgetInterfaceKitSetOnSensorChangeHandler(gPhidgetHandle, OnSensorChanged, Null)
Local serial:Int
Print PhidgetGetSerialNumber(gPhidgetHandle, serial)
Print PhidgetOpen(gPhidgetHandle, -1)'serial)

Print "Waiting 3 seconds for Phidget board to attach..."
errorCode = PhidgetWaitForAttachment(gPhidgetHandle, 3000) 
Print errorCode
If errorCode = 13 Then
	Print "Time out. No Interface board found."
	ClosePhidget() 
	End
Else
	Print "run application"
End If


Rem
While Not KeyHit(KEY_ESCAPE)
Wend


End

End Rem
Graphics 800, 600, 0, 60
SetClsColor(255, 255, 255)
SetColor(0, 0, 0)

While Not KeyHit(KEY_ESCAPE)
	Cls
	DrawText("Hello world", 50, 100)
	Flip
Wend

ClosePhidget() 
End

Function ClosePhidget() 
	Print "Close Phidget."
	Print PhidgetClose(gPhidgetHandle) 
	Print PhidgetDelete(gPhidgetHandle) 
End Function


Function Attach() 
	Print "InterfaceKit Attached!"
	gbAttached = True
End Function


Function Detach()
	Print "InterfaceKit Detached!"
	gbAttached = False
End Function

Function OnSensorChanged()
	Print "SensorChanged"
End Function


More info and dll downloads at www.phidgets.com

You need to use "Win32" istead of "C", as the calling convention for dlls is stdcall.

Tried Win32...
It makes no difference using "C" or "Win32"
Same behaviour.
If there is no interface board attached it runs, waits for 3 secs, closes the link end terminates properly the app.
But if there is an interface board attached it runs, finds it immediately, runs the Attach() function, prints "run application" and... pops up the error message.

Win32 is the proper way to go, and you probably need to use it for any callbacks as well.

and you probably need to use it for any callbacks as well.

you mean?

I don't know if this would make a difference, but your callbacks aren't returning anything and they are defined as :Int() in the API declarations. I'm almost positive it's something related to the way the callbacks are declared, because you're not passing anything to the library other than the -1 in PhidgetOpen().

Unfortunatly I don't think there is anyone where who's used that particular piece of hardware.

The -1 parameter is the a notation for the serialNumber of the automaticly found instance of the PhidgetBoard when calling
PhidgetInterfaceKitCreate(gPhidgetHandle)
One can address multiple i/o boards by using this serialNumber, but since I use only one I can use the -1 value.

If you install the Phidget software without having any hardware you can run my program and it will wait for an i/o board to attach. So the declerations seem to work. The problem occurs when a i/o board is attached. Therefor I'm dependent of a forum member who has some Phidget hardware to test.
Unfortunatly I don't think there is anyone where who's used that particular piece of hardware.

It is very interesting hardware to use for games and interactive shows, though.

you mean?

Stick a "win32" after the declaration like in your function pointers.
its worth a try anyway.

A long in C on 32 bit hardware is the same as int and is not compatible with BlitzMax long, so you need to change the duration:long to duration:int.

also, for callbacks try the following
Global PhidgetSetOnAttachHandler:Int(phidgetHandle:Int, handler:Int()"C", userDataStruct ptr) "C"
Global PhidgetSetOnDetachHandler:Int(phidgetHandle:Int, handler:Int()"C", userDataStruct ptr) "C"
Function Attach() "C"
	Print "InterfaceKit Attached!"
	gbAttached = True
End Function

Function Detach() "C"
	Print "InterfaceKit Detached!"
	gbAttached = False
End Function


actually your callback parameters are all wrong/ missing compared to the examples in the c api manual so you will need to fix them also

@skitracer: Thanks for taking time reading the c api manual.
actually your callback parameters are all wrong/ missing compared to the examples in the c api manual so you will need to fix them also
If that's so, than how do I fix them? What is the right notation?

Btw. your modifications make no difference in behaviour.

I'm in a strange situation of having
* a BlitzMax community with BlitzMax guru's (yes, that's you guys) but without Phidgets experience,
* a Phidget community who has no experience in BlitzMax,
* a colleque who is a DLL expert but who has no experience with BlitzMax nor Phidgets, and finally
* me, the ignorant, who sees lot's of nice opportunities in the combination of BlitzMax and Phidgets.
But I'm not giving up :)


If that's so, than how do I fix them? What is the right notation?



err, have you read the manual ?

Oooh, I wonder if you can get this stuff in the UK?

Might be a nice project for when I get back :-)

I asume I'm the only BlitzMax programmer that uses Phidgets but I would like to use this post to keep track of the changes and insights. And by the reaction of Brucey I have the impression I won't be the only one using Phidgets for long ;)

err, have you read the manual ?

should I?
Of course I read it! But did I understand it completely? I don't think so. But I had an appointment with my DLL-guru yesterday and together with him we came up with the following code:

SuperStrict

Global PhidgetInterfaceKitCreate:Int(phidgetHandle:Int Var) "Win32"
Global PhidgetGetSerialNumber:Int(phidgetHandle:Int, serialNumberAddress:Int Ptr) "Win32"
Global PhidgetOpen:Int(phidgetHandle:Int, serialNumber:Int) "Win32"
Global PhidgetClose:Int(phidgetHandle:Int) "Win32"
Global PhidgetDelete:Int(phidgetHandle:Int) "Win32"

Global PhidgetWaitForAttachment:Int(phidgetHandle:Int, duration:Int) "Win32"
Global PhidgetSetOnAttachHandler:Int(phidgetHandle:Int, handler:Int()"Win32", userDataStruct:Int()"Win32") "Win32"
Global PhidgetSetOnDetachHandler:Int(phidgetHandle:Int, handler:Int()"Win32", userDataStruct:Int()"Win32") "Win32"

Global ThisDLL:Int = LoadLibraryA("c:\Program Files\Phidgets21\Phidget21.dll")

If ThisDLL = Null Then
	Print "Oops, no dll init"
	End
Else
	PhidgetGetSerialNumber = GetProcAddress(ThisDLL, "CPhidget_getSerialNumber")
	PhidgetOpen = GetProcAddress(ThisDLL, "CPhidget_open")
	PhidgetClose = GetProcAddress(ThisDLL, "CPhidget_close")
	PhidgetDelete = GetProcAddress(ThisDLL, "CPhidget_delete")
	PhidgetInterfaceKitCreate = GetProcAddress(ThisDLL, "CPhidgetInterfaceKit_create")
	PhidgetWaitForAttachment = GetProcAddress(ThisDLL, "CPhidget_waitForAttachment")
	PhidgetSetOnAttachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnAttach_Handler")
	PhidgetSetOnDetachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnDetach_Handler")
End If	

Local errorCode:Int
Global gbAttached:Int = False

Global gPhidgetHandle:Int
Print PhidgetInterfaceKitCreate(gPhidgetHandle)
Print PhidgetSetOnAttachHandler(gPhidgetHandle, Attach, Null)
Print PhidgetSetOnDetachHandler(gPhidgetHandle, Detach, Null) 

Local serial:Int
Print PhidgetGetSerialNumber(gPhidgetHandle, Varptr serial)

Print PhidgetOpen(gPhidgetHandle, -1) 'serial)

Print "Waiting 3 seconds for Phidget board to attach..."
errorCode = PhidgetWaitForAttachment(gPhidgetHandle, 3000) 
Print errorCode
If errorCode = 13 Then
	Print "Time out. No Interface board found."
	ClosePhidget() 
	End
Else
	Print "run application"
	DebugStop()
End If


Graphics 800, 600, 0, 60
SetClsColor(255, 255, 255)
SetColor(0, 0, 0)

While Not KeyHit(KEY_ESCAPE)
	Cls
	DebugStop()
	DrawText("Hello world", 50, 100)
	Flip
Wend

ClosePhidget() 
End

Function ClosePhidget() 
	Print "Close Phidget."
	Print PhidgetClose(gPhidgetHandle) 
	Print PhidgetDelete(gPhidgetHandle) 
End Function


Function Attach() "Win32"
	Print "InterfaceKit Attached!"
	gbAttached = True
End Function


Function Detach() "Win32"
	Print "InterfaceKit Detached!"
	gbAttached = False
End Function

Function OnSensorChanged() "Win32"
	Print "SensorChanged"
End Function


A few minor modifications were made, but the result is still the same. We know for certain the PhidgetOpen() function is the cause of the problem but we have no idea how to solve this. It has something to do with the serialNumber.

This is what I know about it so far:
The phidget21.h file shows to obtain the serial number I have to use a pointer to the variable serial.

int __stdcall CPhidget_getSerialNumber (CPhidgetHandle phid, int *serialNumber);

Then to open the device I use the variable serial itself:

int __stdcall CPhidget_open (CPhidgetHandle phid, int serialNumber);

So I translated that to the following lines of code:
'declaration
Global PhidgetGetSerialNumber:Int(phidgetHandle:Int, serialNumberAddress:Int Ptr) "Win32"
...
'function call
Print PhidgetGetSerialNumber(gPhidgetHandle, Varptr serial)

When debugging this the variable serial does not get a number. That's strange.
One can however overrule this by using -1 in the PhidgetOpen() function to specify the first available device. That doesn't work either.

@brucey: I'm from the Netherlands but I'm sure you can buy this in the UK as well.

sorry for being a little short with the info, as you can see your attach and detach callback parameters don't look anything like they do in the following.


also perhaps one thing at a time, i would rip out the callback stuff until you solved your serial number puzzle

#include "stdio.h"
#include "tchar.h"
#include "phidget21.h"
int __stdcall AttachHandler (CPhidgetHandle IFK, void *userptr){
printf("Device attached!\n");
return 0;
}
int __stdcall DetachHandler (CPhidgetHandle IFK, void *userptr){
printf("Device detached! %s\n",userptr);
return 0;
}
int _tmain(int argc, _TCHAR* argv[]){
char mystring[15] = "Successfully!\0";
CPhidgetInterfaceKitHandle ifKit = 0;
CPhidgetInterfaceKit_create(&ifKit);
printf("Device detection active\n");
CPhidget_set_OnAttach_Handler ((CPhidgetHandle)ifKit, AttachHandler, NULL);
CPhidget_set_OnDetach_Handler ((CPhidgetHandle)ifKit, DetachHandler, &mystring);
getchar();
printf("Closing...\n");
CPhidget_close((CPhidgetHandle)ifKit);
CPhidget_delete((CPhidgetHandle)ifKit);
return 0;
}


It works!!!
Thanks to your tip of skipping the attach/detach callback functions. After that I took a closer look at the example code from Appendix IV in the C API manual (the same code as you've just posted) to find out what I was doing wrong.
The result of all that effort is implemented in the code below. It is working code now ;) (To be totally honest; the serialNumber function is still not working.)
Mind you, it is not a program; it is just example code that you can build/run.

The next step I want to make is creating an include file 'phidget.bmx' with a TPhidget type containing all the interfacing with the different Phidget boards (e.g. InterfaceKit, LEDboard, Accelerometer, etc...). If anyone wants to (help me) make a Phidget.mod instead of a phidget.bmx include file I'll be most grateful.


'This example code shows a few options of the Phidget InterfaceKit board.
'It reads 2 analog input values and writes to digital output 1 and 2 a 'blinking' signal.
'
'press esc key to terminate application.

SuperStrict

Global PhidgetInterfaceKitCreate:Int(phidgetHandle:Int Var) "Win32"
Global PhidgetGetSerialNumber:Int(phidgetHandle:Int, serialNumberAddress:Int Ptr) "Win32"
Global PhidgetOpen:Int(phidgetHandle:Int, serialNumber:Int) "Win32"
Global PhidgetClose:Int(phidgetHandle:Int) "Win32"
Global PhidgetDelete:Int(phidgetHandle:Int) "Win32"

Global PhidgetWaitForAttachment:Int(phidgetHandle:Int, duration:Int) "Win32"
Global PhidgetSetOnAttachHandler:Int(phidgetHandle:Int, handler:Int(phidgetHandle:Int, userPtr:Int Ptr)"Win32", userPtr:Int Ptr) "Win32"
Global PhidgetSetOnDetachHandler:Int(phidgetHandle:Int, handler:Int(phidgetHandle:Int, userPtr:Int Ptr)"Win32", userPtr:Int Ptr) "Win32"
Global PhidgetGetSensorValue:Int(phidgetHandle:Int, index:Int, value:Int Ptr) "Win32"
Global PhidgetSetOutputState:Int(phidgetHandle:Int, index:Int, state:Int) "Win32"
'Global PhidgetInterfaceKitSetOnSensorChangeHandler:Int(phidhetHandle:Int, handler:Int()"Win32", userDataStruct:Int()"Win32") "Win32"


Global ThisDLL:Int = LoadLibraryA("c:\Program Files\Phidgets21\Phidget21.dll")

If ThisDLL = Null Then
	Print "Oops, no dll init"
	End
Else
	PhidgetGetSerialNumber = GetProcAddress(ThisDLL, "CPhidget_getSerialNumber")
	PhidgetOpen = GetProcAddress(ThisDLL, "CPhidget_open")
	PhidgetClose = GetProcAddress(ThisDLL, "CPhidget_close")
	PhidgetDelete = GetProcAddress(ThisDLL, "CPhidget_delete")
	PhidgetInterfaceKitCreate = GetProcAddress(ThisDLL, "CPhidgetInterfaceKit_create")
	PhidgetWaitForAttachment = GetProcAddress(ThisDLL, "CPhidget_waitForAttachment")
	PhidgetSetOnAttachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnAttach_Handler")
	PhidgetSetOnDetachHandler = GetProcAddress(ThisDLL, "CPhidget_set_OnDetach_Handler")
	PhidgetGetSensorValue = GetProcAddress(ThisDLL, "CPhidgetInterfaceKit_getSensorValue")
	PhidgetSetOutputState = GetProcAddress(ThisDLL, "CPhidgetInterfaceKit_setOutputState")
	
'	PhidgetInterfaceKitSetOnSensorChangeHandler = getProcAddress(ThisDLL, "CPhidgetInterfaceKit_set_OnSensorChange_Handler")
End If	

'DebugStop() 
Local errorCode:Int
Global gbAttached:Int = False

Global gPhidgetHandle:Int
'DebugStop()
Print PhidgetInterfaceKitCreate(gPhidgetHandle)
Print PhidgetSetOnAttachHandler(gPhidgetHandle, Attach, Null)
Print PhidgetSetOnDetachHandler(gPhidgetHandle, Detach, Null) 

'Print PhidgetInterfaceKitSetOnSensorChangeHandler(gPhidgetHandle, OnSensorChanged, Null)
Local serial:Int
Local serialAddr:Int Ptr = Varptr serial

Print PhidgetGetSerialNumber(gPhidgetHandle, serialAddr)
'DebugStop()

Print PhidgetOpen(gPhidgetHandle, -1)'serial)

Print "Waiting 3 seconds for Phidget board to attach..."
errorCode = PhidgetWaitForAttachment(gPhidgetHandle, 3000) 
Print errorCode
If errorCode = 13 Then
	Print "Time out. No Interface board found."
	ClosePhidget() 
	End
Else
	Print "run application"
	Print PhidgetSetOutputState(gPhidgetHandle, 0, 1)
	Print PhidgetSetOutputState(gPhidgetHandle, 1, 1)
	
'	DebugStop()
End If


Rem
While Not KeyHit(KEY_ESCAPE)
Wend


End

End Rem
Graphics 800, 600, 0, 60
SetClsColor(255, 255, 255)
SetColor(0, 0, 0)
'DebugStop()
Local value:Int = 0
Local valueAddr:Int Ptr = Varptr value

Local cnt:Int = 0
Local state:Int = 0

While Not KeyHit(KEY_ESCAPE)
	Cls
	DrawText("Hello world", 50, 100)
	errorCode = PhidgetGetSensorValue(gPhidgetHandle, 0, valueAddr)
	DrawText("Value at index 0: " + String(value), 50, 130)
	errorCode = PhidgetGetSensorValue(gPhidgetHandle, 1, valueAddr)
	DrawText("Value at index 1: " + String(value), 50, 150)
	cnt:+1
	If cnt>50 Then
		cnt = 0
		state = 1 - state
		errorCode = PhidgetSetOutputState(gPhidgetHandle, 0, state)
		errorCode = PhidgetSetOutputState(gPhidgetHandle, 1, state)
	End If
	Flip
Wend

ClosePhidget() 
End

Function ClosePhidget() 
	Local errorCode:Int
	Print "Close Phidget."
	'turn all digital outputs off
	For Local index:Int = 0 To 7
		errorCode = PhidgetSetOutputState(gPhidgetHandle, index, 0)
	Next
	Print PhidgetClose(gPhidgetHandle) 
	Print PhidgetDelete(gPhidgetHandle) 
End Function


Function Attach:Int(phidgetHandle:Int, userPtr:Int Ptr = Null) "Win32"
	Print "InterfaceKit Attached!"
	gbAttached = True
	Return 0
End Function


Function Detach:Int(phidgetHandle:Int, userPtr:Int Ptr = Null) "Win32"
	Print "InterfaceKit Detached!"
	gbAttached = False
	Return 0
End Function

Function OnSensorChanged() "Win32"
	Print "SensorChanged"
End Function