D2XX by FTDI with Purebasic 5.60+

Just starting out? Need help? Post your questions and find answers here.
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

Hi there,

I'm trying to use a driver on my PC (WinXP + Purebasic x86) and start with the following code :

Code: Select all

Enumeration
  #FT_OK
  #FT_INVALID_HANDLE
  #FT_DEVICE_NOT_FOUND
  #FT_DEVICE_NOT_OPENED
  #FT_IO_ERROR
  #FT_INSUFFICIENT_RESOURCES
  #FT_INVALID_PARAMETER
  #FT_INVALID_BAUD_RATE
  
  #FT_DEVICE_NOT_OPENED_FOR_ERASE
  #FT_DEVICE_NOT_OPENED_FOR_WRITE
  #FT_FAILED_TO_WRITE_DEVICE
  #FT_EEPROM_READ_FAILED
  #FT_EEPROM_WRITE_FAILED
  #FT_EEPROM_ERASE_FAILED
  #FT_EEPROM_NOT_PRESENT
  #FT_EEPROM_NOT_PROGRAMMED
  #FT_INVALID_ARGS
  #FT_NOT_SUPPORTED
  #FT_OTHER_ERROR 
EndEnumeration

#FT_OPEN_BY_SERIAL_NUMBER = 1
#FT_OPEN_BY_DESCRIPTION   = 2
#FT_OPEN_BY_LOCATION      = 4


Import "ftd2xx.lib"
FT_Close (al) As "_FT_Close @ 4"
FT_ClrDtr (al) As "_FT_ClrDtr @ 4"
FT_ClrRts (al) As "_FT_ClrRts @ 4"
FT_CreateDeviceInfoList (al) As "_FT_CreateDeviceInfoList @ 4"
FT_CyclePort (al) As "_FT_CyclePort @ 4"
FT_EE_Program (al, bl) As "_FT_EE_Program @ 8"
FT_EE_ProgramEx (al, bl, cl, dl, el, fl) As "_FT_EE_ProgramEx @ 24"
FT_EE_Read (al, bl) As "_FT_EE_Read @ 8"
FT_EE_ReadConfig (al, bl, cl) As "_FT_EE_ReadConfig @ 12"
FT_EE_ReadEcc (al, bl, cl) As "_FT_EE_ReadEcc @ 12"
FT_EE_ReadEx (al, bl, cl, dl, el, fl) As "_FT_EE_ReadEx @ 24"
FT_EE_UARead (al, bl, cl, dl) As "_FT_EE_UARead @ 16"
FT_EE_UASize (al, bl) As "_FT_EE_UASize @ 8"
FT_EE_UAWrite (al, bl, cl) As "_FT_EE_UAWrite @ 12"
FT_EE_WriteConfig (al, bl, cl) As "_FT_EE_WriteConfig @ 12"
FT_EraseEE (al) As "_FT_EraseEE @ 4"
FT_GetBitMode (al, bl) As "_FT_GetBitMode @ 8"
FT_GetComPortNumber (al, bl) As "_FT_GetComPortNumber @ 8"
FT_GetDeviceInfo (al, bl, cl, dl, el, fl) As "_FT_GetDeviceInfo @ 24"
FT_GetDeviceInfoDetail (al, bl, cl, dl, el, fl, gl, hl) As "_FT_GetDeviceInfoDetail @ 32"
FT_GetDeviceInfoList (al, bl) As "_FT_GetDeviceInfoList @ 8"
FT_GetDriverVersion (al, bl) As "_FT_GetDriverVersion @ 8"
FT_GetEventStatus (al, bl) As "_FT_GetEventStatus @ 8"
FT_GetLatencyTimer (al, bl) As "_FT_GetLatencyTimer @ 8"
FT_GetLibraryVersion (al) As "_FT_GetLibraryVersion @ 4"
FT_GetModemStatus (al, bl) As "_FT_GetModemStatus @ 8"
FT_GetQueueStatus (al, bl) As "_FT_GetQueueStatus @ 8"
FT_GetQueueStatusEx (al, bl) As "_FT_GetQueueStatusEx @ 8"
FT_GetStatus (al, bl, cl, dl) As "_FT_GetStatus @ 16"
FT_IoCtl (al, bl, cl, dl, el, fl, gl, hl) As "_FT_IoCtl @ 32"
FT_ListDevices (al, bl, cl) As "_FT_ListDevices @ 12"
FT_Open (al, bl) As "_FT_Open @ 8"
FT_OpenEx (al, bl, cl) As "_FT_OpenEx @ 12"
FT_Purge (al, bl) As "_FT_Purge @ 8"
FT_Read (al, bl, cl, dl) As "_FT_Read @ 16"
FT_ReadEE (al, bl, cl) As "_FT_ReadEE @ 12"
FT_Reload (al, bl) As "_FT_Reload @ 8"
FT_Rescan () As "_FT_Rescan @ 0"
FT_ResetDevice (al) As "_FT_ResetDevice @ 4"
FT_ResetPort (al) As "_FT_ResetPort @ 4"
FT_RestartInTask (al) As "_FT_RestartInTask @ 4"
FT_SetBaudRate (al, bl) As "_FT_SetBaudRate @ 8"
FT_SetBitMode (al, bl, cl) As "_FT_SetBitMode @ 12"
FT_SetBreakOff (al) As "_FT_SetBreakOff @ 4"
FT_SetBreakOn (al) As "_FT_SetBreakOn @ 4"
FT_SetChars (al, bl, cl, dl, el) As "_FT_SetChars @ 20"
FT_SetDataCharacteristics (al, bl, cl, dl) As "_FT_SetDataCharacteristics @ 16"
FT_SetDeadmanTimeout (al, bl) As "_FT_SetDeadmanTimeout @ 8"
FT_SetDivisor (al, bl) As "_FT_SetDivisor @ 8"
FT_SetDtr (al) As "_FT_SetDtr @ 4"
FT_SetEventNotification (al, bl, cl) As "_FT_SetEventNotification @ 12"
FT_SetFlowControl (al, bl, cl, dl) As "_FT_SetFlowControl @ 16"
FT_SetLatencyTimer (al, bl) As "_FT_SetLatencyTimer @ 8"
FT_SetResetPipeRetryCount (al, bl) As "_FT_SetResetPipeRetryCount @ 8"
FT_SetRts (al) As "_FT_SetRts @ 4"
FT_SetTimeouts (al, bl, cl) As "_FT_SetTimeouts @ 12"
FT_SetUSBParameters (al, bl, cl) As "_FT_SetUSBParameters @ 12"
FT_SetWaitMask (al, bl) As "_FT_SetWaitMask @ 8"
FT_StopInTask (al) As "_FT_StopInTask @ 4"
FT_W32_CancelIo (al) As "_FT_W32_CancelIo @ 4"
FT_W32_ClearCommBreak (al) As "_FT_W32_ClearCommBreak @ 4"
FT_W32_ClearCommError (al, bl, cl) As "_FT_W32_ClearCommError @ 12"
FT_W32_CloseHandle (al) As "_FT_W32_CloseHandle @ 4"
FT_W32_CreateFile (al, bl, cl, dl, el, fl, gl) As "_FT_W32_CreateFile @ 28"
FT_W32_EscapeCommFunction (al, bl) As "_FT_W32_EscapeCommFunction @ 8"
FT_W32_GetCommMask (al, bl) As "_FT_W32_GetCommMask @ 8"
FT_W32_GetCommModemStatus (al, bl) As "_FT_W32_GetCommModemStatus @ 8"
FT_W32_GetCommState (al, bl) As "_FT_W32_GetCommState @ 8"
FT_W32_GetCommTimeouts (al, bl) As "_FT_W32_GetCommTimeouts @ 8"
FT_W32_GetLastError (al) As "_FT_W32_GetLastError @ 4"
FT_W32_GetOverlappedResult (al, bl, cl, dl) As "_FT_W32_GetOverlappedResult @ 16"
FT_W32_PurgeComm (al, bl) As "_FT_W32_PurgeComm @ 8"
FT_W32_ReadFile (al, bl, cl, dl, el) As "_FT_W32_ReadFile @ 20"
FT_W32_SetCommBreak (al) As "_FT_W32_SetCommBreak @ 4"
FT_W32_SetCommMask (al, bl) As "_FT_W32_SetCommMask @ 8"
FT_W32_SetCommState (al, bl) As "_FT_W32_SetCommState @ 8"
FT_W32_SetCommTimeouts (al, bl) As "_FT_W32_SetCommTimeouts @ 8"
FT_W32_SetupComm (al, bl, cl) As "_FT_W32_SetupComm @ 12"
FT_W32_WaitCommEvent (al, bl, cl) As "_FT_W32_WaitCommEvent @ 12"
FT_W32_WriteFile (al, bl, cl, dl, el) As "_FT_W32_WriteFile @ 20"
FT_WaitOnMask (al, bl) As "_FT_WaitOnMask @ 8"
FT_Write (al, bl, cl, dl) As "_FT_Write @ 16"
FT_WriteEE (al, bl, cl) As "_FT_WriteEE @ 12"
EndImport

Define LibraryVer.l
Define Result.i
Define FT_Handle.i
Define ComPort.i
OpenConsole("FTDI driver Test")
Result = FT_GetLibraryVersion (@LibraryVer)
PrintN("Result = "+Str(Result) + "       Version "+Hex(LibraryVer))

Result = FT_OpenEx ("Interface USB -> Compteur", #FT_OPEN_BY_DESCRIPTION, @FT_Handle)
Result = FT_GetComPortNumber (FT_Handle, @ComPort)
Result = FT_Close(FT_Handle)
PrintN("Port = COM"+Str(ComPort))
p$=Input()
Unfortunately, when I try to compile it, I've got an ASM error :
Purebasic.asm [18]:
extrn _FT_Close @ 4
error: extra characters on line.
I'm unable to understand what it means and how to correct it. I've tried to comment each lines containing FT_Close, then the same message occurs with _FT_GetComPortNumber @ 8

Could someone help me ?
Thanks :wink:

Edit : by the way, source for my code is http://forums.purebasic.com/german/view ... 64#p294455
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

Try ImportC or use the dll:

Code: Select all

Global.i FTD2xx_dll
#SPI_DLL_PATH$        = "c:\windows\system32\"
#SPI_DLL_FTD2XX$      = "ftd2xx.dll"
;;FTD2XX_APIFT_STATUS WINAPI FT_Open(int deviceNumber,FT_HANDLE *pHandle);
Prototype.l FT_Open(deviceNumber.l,*pHandle_l)
      FTD2xx_dll = OpenLibrary(#PB_Any, #SPI_DLL_PATH$ + #SPI_DLL_FTD2XX$)
      If FTD2xx_dll
        Global FT_Open.FT_Open = GetFunction(FTD2xx_dll, "FT_Open")
        ;etc...
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

Waouh, not the same job for me (and my level)... but thanks a lot a lot to have done a big part of the work)
Any idea why import and importC aren't working right ?
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

Any PC you want to run your code, must have FTD2XX.DLL and hardware drivers installed and operational so just use the DLL. The PB Import(C) code may be constructed correctly and fail if the drivers are not installed. Or, the Import(C) lib you reference may not be intended for C calls and is more .NET or C++. This is why I just use the DLL and also check its version prior to running.
The prototypes are identical(minus the decorations @xx) to the import statements for each function, so just search and replace them as you need. Also, use a DLL browser like Depends to inspect the FTD2XX.DLL exports.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

However, I'm not sure to be able to use this form :
1) I try to open the dll file ?
FTD2xx_dll = OpenLibrary(#PB_Any, #SPI_DLL_PATH$ + #SPI_DLL_FTD2XX$)
If FTD2xx_dll

2) I create all my functions needed ?
Prototype.l FT_Open(deviceNumber.l,*pHandle_l)
Global FT_Open.FT_Open = GetFunction(FTD2xx_dll, "FT_Open")
;etc...

Please correct me if I'm wrong...
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

You must declare your Prototypes before using them.
;;FTD2XX_APIFT_STATUS WINAPI FT_GetLibraryVersion(LPDWORD lpdwVersion);
Prototype.l FT_GetLibraryVersion(*lpdwVersion_l)
Then Open the library.
FTD2xx_dll = OpenLibrary(#PB_Any, #SPI_DLL_PATH$ + #SPI_DLL_FTD2XX$)
Then get a function from the library.
Global FT_GetLibraryVersion.FT_GetLibraryVersion = GetFunction(FTD2xx_dll, "FT_GetLibraryVersion")
Then if all that is ok, you can call the functions.
FT_GetLibraryVersion(@ftdver_l)
Debug ftdver_l
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

I hope my last question, because the following line disturb me :

Code: Select all

Global FT_GetLibraryVersion.FT_GetLibraryVersion = GetFunction(FTD2xx_dll, "FT_GetLibraryVersion")
Why do you write twice time the same function "FT_GetLibraryVersion.FT_GetLibraryVersion" ? one is for prototype (the first or the second) and the other ?

Thanks a lot to take your time to answer me... :wink: :) :)
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: D2XX by FTDI with Purebasic 5.60+

Post by Helle »

What´s your hardware? I have for fun a FTDI UM232H and a LED-strip WS2801. This is code for tests and a "running light", 64-bit-version (no problem to convert in 32, comments in german):

Code: Select all

OutputBuffer.q
OutputBuffer1.q              ;für "schwarz"
InputBuffer.q
ftHandle.l
NumBytesToSend.l
NumBytesRead.l
NumInputBuffer.l
ftStatus.l
numDevs.l
BytesToWrite.l
BytesWritten.l
ClockDivisor.l = 29          ;60/((1+29)*2) (MHz) = 1Mhz

AnzLED.l = 32                ;anpassen!

R.a
G.a
B.a

DLLOK = OpenLibrary(0, "ftd2xx64.dll") ;64-Bit-Version laden

If DLLOK
  Prototype.i ProtoFT_1(V1l.l)         ;für die 1-Parameter-Funktionen
  CreateDeviceInfoList_FT.ProtoFT_1 = GetFunction(0, "FT_CreateDeviceInfoList")
  Close_FT.ProtoFT_1                = GetFunction(0, "FT_Close")
  ResetDevice_FT.ProtoFT_1          = GetFunction(0, "FT_ResetDevice")

  Prototype.i ProtoFT_2(V1l.l, V2l.l)  ;für die 2-Parameter-Funktionen
  Open_FT.ProtoFT_2                 = GetFunction(0, "FT_Open")
  GetQueueStatus_FT.ProtoFT_2       = GetFunction(0, "FT_GetQueueStatus")
  SetLatencyTimer_FT.ProtoFT_2      = GetFunction(0, "FT_SetLatencyTimer")

  Prototype.i ProtoFT_3(V1l.l, V2l.l, V3l.l)   ;für die 3-Parameter-Funktionen
  SetUSBParameters_FT.ProtoFT_3     = GetFunction(0, "FT_SetUSBParameters")      
  SetTimeouts_FT.ProtoFT_3          = GetFunction(0, "FT_SetTimeouts") 
  SetBitMode_FT.ProtoFT_3           = GetFunction(0, "FT_SetBitMode")

  Prototype.i ProtoFT_4(V1l.l, V2l.l, V3l.l, V4l.l)   ;für die 4-Parameter-Funktionen
  Write_FT.ProtoFT_4                = GetFunction(0, "FT_Write")
  Read_FT.ProtoFT_4                 = GetFunction(0, "FT_Read")

  Prototype.i ProtoFT_5(V1l.l, V2l.l, V3l.l, V4l.l, V5l.l)   ;für die 5-Parameter-Funktionen
  SetChars_FT.ProtoFT_5             = GetFunction(0, "FT_SetChars")


  ftStatus = CreateDeviceInfoList_FT(@numDevs); : Debug ftStatus : Debug numDevs
  CDIL$ = "CreateDeviceInfoList: "
  If ftStatus = 0 And numDevs > 0
    Ergebnis$ = CDIL$ + "O.K." + #LFCR$ + Str(numDevs) + " Device(s) gefunden!" + #LFCR$
    MessageRequester("Ergebnisse FT232H", Ergebnis$)
  Else 
    Ergebnis$ = CDIL$ + "Kein Device gefunden! Ende!"
    CloseLibrary(0)
    MessageRequester("Ergebnisse FT232H", Ergebnis$)
    End
  EndIf

  OutputBuffer = AllocateMemory(1024)
  OutputBuffer1 = AllocateMemory(1024) ;für LEDs "aus" (schwarz)      
  InputBuffer = AllocateMemory(1024)


    ftStatus = Open_FT(0, @ftHandle) : Debug ftStatus : Debug ftHandle ;0=Device-Nr.1
    Ergebnis$ + "Handle: " + Str(ftHandle) + #LFCR$ 

;Configure FTDI Port For MPSSE Use
    ftStatus = ResetDevice_FT(ftHandle) : Debug "ResetDevice = " + Str(ftStatus)
    ftStatus = GetQueueStatus_FT(ftHandle, @NumInputBuffer) : Debug ftStatus : Debug "Im Buffer2: " + Str(NumInputBuffer)
    ftStatus = SetUSBParameters_FT(ftHandle, $FFFF, $FFFF) : Debug ftStatus
    ftStatus = SetChars_FT(ftHandle, 0, 0, 0, 0) : Debug ftStatus
    ftStatus = SetTimeouts_FT(ftHandle, 0, 3000) : Debug ftStatus
    ftStatus = SetLatencyTimer_FT(ftHandle, 1) : Debug ftStatus
    ftStatus = SetBitMode_FT(ftHandle, 0, 0) : Debug ftStatus  ;Reset Controller
    ftStatus = SetBitMode_FT(ftHandle, 0, 2) : Debug ftStatus  ;Enable MPSSE mode

Delay(50)

;Enable internal loop-back
    PokeA(OutputBuffer, $84)
    BytesToWrite = 1;NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben loop-back: " + Str(BytesWritten)
    ;Ergebnis$ + "Geschriebe Bytes für SPI_Enable : " + Str(BytesWritten) + #LFCR$

;Synchronize the MPSSE by sending a bogus opcode (0xAB),
;The MPSSE will respond with "Bad Command" (0xFA) followed by the bogus opcode itself.
    PokeA(OutputBuffer, $AB)
    BytesToWrite = 1;NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben Bad Command: " + Str(BytesWritten)
;Delay(100)


NumBytesRead = 0
While NumBytesRead <> 2
ftStatus = GetQueueStatus_FT(ftHandle, @NumInputBuffer) : Debug ftStatus : Debug "Im Buffer3: " + Str(NumInputBuffer)
ftStatus = Read_FT(ftHandle, InputBuffer, NumInputBuffer, @NumBytesRead) 
ftStatus = GetQueueStatus_FT(ftHandle, @NumInputBuffer) : Debug ftStatus : Debug "Im Buffer : " + Str(NumInputBuffer)
Wend
Debug Hex(PeekA(InputBuffer))     ;$FA 
Debug Hex(PeekA(InputBuffer + 1)) ;$AB

;Disable internal loop-back
    PokeA(OutputBuffer, $85)
    BytesToWrite = 1;NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben loop-back: " + Str(BytesWritten)

;MPSSE Setup
;Configure the MPSSE settings For JTAG
;Multple commands can be sent To the MPSSE With one FT_Write
    NumBytesToSend = 0
    PokeA(OutputBuffer + NumBytesToSend, $8A)  ;Use 60MHz master clock (disable divide by 5)
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, $97)  ;Turn off adaptive clocking (may be needed for ARM)
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, $8D)  ;Disable three-phase clocking
    NumBytesToSend + 1
    BytesToWrite = NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben Configure the MPSSE: " + Str(BytesWritten)

;Set TCK frequency
    NumBytesToSend = 0
    PokeA(OutputBuffer + NumBytesToSend, $86)  ;Command to set clock divisor
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, ClockDivisor & $FF)         ;Set 0xValueL of clock divisor
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, (ClockDivisor >> 8) & $FF)  ;Set 0xValueH of clock divisor
    NumBytesToSend + 1
    BytesToWrite = NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben TCK frequency: " + Str(BytesWritten)

;// Set initial states of the MPSSE Interface
;// - low byte, both pin directions And output values
;// Pin name   Signal     Direction    Config    Initial   State Config
;// ADBUS0     TCK/SK       output        1        high        1         Bit0
;// ADBUS1     TDI/DO       output        1        low         0
;// ADBUS2     TDO/DI       input         0                    0
;// ADBUS3     TMS/CS       output        1        high        1
;// ADBUS4     GPIOL0       output        1        low         0
;// ADBUS5     GPIOL1       output        1        low         0
;// ADBUS6     GPIOL2       output        1        high        1
;// ADBUS7     GPIOL3       output        1        high        1         Bit7
;                                                             C9         Wert des Bytes
;Set initial states of the MPSSE interface
    NumBytesToSend = 0
    PokeA(OutputBuffer + NumBytesToSend, $80)  ;Configure data bits low-byte of MPSSE port
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, $09)  ;$C9    Initial state config above
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, $0B)  ;$FB    Direction config above
    NumBytesToSend + 1
    BytesToWrite = NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben initial states1: " + Str(BytesWritten)


    ;SPI_Enable
;    NumBytesToSend = 0
;    For i = 0 To 4                               ;one 0x80 command can keep 0.2us, do 5 times to stay in this situation for 1µs
;      PokeA(OutputBuffer + NumBytesToSend, $80)  ;GPIO command for ADBUS
;      NumBytesToSend + 1
;      PokeA(OutputBuffer + NumBytesToSend, $08)  ;set CS high, MOSI and SCL low
;      NumBytesToSend + 1
;      PokeA(OutputBuffer + NumBytesToSend, $0B)  ;bit3:CS, bit2:MISO, bit1:MOSI, bit0:SCK
;      NumBytesToSend + 1
;    Next
;;Debug NumBytesToSend
;    BytesToWrite = NumBytesToSend
;    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten); : Debug ftStatus : Debug "Geschrieben1: " + Str(BytesWritten)
;    Ergebnis$ + "Geschriebe Bytes für SPI_Enable : " + Str(BytesWritten) + #LFCR$

;// Set initial states of the MPSSE Interface
;// - high byte, both pin directions And output values
;// Pin name   Signal   Direction   Config Initial   State Config
;// ACBUS0     GPIOH0     input         0                  0
;// ACBUS1     GPIOH1     input         0                  0
;// ACBUS2     GPIOH2     input         0                  0
;// ACBUS3     GPIOH3     input         0                  0
;// ACBUS4     GPIOH4     input         0                  0
;// ACBUS5     GPIOH5     input         0                  0
;// ACBUS6     GPIOH6     input         0                  0
;// ACBUS7     GPIOH7     input         0                  0
    NumBytesToSend = 0
    PokeA(OutputBuffer + NumBytesToSend, $82)  ;Configure data bits low-byte of MPSSE port
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, 0)  ;
    NumBytesToSend + 1
    PokeA(OutputBuffer + NumBytesToSend, $0)  ;
    NumBytesToSend + 1
    BytesToWrite = NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben initial states2: " + Str(BytesWritten)

NumBytesToSend = 0
      PokeA(OutputBuffer + NumBytesToSend, $10)  ;Output on rising clock, no input, MSB first, clock a number of bytes out
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, (AnzLED * 3) - 1)  ;Length L der Daten! -1
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, 0)  ;Length H
      NumBytesToSend + 1

For j = 0 To (AnzLED >> 2) - 1
      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;rot
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $00)  ;grün
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $00)  ;blau
      NumBytesToSend + 1

      PokeA(OutputBuffer + NumBytesToSend, $00)  ;rot
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;grün
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $00)  ;blau
      NumBytesToSend + 1

      PokeA(OutputBuffer + NumBytesToSend, $00)  ;rot
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $00)  ;grün
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;blau
      NumBytesToSend + 1

      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;rot
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;grün
      NumBytesToSend + 1
      PokeA(OutputBuffer + NumBytesToSend, $ff)  ;blau
      NumBytesToSend + 1
Next

    BytesToWrite = NumBytesToSend
    ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben: " + Str(BytesWritten)

    OpenWindow(0, 0, 0, 220, 70, "Test LED-Kette mit FT232_SPI", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    ButtonGadget(0, 10, 10, 200, 20, "LED-Lauf-Licht")
    ButtonGadget(1, 10, 40, 200, 20, "Ende, LEDs aus", #PB_Button_Default)

;alle LEDs aus, OutputBuffer1 ist mit 0 initialisiert!
NumBytesToSend = 0
      PokeA(OutputBuffer1 + NumBytesToSend, $10)  ;Output on rising clock, no input, MSB first, clock a number of bytes out
      NumBytesToSend + 1
      PokeA(OutputBuffer1 + NumBytesToSend, (AnzLED * 3) - 1)  ;Length L der Daten! -1
      NumBytesToSend + 1
      PokeA(OutputBuffer1 + NumBytesToSend, 0)  ;Length H
      NumBytesToSend + 1
;NumBytesToSend = 3
;For j = 0 To (AnzLED * 3) - 1
;  PokeA(OutputBuffer1 + NumBytesToSend, $00)  ;schwarz
;  NumBytesToSend + 1
;Next
BytesToWrite = (AnzLED * 3) + 3
ftStatus = Write_FT(ftHandle, OutputBuffer1, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben!!!: " + Str(BytesWritten)

  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
        Case 0
Repeat

    EventID = WindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
        Case 1
          Break 2
      EndSelect
    EndIf

          PokeA(@B, PeekA(OutputBuffer + (AnzLED * 3) + 2))
          PokeA(@G, PeekA(OutputBuffer + (AnzLED * 3) + 1))
          PokeA(@R, PeekA(OutputBuffer + AnzLED * 3))

For i = 0 To AnzLED - 2
  PokeA(OutputBuffer + (AnzLED * 3) + 2 - (i * 3), PeekA(OutputBuffer + (AnzLED * 3) - 1 - (i * 3)))
  PokeA(OutputBuffer + (AnzLED * 3) + 1 - (i * 3), PeekA(OutputBuffer + (AnzLED * 3) - 2 - (i * 3)))
  PokeA(OutputBuffer + AnzLED * 3 - (i * 3), PeekA(OutputBuffer + (AnzLED * 3) - 3 - (i * 3)))
Next

          PokeA(OutputBuffer + 5, B)
          PokeA(OutputBuffer + 4, G)
          PokeA(OutputBuffer + 3, R)

BytesToWrite = (AnzLED * 3) + 3;NumBytesToSend
ftStatus = Write_FT(ftHandle, OutputBuffer, BytesToWrite, @BytesWritten); : Debug ftStatus

Delay(1000)
ForEver

        Case 1
          Break

      EndSelect
     ElseIf EventID = #PB_Event_CloseWindow
      Break
    EndIf
  ForEver

;alle LEDs aus, s.oben
BytesToWrite = (AnzLED * 3) + 3
ftStatus = Write_FT(ftHandle, OutputBuffer1, BytesToWrite, @BytesWritten) : Debug ftStatus : Debug "Geschrieben: " + Str(BytesWritten)
 

  FreeMemory(OutputBuffer)
  FreeMemory(OutputBuffer1)
  FreeMemory(InputBuffer)
  ftStatus = Close_FT(ftHandle) : Debug ftStatus

  CloseLibrary(0)
 Else 
  MessageRequester("Fehler!", "ftd2xx64.dll nicht gefunden!")
  End
EndIf

;MessageRequester("Ergebnisse FT232H", Ergebnis$)
End


;FT_STATUS (DWORD):
 ;FT_OK = 0
 ;FT_INVALID_HANDLE = 1
 ;FT_DEVICE_NOT_FOUND = 2
 ;FT_DEVICE_NOT_OPENED = 3
 ;FT_IO_ERROR = 4
 ;FT_INSUFFICIENT_RESOURCES = 5
 ;FT_INVALID_PARAMETER = 6
 ;FT_INVALID_BAUD_RATE = 7
 ;FT_DEVICE_NOT_OPENED_FOR_ERASE = 8
 ;FT_DEVICE_NOT_OPENED_FOR_WRITE = 9
 ;FT_FAILED_TO_WRITE_DEVICE = 10
 ;FT_EEPROM_READ_FAILED = 11
 ;FT_EEPROM_WRITE_FAILED = 12
 ;FT_EEPROM_ERASE_FAILED = 13
 ;FT_EEPROM_NOT_PRESENT = 14
 ;FT_EEPROM_NOT_PROGRAMMED = 15
 ;FT_INVALID_ARGS = 16
 ;FT_NOT_SUPPORTED = 17
 ;FT_OTHER_ERROR = 18
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

Ok, once you get over this, it will be super easy.
Prototype is different than Type in that it points to a Procedure().
When I define a variable, I have to specify its Type.
Define MyVar.Type
When I define a Prototype and then use it, I have to specify a (Proto)Type.
Prototype.l FT_GetLibraryVersion(*lpdwVersion_l)
Global FT_GetLibraryVersion.FT_GetLibraryVersion = GetFunction(FTD2xx_dll, "FT_GetLibraryVersion")
I could have defined the Prototype as this:
Prototype.l protoFT_GetLibraryVersion(*lpdwVersion_l)
But, that is just too much typing and confusion for me.
I prefer the Prototypes match the function name I have to call.
The 'FT_' prefix is necessary to avoid conflicts with other libraries, since I seldom use modules.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

Thanks for your explanations Skywalk : not totally clear but I've to apply if I want to understand, isn't it ? :D
Thanks for your example Helle : my project is a Teleinfo equipement with two way (need SetBitMode() to switch). Teleinfo is a protocol with powercounter from Enedis provider. :)
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

*yups* :cry:
Maybe I need a little bit more help. The following code isn't working.

Code: Select all

Global.i FTD2xx_dll
#SPI_DLL_PATH$        = "c:\windows\system32\"
#SPI_DLL_FTD2XX$      = "ftd2xx.dll"
;;FTD2XX_APIFT_STATUS WINAPI FT_Open(int deviceNumber,FT_HANDLE *pHandle);
Prototype.l FT_Open(deviceNumber.l,*pHandle_l)
Prototype.l FT_OpenEx(*String_s, dwFlag.w, *pHandle_l)
Prototype.l FT_GetComPortNumber(pHandle.l, ComPort.w)
Prototype.l FT_Close(pHandle.l)

FTD2xx_dll = OpenLibrary(#PB_Any, #SPI_DLL_PATH$ + #SPI_DLL_FTD2XX$)
If FTD2xx_dll
  Global FT_Open.FT_Open           = GetFunction(FTD2xx_dll, "FT_Open")
  Global FT_OpenEx.FT_OpenEx       = GetFunction(FTD2xx_dll, "FT_OpenEx")
  Global FT_Close.FT_Close         = GetFunction(FTD2xx_dll, "FT_Close")
  Global FT_GetComPortNumber.FT_GetComPortNumber = GetFunction(FTD2xx_dll, "FT_GetComPortNumber")
  
  ;etc...
EndIf


Define LibraryVer.l
Define Result.i
Define FT_Handle.i
Define ComPort.i
Define String.s = "Interface USB -> Compteur"

OpenConsole("FTDI driver Test")

Result = FT_OpenEx(*String, #FT_OPEN_BY_DESCRIPTION, @FT_Handle)
Result = FT_GetComPortNumber (FT_Handle, @ComPort)
Result = FT_Close(FT_Handle)
PrintN("Port = COM"+Str(ComPort))
p$=Input()
I feel I commit some mistakes with *String, @String or String.s
FT_OpenEx needs a string as first parameter, Flag.w as second parameter, and return the result in the third parameter.

May I've some advice to do that ? Thanks again.
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

As all things, it will become clear with practice.
I prefer to keep all my code within Procedures.
Mainline code contains Globals, Macro's, Constants, etc. and the code to start the actual app.
Example:
Init()
Main()
Quit()
A bit annoying, but PB does not allow Prototypes defined within a Procedure.
So, they must also be defined in the mainline.
In Helle's mainline code, he defines the prototype immediately before their 1st call.

Code: Select all

Prototype.i ProtoFT_2(V1l.l, V2l.l)  ;für die 2-Parameter-Funktionen
Open_FT.ProtoFT_2 = GetFunction(0, "FT_Open")
Also notice, he changes the Prototype naming. To me, this is unnecessary.
So, this is just a question of style and how you see your code after 6 months away? :)
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: D2XX by FTDI with Purebasic 5.60+

Post by skywalk »

You are missing some Constant definitions in the snippet you posted?

Code: Select all

;;// FT_OpenEx Flags
;;//
#FT_OPEN_BY_SERIAL_NUMBER                         = 1  
#FT_OPEN_BY_DESCRIPTION                           = 2  
#FT_OPEN_BY_LOCATION                              = 4  
If you only have 1 FTD device, then you can use
e = FT_Open(0, @handle)
If you want to pass strings back and forth, that requires an Ascii buffer and more code.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Golfy
User
User
Posts: 97
Joined: Wed Mar 21, 2012 6:10 pm

Re: D2XX by FTDI with Purebasic 5.60+

Post by Golfy »

Yes, only one.
And yes again, the string permit to search for COM port by description.

I prefer to be structured with procedures. My upper code is only a linear draft.

Enum and some constantes have been prepared at the beginning of the code :

Code: Select all

Enumeration
  #FT_OK
  #FT_INVALID_HANDLE
  #FT_DEVICE_NOT_FOUND
  #FT_DEVICE_NOT_OPENED
  #FT_IO_ERROR
  #FT_INSUFFICIENT_RESOURCES
  #FT_INVALID_PARAMETER
  #FT_INVALID_BAUD_RATE
  
  #FT_DEVICE_NOT_OPENED_FOR_ERASE
  #FT_DEVICE_NOT_OPENED_FOR_WRITE
  #FT_FAILED_TO_WRITE_DEVICE
  #FT_EEPROM_READ_FAILED
  #FT_EEPROM_WRITE_FAILED
  #FT_EEPROM_ERASE_FAILED
  #FT_EEPROM_NOT_PRESENT
  #FT_EEPROM_NOT_PROGRAMMED
  #FT_INVALID_ARGS
  #FT_NOT_SUPPORTED
  #FT_OTHER_ERROR 
EndEnumeration

#FT_OPEN_BY_SERIAL_NUMBER = 1
#FT_OPEN_BY_DESCRIPTION   = 2
#FT_OPEN_BY_LOCATION      = 4
Post Reply