Using d2xx.dll in python with ctypes

1.3k views Asked by At

I'm trying to use d2xx.dll which is a library for interfacing FTDI's USB controller chips. I want to use this library in my python code. I decided to use ctypes library in python to call dll functions. I failed to call function from dll file appropriately and I think I have some problems with variable types that I pass to the functions in the dll library. I am not a professional programmer, so take it easy on me. :D

Here is what tried so far,

import ctypes
from ctypes import *

d2xxdll = ctypes.cdll.LoadLibrary('ftd2xx.dll') #Load the dll library 
d2xxdll.FT_CreateDeviceInfoList.argtypes =[ctypes. c_ulong] # specify function's input type
d2xxdll.FT_CreateDeviceInfoList.restype = ctypes.c_ulong # specify function's return type

numDevs = ctypes.c_ulong()
p_numDevs = POINTER(numDevs)
FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(p_numDevs)

print(FT_STATUS)
print(numDevs)

I am just trying to detect how many D2XX devices are connected with FT_CreateDeviceInfoList() function. FT_CreateDeviceInfoList is described in d2xx.dll documentation page 6. The function has one input parameter which is a pointer to an unsigned long and it returns the state of the USB device. I declare an unsigned long with "numDevs = ctypes.c_ulong()" and declare its pointer in "p_numDevs = POINTER(numDevs)", and I get the following error when I run the code.

Traceback (most recent call last):
  File "C:\Users\asus\Desktop\dokümanlar\Python_Ogren\Ctypes_cll\d2xx_dll.py", line 9, in <module>
    p_numDevs = ctypes.POINTER(numDevs)
TypeError: must be a ctypes type

I also tried using byref to pass the address of numDevs:

import ctypes
from ctypes import *

d2xxdll = ctypes.cdll.LoadLibrary('ftd2xx.dll') #Load the dll library 
d2xxdll.FT_CreateDeviceInfoList.argtypes =[ctypes. c_ulong] # specify function's input type
d2xxdll.FT_CreateDeviceInfoList.restype = ctypes.c_ulong # specify function's return type

numDevs = ctypes.c_ulong()

FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(ctypes.byref(numDevs))

print(FT_STATUS)
print(numDevs)


This time I get the following:

Traceback (most recent call last):
  File "C:\Users\asus\Desktop\dokümanlar\Python_Ogren\Ctypes_cll\d2xx_dll.py", line 10, in <module>
    FT_STATUS = d2xxdll.FT_CreateDeviceInfoList(ctypes.byref(numDevs))
ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type

How should I pass the input parameter? I know there are some wrappers for d2xx.dll in python like pyusb, but for some reason I couldn't got them working. I wrote some C code with d2xx.dll they worked like charm. Right now I am looking for a way to get them working in python.

Thanks in advance.

1

There are 1 answers

0
Mark Tolonen On

The C definition of the function is:

typedef ULONG   FT_STATUS;

FTD2XX_API
FT_STATUS WINAPI FT_CreateDeviceInfoList(
    LPDWORD lpdwNumDevs
);

ctypes has a library of Windows types to help you map them correctly. The parameter type is not a c_ulong but a POINTER(c_ulong). The wintypes module defines LPDWORD correctly as this type. Then you create a DWORD and pass it byref().

Below is a complete wrapper:

import ctypes
from ctypes import wintypes

FT_STATUS = wintypes.ULONG
FT_OK = 0

# Note: WINAPI is __stdcall so if using 32-bit Windows you want WinDLL().
#       Use CDLL() for __cdecl calling convention.
#       On 64-bit Windows there is only one calling convention and either works.
ftd2xx = ctypes.WinDLL('ftd2xx')

_FT_CreateDeviceInfoList = ftd2xx.FT_CreateDeviceInfoList
_FT_CreateDeviceInfoList.argtypes = wintypes.LPDWORD,
_FT_CreateDeviceInfoList.restype = FT_STATUS

def FT_CreateDeviceInfoList():
    num_devs = wintypes.DWORD()
    if _FT_CreateDeviceInfoList(ctypes.byref(num_devs)) != FT_OK:
        raise RuntimeError('failed')
    return num_devs.value