k8055 GM
Home Site home Platforming Auto-sprites Vectors Path Finding quaternions.htm Variable Scope Water Panic Super Bouncy Ball Balls of Doom Contents k8055 GM Downloads

 

Controlling the Velleman k8055 interface from within a Gamemaker program

Note this should probably be considered outdated, the k8055 card's protocol has been reverse-engineered by several people and it is likely that a direct GM extension could be written
Also note there is probably little call for this

Background:

Velleman product page

The K8055 is an inexpensive digital and analog interface for connection to a computer via USB. Velleman supply a DLL to control the PCB. While it's unlikely that you'd want to use a K8055 within an actual game you might use Gamemaker to build a control window for a project.

Although Gamemaker includes commands to link to a DLL the data formats are not compatible with the K8055 DLL. I have written a program gm8055.dll to act as "glue" between Gamemaker and the Velleman DLL.

Due to poor file management I am having some difficulty packaging the source code for gm8055.dll. It's written in OpenWatcom C and compiles under the IDE. It's based on an example of DLL source code and contains a lot of excess baggage.

Download gm8055.dll

Demo exe and source Note that these programs require a copy of the Velleman DLL in order to run. Also they won't do much without a K8055 card.

Usage: gm8055.dll may be distributed freely and embedded as a data file. I recommend that the Velleman K8055D DLL is distributed separately as I have not seen license terms for it.

Functions in gm8055.dll

double GM_OpenDevice(double CardAddress)

This is the old method of opening communications with the board, and has been superseded by the combination of GM_SearchDevices and GM_SetCurrentDevice. Do not use this call after calling GM_SearchDevices as it will fail.

Device addresses are 0 to 3.

double GM_CloseDevice()

Call this once at the end of the program. You should not call this when switching between boards.

Analog input

double GM_ReadAnalogChannel(double Channel)

Channels are 1 and 2.

double GM_ReadAllAnalog()

Note that GM_ReadAllAnalog() returns two 16 bit values combined into one number. The top 16 bits are the Channel 1 value and the bottom 16 bits are Channel 2. Values are only 0-255.

Analog output

double GM_OutputAnalogChannel(double Channel, double Data)
double GM_OutputAllAnalog(double Data1, double Data2)
double GM_ClearAnalogChannel(double Channel)

Note this function returns Zero since the K8055D equivalent returns void.

double GM_ClearAllAnalog() (Returns Zero)
double GM_SetAnalogChannel(double Channel) (Returns Zero)
double GM_SetAllAnalog() (Returns Zero)

Digital output

double GM_WriteAllDigital(double Data) (Returns Zero)
double GM_ClearDigitalChannel(double Channel) (Returns Zero)

Channels are 1 to 8

double GM_ClearAllDigital() (Returns Zero)
double GM_SetDigitalChannel(double Channel) (Returns Zero)
double GM_SetAllDigital() (Returns Zero)

Digital input

double GM_ReadDigitalChannel(double Channel)
double GM_ReadAllDigital()

Counters

double GM_ReadCounter(double CounterNr)
double GM_ResetCounter(double CounterNr) Returns Zero.
double GM_SetCounterDebounceTime(double CounterNr, double DebounceTime) Returns Zero.

Setup and initialisation

double GM_SearchDevices()

Returns a four bit value indicating which boards are present: bit 0 = board 0, bit1 = board 1 etc. Returns -1 if used with an old version of K8055D.DLL. 

double GM_SetCurrentDevice(double Address)

Note this function redirects to OpenDevice when used on an old K8055D.DLL that doesn't implement SetCurrentDevice. As such you should use this function in preferance to GM_OpenDevice.

double GM_Version()

Don't call this function, it pops up an "About" box but will not return until the box is closed, so your program will freeze.

/*
"Glue" to allow the Velleman P8055 pcb to be used from Gamemaker.
Wrappers are provided for all functions so all parameters are of type "double".
Note that currently ReadAllAnalog combines the two bytes as two 16 bit values,
Channel1 is high word and Channel2 is low word before returning them in "double"
(floating point) form. 16 bits are returned to allow for future versions with 10
or 12 bit analog.

Also note that the Version function will "block" if called from GM and that the old OpenDevice
method of initialisation and the newer SearchDevices/SetCurrentDevice methods are incompatible.
Attempting to call SetCurrentDevice after OpenDevice has been used will fail and vice-versa.

SearchDevices,SetCurrentDevice and Version are not implemented in early versions
of the K8055D DLL. To avoid dependancy issues this DLL soft-links those functions
so they can be used if available but a program can still function if they are missing.
They return -1 if unimplemented, except for SetCurrentDevice which is converted to OpenDevice
if unavailable. This means that if you don't bother to test for -1
your program will detect all cards present on an old K8055D.DLL version

*/      
     #include <stdio.h>
     #include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

#define FUNCTION __declspec(dllimport)

FUNCTION long __syscall OpenDevice(long CardAddress);
FUNCTION void __syscall CloseDevice(void);
FUNCTION long __syscall ReadAnalogChannel(long Channel);
FUNCTION void __syscall ReadAllAnalog(long *Data1, long *Data2);
FUNCTION void __syscall OutputAnalogChannel(long Channel, long Data);
FUNCTION void __syscall OutputAllAnalog(long Data1, long Data2);
FUNCTION void __syscall ClearAnalogChannel(long Channel); 
FUNCTION void __syscall ClearAllAnalog();
FUNCTION void __syscall SetAnalogChannel(long Channel); 
FUNCTION void __syscall SetAllAnalog();
FUNCTION void __syscall WriteAllDigital(long Data);
FUNCTION void __syscall ClearDigitalChannel(long Channel);
FUNCTION void __syscall ClearAllDigital();
FUNCTION void __syscall SetDigitalChannel(long Channel);
FUNCTION void __syscall SetAllDigital();
FUNCTION int __syscall ReadDigitalChannel(long Channel);
FUNCTION long __syscall ReadAllDigital();
FUNCTION long __syscall ReadCounter(long CounterNr);
FUNCTION void __syscall ResetCounter(long CounterNr);
FUNCTION void __syscall SetCounterDebounceTime(long CounterNr, long DebounceTime);

#ifdef __cplusplus
}
#endif

     #if defined(__cplusplus)
     #define EXTERNC extern "C"
     #else
     #define EXTERNC
     #endif
     DWORD TlsIndex; /* Global Thread Local Storage index */
     HINSTANCE K8055DLib = NULL;

     long (__stdcall *SearchDevices)(void) = NULL; 
     long (__stdcall *SetCurrentDevice)(long Address) = NULL; 
     void (__stdcall *Version)(void) = NULL; 

     

     /* Error checking should be performed in following code */


     BOOL APIENTRY LibMain( HANDLE hinstDLL,

                            DWORD  fdwReason,
                            LPVOID lpvReserved )
     {
         switch( fdwReason ) {
         case DLL_PROCESS_ATTACH:
             /* do process initialization */
             /* create soft links */
             K8055DLib = LoadLibrary("K8055D.dll");
             if (K8055DLib)
             {
                 SearchDevices = (long (__stdcall *) (void))GetProcAddress(K8055DLib, "SearchDevices");
                 SetCurrentDevice = (long (__stdcall *) (long))GetProcAddress(K8055DLib, "SetCurrentDevice");
                 Version = (void (__stdcall *) (void))GetProcAddress(K8055DLib, "Version");
             }

             /* create TLS index */
             TlsIndex = TlsAlloc();
 
                 
             break;


         case DLL_THREAD_ATTACH:
             /* do thread initialization */

             /* allocate private storage for thread */
             /* and save pointer to it */
             TlsSetValue( TlsIndex, malloc(200) );
             break;


         case DLL_THREAD_DETACH:
             /* do thread cleanup */

             /* get the TLS value and free associated memory */
             free( TlsGetValue( TlsIndex ) );
             break;


         case DLL_PROCESS_DETACH:

             /* do process cleanup */
             if (K8055DLib)
                 FreeLibrary(K8055DLib); 

             /* free TLS index */
             TlsFree( TlsIndex );
             break;
         }
         return( 1 );        /* indicate success */
         /* returning 0 indicates initialization failure */
     }

     EXTERNC double __syscall GM_OpenDevice(double CardAddress)
     {
         return OpenDevice(CardAddress);
     }
     
     EXTERNC double __syscall GM_CloseDevice()
     {
         CloseDevice();
         return 0;
     }
     
     EXTERNC double __syscall GM_ReadAnalogChannel(double Channel)
     {
         return ReadAnalogChannel(Channel);
     }

     EXTERNC double __syscall GM_ReadAllAnalog()
     {
         long iData1,iData2;
         ReadAllAnalog(&iData1,&iData2);
         return ((iData1 & 0xFFFF) << 16 )|( iData2 & 0xFFFF);
     }
     EXTERNC double __syscall GM_OutputAnalogChannel(double Channel, double Data)
     {
         OutputAnalogChannel(Channel, Data);
         return 0;
     }
     EXTERNC double __syscall GM_OutputAllAnalog(double Data1, double Data2)
     {
         OutputAllAnalog(Data1, Data2);
         return 0;
     }
     EXTERNC double __syscall GM_ClearAnalogChannel(double Channel)
     {
         ClearAnalogChannel(Channel);
         return 0;
     }
     EXTERNC double __syscall GM_ClearAllAnalog()
     {
         ClearAllAnalog();
         return 0;
     }
     EXTERNC double __syscall GM_SetAnalogChannel(double Channel)
     {
         SetAnalogChannel(Channel);
         return 0;
     }
     EXTERNC double __syscall GM_SetAllAnalog()
     {
         SetAllAnalog();
         return 0;
     }
     EXTERNC double __syscall GM_WriteAllDigital(double Data)
     {
         WriteAllDigital(Data); 
         return 0;
     }
     EXTERNC double __syscall GM_ClearDigitalChannel(double Channel)
     {
         ClearDigitalChannel(Channel);
         return 0;
     }
     EXTERNC double __syscall GM_ClearAllDigital()
     {
         ClearAllDigital();
         return 0;
     }
     EXTERNC double __syscall GM_SetDigitalChannel(double Channel)
     {
         SetDigitalChannel(Channel);
         return 0;
     }
     EXTERNC double __syscall GM_SetAllDigital()
     {
         SetAllDigital();
         return 0;
     }
     EXTERNC double __syscall GM_ReadDigitalChannel(double Channel)
     {
         return ReadDigitalChannel(Channel);
     }
     EXTERNC double __syscall GM_ReadAllDigital()
     {
         return ReadAllDigital();
     }
     EXTERNC double __syscall GM_ReadCounter(double CounterNr)
     {
         return ReadCounter(CounterNr);
     }
     EXTERNC double __syscall GM_ResetCounter(double CounterNr)
     {
         ResetCounter(CounterNr);
         return 0;
     }
     EXTERNC double __syscall GM_SetCounterDebounceTime(double CounterNr, double DebounceTime)
     {
         SetCounterDebounceTime(CounterNr,DebounceTime);
         return 0;
     }
     EXTERNC double __syscall GM_SearchDevices()
     {
         if (SearchDevices != NULL)
         {
             return (*SearchDevices) ();
         };
         return -1;
     }
     EXTERNC double __syscall GM_SetCurrentDevice(double Address)
     {
         if (SetCurrentDevice != NULL)
         {
             return (*SetCurrentDevice) (Address);
         };
         return OpenDevice(Address);
     }
     EXTERNC double __syscall GM_Version()
     {
         if (Version != NULL)
         {
             (*Version) ();
             return 0;
         };
         return -1;
     }