Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

DllCall problem controlling LEDs with PacDrive.dll, syntax?


  • Please log in to reply
7 replies to this topic
gwarble
  • Guests
  • Last active:
  • Joined: --
Hey Everyone,

I'm trying to control LEDs with the PacDrive and its PacDrive.dll, but am not having much success. Any help would be greatly appreciated:

PacDrive SDK (.dll) info can be found here: http://www.ultimarc.com/pacdrive.html at the very bottom of the page

From the DLLs readme:
int PacInitialize()

- Initialize all PacDrive and U-HID Devices
- Returns the number of PacDrives and U-HID's on the PC
- They are sorted in order of PacDrive's Version Numbers, then U-HID's PID.

void PacShutdown()

- Shutdown all PacDrive and U-HID Devices
- No return value

bool PacSetLEDStates(int id, USHORT data)

- Sends data to the PacDrive or U-HID specified by id
- Returns true for success and false for failure
- You can use up to 16 PacDrive's and 16 U-HID's (id 0 to id 31). The order they are sorted is PacDrive by Version number first then U-HID by PID.

int PacGetVendorId(int id)
- Returns the Vendor Id of the device specified by id

And here's where i'm stuck:
 If DllCall("PacDrive.dll\PacInitialize")
 {
  MsgBox, % DllCall("PacDrive.dll\PacGetVersionNumber","Int",0) "`n`nErrorLevel:" 
ErrorLevel
 MsgBox, % DllCall("PacDrive.dll\PacSetLEDStates",Int,0,UShort,0xFFFF) "`n`nErrorLevel: " ErrorLevel
 }

So PacInitialize called from ahk is working properly, returning 0 if no devices are found and returning 1 if the device is plugged in.

But the other two functions are returning 0 (ie failure) no matter how i configure the parameters... I know this is hard to diagnose without the actual hardware connected, but am i missing something simple here? The code examples for other languages that are provided with the dll are working properly to control the pacdrive, which tells me the dll and hardware are working properly

thanks in advance!

- gwarble[/url]

gwarble
  • Guests
  • Last active:
  • Joined: --
FYI, here are the example calls from other languages:

VB.NET:
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Runtime.InteropServices

Class PacDrive
    <DllImport("PacDrive.dll", CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Function PacInitialize() As Integer
    End Function

    <DllImport("PacDrive.dll", CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Sub PacShutdown()
    End Sub

    <DllImport("PacDrive.dll", CallingConvention:=CallingConvention.StdCall)> _
    Private Shared Function PacSetLEDStates(ByVal id As Integer, ByVal data As UShort) As Boolean
    End Function

    Public NumDevices As Integer = 0

    Public Sub New()
    End Sub

    Public Function Initialize() As Integer
        NumDevices = PacInitialize()

        Return NumDevices
    End Function

    Public Sub Shutdown()
        For i As Integer = 0 To NumDevices - 1
            SetLEDStates(i, New Boolean() {False, False, False, False, False, False, _
            False, False, False, False, False, False, _
            False, False, False, False})
        Next

        PacShutdown()
    End Sub

    Public Sub SetLEDStates(ByVal id As Integer, ByVal data As UShort)
        PacSetLEDStates(id, data)
    End Sub

    Public Sub SetLEDStates(ByVal id As Integer, ByVal data As Boolean())
        Dim dataSend As UShort = 0

        For i As Integer = 0 To data.Length - 1
            If data(i) Then
                dataSend = dataSend Or CUShort(1 << i)
            End If
        Next


        PacSetLEDStates(id, dataSend)
    End Sub
End Class

VB6:
Private Declare Function PacInitialize Lib "PacDrive" () As Integer
Private Declare Sub PacShutdown Lib "PacDrive" ()
Private Declare Function PacSetLEDStates Lib "PacDrive" (ByVal id As Integer, ByVal data As Integer) As Boolean

Private Sub Command1_Click()
    Dim numdevices As Integer
    
    numdevices = PacInitialize
    
    If numdevices > 0 Then
        PacSetLEDStates 0, &HAAAA
    End If
End Sub

Private Sub Command2_Click()
    PacSetLEDStates 0, 0
    
    PacShutdown
End Sub

C#:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace PacDriveDemo
{
    class PacDrive
    {
        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int PacInitialize();

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern void PacShutdown();

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        [return]
        private static extern bool PacSetLEDStates(int id, ushort data);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int PacGetVendorId(int Id);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int PacGetProductId(int Id);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int PacGetVersionNumber(int Id);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern void PacGetVendorName(int Id, StringBuilder VendorName);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern void PacGetProductName(int Id, StringBuilder ProductName);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern void PacGetSerialNumber(int Id, StringBuilder SerialNumber);

        [DllImport("PacDrive.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern void PacGetDevicePath(int Id, StringBuilder DevicePath);

        public int NumDevices = 0;

        public PacDrive()
        {
        }

        public int Initialize()
        {
            NumDevices = PacInitialize();

            return NumDevices;
        }

        public void Shutdown()
        {
            for(int i=0; i<NumDevices; i++)
                SetLEDStates(i, new bool[] { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false });

            PacShutdown();
        }

        public void SetLEDStates(int Id, ushort Data)
        {
            PacSetLEDStates(Id, Data);
        }

        public void SetLEDStates(int Id, bool[] Data)
        {
            ushort dataSend = 0;

            for (int i=0; i < Data.Length; i++)
                if (Data[i]) dataSend |= (ushort)(1 << i);

            PacSetLEDStates(Id, dataSend);
        }

        public int GetVendorId(int Id)
        {
            return PacGetVendorId(Id);
        }

        public int GetProductId(int Id)
        {
            return PacGetProductId(Id);
        }

        public int GetVersionNumber(int Id)
        {
            return PacGetVersionNumber(Id);
        }

        public string GetVendorName(int Id)
        {
            StringBuilder sb = new StringBuilder(256);

            PacGetVendorName(Id, sb);

            return sb.ToString();
        }

        public string GetProductName(int Id)
        {
            StringBuilder sb = new StringBuilder(256);

            PacGetProductName(Id, sb);

            return sb.ToString();
        }

        public string GetSerialNumber(int Id)
        {
            StringBuilder sb = new StringBuilder(256);

            PacGetSerialNumber(Id, sb);

            return sb.ToString();
        }

        public string GetDevicePath(int Id)
        {
            StringBuilder sb = new StringBuilder(256);

            PacGetDevicePath(Id, sb);

            return sb.ToString();
        }
    }
}

Delphi:
unit SDIMAIN;

interface

uses Windows, Classes, Graphics, Forms, Controls, Menus,
  Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ImgList, StdActns,
  ActnList, ToolWin, SysUtils;

const
  PACDRIVE_MAX_DEVICES : Integer = 16;

type
  TSDIAppForm = class(TForm)
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  PACDRIVEHANDLE = THandle;

Function PacInitialize() : Integer; stdcall; external 'PacDrive.dll';
Procedure PacShutdown() stdcall; external 'PacDrive.dll';
Function PacSetLEDStates(id: Integer; data: Word) : Boolean; stdcall; external 'PacDrive.dll';

var
  SDIAppForm: TSDIAppForm;

implementation

{$R *.dfm}

procedure TSDIAppForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  PacSetLEDStates(0, 0);
  PacShutdown();
end;

procedure TSDIAppForm.FormShow(Sender: TObject);
var
  numdevices: Integer;
begin
  numdevices := PacInitialize();

  if (numdevices > 0) then
  begin
    PacSetLEDStates(0, StrToInt('$AAAA'))
  end;
end;

end.

Thanks again!
- gwarble

  • Guests
  • Last active:
  • Joined: --
DllCall("LoadLibrary",Str,"PacDrive.dll")


gwarble
  • Guests
  • Last active:
  • Joined: --
Thanks for the help.... Its working as expected now... i'll post the working code for reference in case anyone else wants to get one of these working...

For my information (i'm new to ahk and have only used dllcalls for simple things like blat), what makes the "LoadLibrary" necessary? Reading thru the documentation before i posted, i came across this feature but it is only documented as a way to speed up the call (under the performance heading)

- gwarble

engunneer
  • Moderators
  • 9162 posts
  • Last active: Sep 12 2014 10:36 PM
  • Joined: 30 Aug 2005
it can also be used to keep a hardware driver 'alive' in memory. I have used ahk to talk to CNC motion control hardware, and the dll only wants to be loaded once to keep everything active.

if you don't LoadLibrary, then the dll is opened and closed on every call, so the second call is just like forgetting to initialize it, since the initialized call was closed when the other command finished.

Hope this helps.

gwarble
  • Guests
  • Last active:
  • Joined: --
ah, i see

thanks for the explanation... makes total sense

thats funny you mentioned cnc motion control... i'm actually using this for the cnc machine shop where i work... not for direct motion control though, just for machine/network integration (we've got a bunch of VMCs) and machine monitoring/logging/status lights/DNC/etc...

if anyone's interested in getting started with a PacDrive or U-HID using pacdrive.dll, here's a quick and dirty script to flash LEDs 1 and 2 randomly

#SingleInstance Force
#Persistent
#NoEnv
SetWorkingDir, %A_ScriptDir%

 If DllCall("LoadLibrary", "str", "PacDrive.dll")
  If DllCall("PacDrive.dll\PacInitialize")
   DllCall("PacDrive.dll\PacSetLEDStates",Int,0,UShort,3) "`n`nError: " ErrorLevel
 Else
  ExitApp
 SetTimer, ChangeLED, 100
Return

ChangeLED:
 Random, rand, 0, 3
 DllCall("PacDrive.dll\PacSetLEDStates",Int,0,UShort,rand)
Return

Thanks again
- gwarble

RamjetR
  • Members
  • 1 posts
  • Last active: Jun 19 2011 09:19 AM
  • Joined: 29 Apr 2011

ah, i see

if anyone's interested in getting started with a PacDrive or U-HID using pacdrive.dll, here's a quick and dirty script to flash LEDs 1 and 2 randomly

Thanks again
- gwarble


Hi gwarble and engunneer.

You've got no idea how much this post helped me!!! Thankyou so much for sharing your code and knowledge.

Yesterday I didn't know the first thing about ANY scripting language as all of my previous programming is done in Assembly MCU and binary coding. All this higher level stuff with squiggly lines didn't mean anything to me hahaha

Last night I sat down and watched all RaptorX's tutorials, and played with your code gwarble and managed to make it work on my new PacDrive which I'm using to emulate a Sega VR Panel on an old Sega Touring Car DX arcade machine I bought.

My intention is to eventually get the LED's to light the appropiate buttons depending on events in racing games... ie Shift Light, Caution Flags, Fuel warning, Nitrous (for those NFS waahooo games) etc etc...

First thing I needed to do was... well.... learn a programming language - and AutoHotKey seemed like exactly what I need right now. Find some example code and talk to the PacDrive.... Thankyou for the above code... great starting point!

So now I have installed a Simple Gamepad into my cabinet, wired up the buttons and asked AHK to light up each button as it is pressed.

Here is my code and feel free to distrobute and change as you all feel. Please post back here with your updates however so I can learn from your experience aswell as banging my head trying to learn scripting from scratch.

#SingleInstance Force 
#Persistent 
#NoEnv 
SetWorkingDir, %A_ScriptDir% 


; Uses of the PacDrive.dll
; First, Load the Library with DllCall("LoadLibrary", "str", "PacDrive.dll")
; Then Initialize the PacDrive with DllCall("PacDrive.dll\PacInitialize")
; To set the LEDs as a whole use DllCall("PacDrive.dll\PacSetLEDStates",Int,0,UShort,0)   -  Note (integer, pacdrive ID, short integer, decimal value for LEDs)
; To set induvidual LEDs, use DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,0,Int,1)	  -  Note (integer, pacdrive ID, integer, pin0, integer, 1 means ON)
;
; This program, loads the PacDrive.dll (which should be in the same folder as the AHK file you ran) and initializes it.
; Then it will refresh the LED output status for Pin 0 -3 (ie the first 4 LED ports on the PacDrive) after reading what the status of the joystick buttons are
;
; For this program, I used a basic gamepad and wired the buttons to some Arcade LED buttons on my Sega Touring Car Arcade to simulate the Sega VR Buttons.
; My Buttons from left to right are, RED, YELLOW, GREEN and BLUE. It just so happened as I wired them that RED = Joy6, Yellow = Joy8, Green = Joy5 and Blue = Joy7
; Every 100ms the ChangeLED routine is called from the settimer command and it reads a Joy button, checks to see if it's (D) Down and if so, sets the LED port pin 
; to (1) ON. If it is not Down, then it sets the LED port to (0) OFF.
;
; So, in the routine for checking the Joy Buttons, I can also trigger a Keystroke send too. So if you want to reconfigure a Joypad button to a Keystroke... thats's
; where you would put it.
;
; Original code by Gwarble - THANKYOU!!!
;
; Modified for basic Gamepad/Joypad/Joystick indication by Ramjet - Later to be upgraded to Arcade/RaceSim cockpit




If DllCall("LoadLibrary", "str", "PacDrive.dll") 
  If DllCall("PacDrive.dll\PacInitialize") 
   DllCall("PacDrive.dll\PacSetLEDStates",Int,0,UShort,0) "`n`nError: " ErrorLevel
 Else 
  ExitApp 
  SetTimer, ChangeLED, 100
Return 


ChangeLED: 

GetKeyState, state, 1joy6		;Red Button
if state = D
{
	DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,0,Int,1) 
}
else
	{DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,0,Int,0) 
}	

GetKeyState, state, 1joy8		;Yellow Button
if state = D
{
	DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,1,Int,1) 
}
else
	{DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,1,Int,0) 
}

GetKeyState, state, 1joy5		;Green Button
if state = D
{
	DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,2,Int,1) 
}
else
{	
	DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,2,Int,0) 
}

GetKeyState, state, 1joy7		;Blue Button
if state = D
{
	DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,3,Int,1) 
}
else
	{DllCall("PacDrive.dll\PacSetLEDState",Int,0,Int,3,Int,0) 
}

return

The usage for calling the DLL's were the hardest part and trying to figure out the syntax and how to scan the joystick buttons would work and not interferre with the initialising of the dll Gwarble posted.

But hey, for a few hours of watching tutorials and messing with code... it works. All the buttons light when I press the corrosponding gamepad button, and now I have to get my head around Cheat Engine for scanning and reading game memory for pulling out values such as Shift lights, NOS available, etc etc...

Thanks again

Ramjet

David Techer
  • Members
  • 1 posts
  • Last active: Jan 20 2015 12:43 PM
  • Joined: 20 Jan 2015

Hello,

 

I'm french, sorry for my english.

 

I have the "pacdrive usb board". I test your AHK, but nothing blink.

 

Windows 8 x64 with autohotkey 32.

 

What should i do with the "PackDriverSdk" ? Should i copy PacDrive32.dll in c:/windows/system32 ?

 

Can you give me a step-by-step action ?

 

----------------------------------------

 

OK, i found the problem, just copy PacDrive32.dll in the same directory of AHK, and replace "PacDrive.dll" in the ahk by "PacDrive32.dll"

 

SOLVED