3

I have the following program, which uses the ftd2xx library to write a byte to an USB device and then reads the reply.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include "../ftd2xx.h"

void fatal (const char *format,...) {
  va_list argp;
  fprintf(stderr, "FATAL: ");
  va_start(argp, format);
  vfprintf(stderr, format, argp);
  va_end(argp);
  fprintf(stderr, "\n");
  exit(3);
}

int main(int argc, char* argv[]) {
  int pid = fork();
  if (pid > 0) { //replace with: if (pid == 0) {
    FT_STATUS ftStatus;
    printf("before FT_OpenEx\n");
    FT_HANDLE ftHandle;  
    if ((ftStatus = FT_OpenEx("DA011SCV", FT_OPEN_BY_SERIAL_NUMBER, &ftHandle)) != FT_OK) fatal("FT_OpenEx failed");
    printf("before FT_Write\n");
    uint8_t buffer[1];
    buffer[0] = 0x55;
    DWORD bytesWritten;
    if ((ftStatus = FT_Write(ftHandle, buffer, sizeof(buffer), &bytesWritten)) != FT_OK) fatal("FT_Write failed");
    printf("before FT_Read\n");
    DWORD bytesRead;
    if ((ftStatus = FT_Read(ftHandle, buffer, 1, &bytesRead)) != FT_OK) fatal("FT_Read failed");
    if (bytesRead > 0) {
      printf("FT_Read data=0x%02X\n", buffer[0]);
    } else {
      printf("FT_Read no data\n");
    }
    printf("before FT_Close\n");
    if ((ftStatus = FT_Close(ftHandle)) != FT_OK) fatal("FT_Close failed");
    printf("press Enter to exit\n");
  }
  getchar();
  exit(0);
}

The code as shown produces this output:

//Output if (pid > 0)
before FT_OpenEx
before FT_Write
before FT_Read
FT_Read data=0x55
before FT_Close
press Enter to exit

However, if I change the condition of the first if from (pid > 0) to (pid == 0), i.e. if I do the USB communication in the child process, then the program hangs in the FT_Read() function and the output is:

//Output if (pid == 0)
before FT_OpenEx
before FT_Write
before FT_Read

Why does this happen?

Some details:

  • The USB chip in the device is a FT240X with factory setting.
  • The USB device acts like an echo: every byte it receives is immediately sent back.
  • I checked with a protocol analyzer that the transmitted byte values are correct.
  • The ftd2xx library version is 1.1.12.
ttt13579
  • 31
  • 3
  • What happens if, after you fork, you execve your image again (and detect this condition so you don't do it endlessly)? It sounds like some sort of global state maintained by the FTDI library (poke through header files?) is being corrupted by the fork. – antiduh Feb 02 '16 at 22:15
  • What platform are you seeing this behavior on? –  Feb 02 '16 at 22:18
  • @antiduh After `execve()` in the child the `FT_Read()` worked. I will try this approach, although I'd still like to know why a simple `fork()` doesn't work. – ttt13579 Feb 03 '16 at 18:52
  • @duskwuff It's OpenSuse/Linux, the output of `uname -a` is: `Linux linux 3.11.6-4-desktop #1 SMP PREEMPT Wed Oct 30 18:04:56 UTC 2013 (e6d4a27) x86_64 x86_64 x86_64 GNU/Linux`. – ttt13579 Feb 03 '16 at 18:54
  • @tom - there's a bug in the FTDI library code. They're setting up some sort of global state, perhaps a mutex. Read the manpage on fork, a lot of state isn't reset the same when you fork. – antiduh Feb 03 '16 at 19:11

2 Answers2

4

What you're describing sounds like there's a bug in the ftd2xx library -- it's possible that the library performs some initialization when it's loaded which becomes invalid when the process ID changes.

The ftd2xx library is closed-source and distributed under a license that prohibits reverse-engineering, so there's no way for me to tell for sure what's going on. You may want to try using an open-source FTDI library, such as libftdi, instead.

1

The library is strange - I had the same problem. For me it helped to load the library dynamically after calling the fork(). Check this post https://stackoverflow.com/a/7626550/907675 to see how to dynamically load a function from a library.

Community
  • 1
  • 1
Honza Vojtěch
  • 685
  • 1
  • 7
  • 27
  • I'm running into the same problem with libftd2xx in a project I'm working on, and want to know: did you have to invoke each and every D2XX function dynamically, by creating a pointer to it with `dlsym` first? Or was it sufficient just to invoke that once and then call the functions by name? – soapergem Mar 26 '17 at 14:09
  • @SoaperGEM: I think when you load the library dynamically, you have to call each function via its pointer retrieved by dlsym (and that's the way how I did it). If you would call the functions by name, you would use the library in static manner. By the way, the ftd2xx is quite rubbish on Linux, I finally had to switch to libftdi and I am much happier. – Honza Vojtěch Mar 29 '17 at 15:08
  • Ok thanks very much. I will check out libftdi; it sounds like quite a few people prefer that one over the official library! – soapergem Mar 29 '17 at 15:22