在Linux / Mono上运行的FTDI D2XX C#.NET包装器 - 触发的SetEventNotification似乎使程序

时间:2016-05-05 17:23:14

标签: c# linux mono ftdi d2xx

我正在努力移植一个现有的,功能强大的C#应用​​程序,它在Windows上使用FTDI D2XX C# .NET wrapper,再到Linux和Mono。 我按照安装Linux D2XX driver的说明进行了操作。当检测到我们在Linux上运行时,我们会在C#.NET包装器中查找并加载Linux驱动程序,而不是Windows驱动程序。

完成这项工作后,我们的许多应用程序代码仍然正常,但似乎在FT_EVENT_RXCHAR事件上触发了使用SetEventNotification函数设置的事件时,应用程序崩溃。

C#应用程序的流程是:

  1. 设置与FTDI设备的通信
  2. 当FTDI设备提供新数据时,将通知SetEventNotification
  3. Ping FTDI设备,让它知道我们已准备就绪,我们想要一些数据
  4. 当收到新数据的通知时(来自使用SetEventNotification),用它做一些事情
  5. 更详细一点:

    • 使用C#包装器进行读取和写入似乎在Linux / Mono上运行良好
      • 首先使用Write对设备进行ping操作,然后执行以下读取操作
    • 使用D2XX程序员指南中提供的示例代码,在Linux上编写的C代码在使用SetEventNotification时不会崩溃
    • (明显的)替代方案,使用C#包装器读取所需的字节数似乎在Linux / Mono上正常工作

    几个问题:

    1. 是否有人使用C#.NET Wrapper处理Linux / Mono上的D2XX驱动程序并遇到此问题?
    2. C#Wrapper的SetEventNotification需要一个EventWaitHandle,然后使用SafeWaitHandle检索本机操作系统句柄。这个问题可能在这里吗?
    3. 非常感谢所提供的任何见解。

      修改

      堆栈跟踪现在附在下面。

      我试图转向轮询方法,但是当我们执行FTDI读取时,似乎可能有一个“框架”的数据未完全写入,我们将在数据中有一个缺口。

      我已经与FTDI联系,寻求有关该问题的一些指导。如果我听到一些可行的话会更新。

      # mono --debug ./CT4USB.exe
      
      Native stacktrace:
      
          mono() [0x49d5fc]
          mono() [0x424a0e]
          /lib/x86_64-linux-gnu/libpthread.so.0(+0x10330) [0x7f3253539330]
          /lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x4) [0x7f3253533404]
          /usr/local/lib/libftd2xx.so(+0x12f52) [0x7f324b9d1f52]
          /usr/local/lib/libftd2xx.so(+0x134f1) [0x7f324b9d24f1]
          /usr/local/lib/libftd2xx.so(processor_thread+0x21b) [0x7f324b9d29bd]
          /lib/x86_64-linux-gnu/libpthread.so.0(+0x8184) [0x7f3253531184]
          /lib/x86_64-linux-gnu/libc.so.6(clone+0x6d) [0x7f325325e37d]
      
      Debug info from gdb:
      
      [New LWP 5654]
      [New LWP 5653]
      [New LWP 5652]
      [New LWP 5645]
      [New LWP 5644]
      [New LWP 5643]
      [New LWP 5642]
      [New LWP 5641]
      [New LWP 5640]
      [New LWP 5639]
      [Thread debugging using libthread_db enabled]
      Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
      0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
      81  ../sysdeps/unix/syscall-template.S: No such file or directory.
        Id   Target Id         Frame 
        11   Thread 0x7f32523ff700 (LWP 5639) "mono" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
        10   Thread 0x7f3252a81700 (LWP 5640) "Finalizer" sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
        9    Thread 0x7f3253efa700 (LWP 5641) "mono" __clock_nanosleep (clock_id=1, flags=1, req=0x7f3253ef9d80, rem=0x7f325326c974 <__clock_nanosleep+132>) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:49
        8    Thread 0x7f324bfff700 (LWP 5642) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
        7    Thread 0x7f324bdfe700 (LWP 5643) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
        6    Thread 0x7f324b9be700 (LWP 5644) "Threadpool work" 0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
        5    Thread 0x7f324b1bd700 (LWP 5645) "Threadpool work" 0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
        4    Thread 0x7f324a7ff700 (LWP 5652) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
        3    Thread 0x7f3249ffe700 (LWP 5653) "Threadpool work" 0x00007f3253538ed9 in __libc_waitpid (pid=5655, stat_loc=0x7f3249ffce4c, options=0) at ../sysdeps/unix/sysv/linux/waitpid.c:40
        2    Thread 0x7f32497fd700 (LWP 5654) "Threadpool work" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
      * 1    Thread 0x7f325405d7c0 (LWP 5638) "mono" 0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
      
      Thread 11 (Thread 0x7f32523ff700 (LWP 5639)):
      #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
      #1  0x00000000005f9aec in ?? ()
      #2  0x00007f3253531184 in start_thread (arg=0x7f32523ff700) at pthread_create.c:312
      #3  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 10 (Thread 0x7f3252a81700 (LWP 5640)):
      #0  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
      #1  0x000000000061de28 in mono_sem_wait ()
      #2  0x00000000005a2076 in ?? ()
      #3  0x00000000005843d3 in ?? ()
      #4  0x0000000000624666 in ?? ()
      #5  0x00007f3253531184 in start_thread (arg=0x7f3252a81700) at pthread_create.c:312
      #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 9 (Thread 0x7f3253efa700 (LWP 5641)):
      #0  __clock_nanosleep (clock_id=1, flags=1, req=0x7f3253ef9d80, rem=0x7f325326c974 <__clock_nanosleep+132>) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:49
      #1  0x00000000006122c8 in ?? ()
      #2  0x0000000000588244 in ?? ()
      #3  0x00000000005843d3 in ?? ()
      #4  0x0000000000624666 in ?? ()
      #5  0x00007f3253531184 in start_thread (arg=0x7f3253efa700) at pthread_create.c:312
      #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 8 (Thread 0x7f324bfff700 (LWP 5642)):
      #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
      #1  0x00000000005fef90 in ?? ()
      #2  0x00000000006117a2 in ?? ()
      #3  0x00000000005840fd in ?? ()
      #4  0x00000000005853e6 in ?? ()
      #5  0x00000000418b9b0e in ?? ()
      #6  0x0000000000000000 in ?? ()
      
      Thread 7 (Thread 0x7f324bdfe700 (LWP 5643)):
      #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
      #1  0x000000000061b982 in ?? ()
      #2  0x0000000000586b58 in ?? ()
      #3  0x00000000005843d3 in ?? ()
      #4  0x0000000000624666 in ?? ()
      #5  0x00007f3253531184 in start_thread (arg=0x7f324bdfe700) at pthread_create.c:312
      #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 6 (Thread 0x7f324b9be700 (LWP 5644)):
      #0  0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
      #1  0x00007f324b9f2a52 in linux_netlink_event_thread_main () from /usr/local/lib/libftd2xx.so
      #2  0x00007f3253531184 in start_thread (arg=0x7f324b9be700) at pthread_create.c:312
      #3  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 5 (Thread 0x7f324b1bd700 (LWP 5645)):
      #0  0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
      #1  0x00007f324b9eb14e in handle_events () from /usr/local/lib/libftd2xx.so
      #2  0x00007f324b9eb569 in libusb_handle_events_timeout_completed () from /usr/local/lib/libftd2xx.so
      #3  0x00007f324b9eb674 in libusb_handle_events_timeout () from /usr/local/lib/libftd2xx.so
      #4  0x00007f324b9c924f in poll_async_libusb () from /usr/local/lib/libftd2xx.so
      #5  0x00007f3253531184 in start_thread (arg=0x7f324b1bd700) at pthread_create.c:312
      #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 4 (Thread 0x7f324a7ff700 (LWP 5652)):
      #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
      #1  0x00007f324b9cf9fe in EventWait () from /usr/local/lib/libftd2xx.so
      #2  0x00007f324b9d2651 in reader_thread () from /usr/local/lib/libftd2xx.so
      #3  0x00007f3253531184 in start_thread (arg=0x7f324a7ff700) at pthread_create.c:312
      #4  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 3 (Thread 0x7f3249ffe700 (LWP 5653)):
      #0  0x00007f3253538ed9 in __libc_waitpid (pid=5655, stat_loc=0x7f3249ffce4c, options=0) at ../sysdeps/unix/sysv/linux/waitpid.c:40
      #1  0x000000000049d689 in ?? ()
      #2  0x0000000000424a0e in ?? ()
      #3  <signal handler called>
      #4  __GI___pthread_mutex_lock (mutex=0x0) at ../nptl/pthread_mutex_lock.c:66
      #5  0x00007f324b9d1f52 in signalSomeEvents () from /usr/local/lib/libftd2xx.so
      #6  0x00007f324b9d24f1 in ProcessBulkInData () from /usr/local/lib/libftd2xx.so
      #7  0x00007f324b9d29bd in processor_thread () from /usr/local/lib/libftd2xx.so
      #8  0x00007f3253531184 in start_thread (arg=0x7f3249ffe700) at pthread_create.c:312
      #9  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 2 (Thread 0x7f32497fd700 (LWP 5654)):
      #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
      #1  0x00007f324b9cf904 in EventWait () from /usr/local/lib/libftd2xx.so
      #2  0x00007f324b9cbfd1 in write_thread () from /usr/local/lib/libftd2xx.so
      #3  0x00007f3253531184 in start_thread (arg=0x7f32497fd700) at pthread_create.c:312
      #4  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      
      Thread 1 (Thread 0x7f325405d7c0 (LWP 5638)):
      #0  0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
      #1  0x00000000005fedfa in ?? ()
      #2  0x000000000061101b in ?? ()
      #3  0x000000000058415e in ?? ()
      #4  0x0000000000585309 in ?? ()
      #5  0x00000000418b3e8d in ?? ()
      #6  0x00000000015de450 in ?? ()
      #7  0x00007ffc9ba9b960 in ?? ()
      #8  0x00007f3253fb8130 in ?? ()
      #9  0x00007f3252400578 in ?? ()
      #10 0x00007f3252400528 in ?? ()
      #11 0x00000000015a41e0 in ?? ()
      #12 0x00000000418b3e07 in ?? ()
      #13 0x00007ffc9ba9b4d0 in ?? ()
      #14 0x00007ffc9ba9b450 in ?? ()
      /build/buildd/gdb-7.7.1/gdb/dwarf2-frame.c:692: internal-error: Unknown CFI encountered.
      A problem internal to GDB has been detected,
      further debugging may prove unreliable.
      Quit this debugging session? (y or n) [answered Y; input not from terminal]
      /build/buildd/gdb-7.7.1/gdb/dwarf2-frame.c:692: internal-error: Unknown CFI encountered.
      A problem internal to GDB has been detected,
      further debugging may prove unreliable.
      Create a core file of GDB? (y or n) [answered Y; input not from terminal]
      
      =================================================================
      Got a SIGSEGV while executing native code. This usually indicates
      a fatal error in the mono runtime or one of the native libraries 
      used by your application.
      =================================================================
      
      Aborted (core dumped)
      

      编辑第二个:

      Mono的SafeWaitHandle的表示和SetEventNotification的预期参数完全不同。因为FTDI D2XX库试图将SafeWaitHandle视为EVENT_HANDLE(在ftd2xx.h头中定义;基本上是pthread_cond_t和pthread_mutex_t),我认为这就是我们崩溃的原因。

      我想我可以继续在FTDI D2XX C#.NET包装器中使用带有libpthread的P / Invoke来执行pthread条件和互斥锁与Mono SafeWaitHandle之间的必要转换。此时,我需要工作的C代码,它将在pdiread_cond_wait上循环并阻塞FTDI D2XX。我还没有让代码工作。如果有人有建议,请在下面列出:

      /*/*
      
      gcc -o SetEventNotification_separate_thread SetEventNotification_separate_thread.c -lpthread -lftd2xx -Wl,-rpath /usr/local/lib
      
      */
      
      #include <stdlib.h>
      #include <pthread.h>
      #include <stdio.h>
      #include <stdint.h>
      #include "../ftd2xx.h"
      
      static FT_HANDLE ft_handle;
      
      
      // Seems like this sort of stuff should have been provided by FTDI
      static const char *ft_errors[] =
      {
          [FT_OK] = "Success",
          [FT_INVALID_HANDLE] = "Invalid device handle",
          [FT_DEVICE_NOT_FOUND] = "Device not found",
          [FT_DEVICE_NOT_OPENED] = "Device not opened",
          [FT_IO_ERROR] = "Input/output error",
          [FT_INSUFFICIENT_RESOURCES] = "Insufficient resources",
          [FT_INVALID_PARAMETER] = "Invalid parameter",
          [FT_INVALID_BAUD_RATE] = "Invalid baud rate",
          [FT_DEVICE_NOT_OPENED_FOR_ERASE] = "Device not opened for erase",
          [FT_DEVICE_NOT_OPENED_FOR_WRITE] = "Device not opened for write",
          [FT_FAILED_TO_WRITE_DEVICE] = "Failed to write device",
          [FT_EEPROM_READ_FAILED] = "EEPROM read failed",
          [FT_EEPROM_WRITE_FAILED] = "EEPROM write failed",
          [FT_EEPROM_ERASE_FAILED] = "EEPROM erase failed",
          [FT_EEPROM_NOT_PRESENT] = "EEPROM not present",
          [FT_EEPROM_NOT_PROGRAMMED] = "EEPROM not programmed",
          [FT_INVALID_ARGS] = "Invalid argument",
          [FT_NOT_SUPPORTED] = "Not supported",
          [FT_OTHER_ERROR] = "Other error"
      };
      
      static const int num_ft_errors = sizeof(ft_errors) / sizeof(ft_errors[FT_OK]);
      static const char *ft_strerror(FT_STATUS ft_status)
      {
          if (ft_status < 0        // Should be impossible because it is unsigned
          || ft_status >= num_ft_errors
          || !ft_errors[ft_status])
          {
          return "Unknown error";
          }
          return ft_errors[ft_status];
      }
      
      static void ft_error_exit(const char *str, FT_STATUS ft_status)
      {
          if (str && *str)
          fprintf(stderr, "%s: %sn", str, ft_strerror(ft_status));
          else
          fprintf(stderr, "%sn", ft_strerror(ft_status));
          exit(1);
      }
      
      static void pthread_error_exit(const char *str, int err)
      {
          if (str && *str)
          fprintf(stderr, "%s: %sn", str, strerror(err));
          else
          fprintf(stderr, "%sn", strerror(err));
          exit(1);
      }
      
      static void std_error_exit(const char *str)
      {
          perror(str);
          exit(1);
      }
      
      // Reader thread function
      static void *reader_func(void *arg)
      {
        FT_STATUS ft_status;
        EVENT_HANDLE eh;
        DWORD chars_in_q;
        char buf[8192];
        int pterr;
      
      
      
        if ((pterr = pthread_mutex_init(&eh.eMutex, NULL)))
          pthread_error_exit("pthread_mutex_init", pterr);
        if ((pterr = pthread_cond_init(&eh.eCondVar, NULL)))
          pthread_error_exit("pthread_cond_init", pterr);
      
        if ((ft_status = FT_SetEventNotification(ft_handle, FT_EVENT_RXCHAR,
                             (PVOID)&eh)) != FT_OK)
        ft_error_exit("FT_SetEventNotification", ft_status);
      
        for (;;)
        {
          printf("at for: chars_in_q: %d\n", chars_in_q);
      
          if ((pterr = pthread_mutex_lock(&eh.eMutex))){
            pthread_error_exit("pthread_mutex_lock", pterr);
            printf("pthread_mutex_lock failed...\n");
          }
          printf("pthread_mutex_lock\n");
          if ((ft_status = FT_GetQueueStatus(ft_handle, &chars_in_q)) != FT_OK)
            ft_error_exit("FT_GetQueueStatus", ft_status);
          printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
      //    while (chars_in_q == 0)
      //    {
            printf("<<----------- SetEventNotification pthread_cond_wait --------------->>\n");
            if ((pterr = pthread_cond_wait(&eh.eCondVar, &eh.eMutex)))
              pthread_error_exit("pthread_cond_wait", pterr);
            printf("pthread_cond_wait\n");
            if ((ft_status = FT_GetQueueStatus(ft_handle,
                               &chars_in_q)) != FT_OK)
              ft_error_exit("FT_GetQueueStatus", ft_status);
            printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
      //    }
          if ((pterr = pthread_mutex_unlock(&eh.eMutex)))
            pthread_error_exit("pthread_mutex_unlock", pterr);
      
          printf("pthread_mutex_unlock\n");
      
          while (chars_in_q)
          {
            printf("at while (chars_in_q): chars_in_q: %d\n", chars_in_q);
      
            DWORD len_to_read, len_read;
            ssize_t len_written;
      
            len_to_read = (chars_in_q > sizeof(buf)) ? sizeof(buf) : chars_in_q;
      
            if ((ft_status = FT_Read(ft_handle, (LPVOID)buf,
                         len_to_read, &len_read)) != FT_OK)
              ft_error_exit("FT_Read", ft_status);
            if (!len_read)
            {
              fprintf(stderr, "FT_Read returned no data.n");
              exit(1);
            }
      
            len_written = printf("%s\n", buf);
            printf("len_to_read: %d\n", len_to_read);
            printf("len_read: %d\n", len_read);
      
            chars_in_q -= len_read;
          }
        }
      }
      
      int main(int argc, char *argv[])
      {
        FT_STATUS ft_status;
        DWORD devCount;
        DWORD devIndex = 0; // first device
        DWORD numDevices = 1;
        char serialNumber[64]; // more than enough room!
      
        const unsigned int baudrate = 8000000;
      
        FT_DEVICE_LIST_INFO_NODE * devInfo;
        devInfo = malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevices);
      
        ft_status = FT_CreateDeviceInfoList(&devCount);
      
        if(  ft_status != FT_OK)
        {
          printf("No devices connected!\n");
          exit(-1);
        }
      
        printf("Devices found: %d\n", devCount);
      
        ft_status = FT_ListDevices((PVOID)devIndex, serialNumber, FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
        if (  ft_status == FT_OK)
        {
          // FT_ListDevices OK, serial number is in serialNumber
          printf("Device Serial Number: %s\n", serialNumber);
        }
        else
        {
          // FT_ListDevices failed
        }
      
        ft_status = FT_OpenEx(serialNumber, FT_OPEN_BY_SERIAL_NUMBER, &ft_handle);
      
        printf("after calling FT_OpenEx\n");
      
        if (  ft_status == FT_OK)
        {
          // FT_OpenEx OK, ft_handle not null
          printf("FT_OpenEx succeeded\n");
        }
        else
        {
          printf("FT_OpenEx failed\n");
        }
      
          ft_status = FT_SetBaudRate(ft_handle, baudrate);
      
        if (  ft_status == FT_OK)
        {
          // FT_SetBaudRate OK
          printf("FT_SetBaudRate succeeded\n");
        }
        else
        {
          printf("FT_SetBaudRate failed\n");
        }
      
        ft_status = FT_SetFlowControl(ft_handle, FT_FLOW_RTS_CTS, 0, 0);
      
        if (  ft_status == FT_OK)
        {
          // FT_SetFlowControl OK
          printf("FT_SetFlowControl succeeded\n");
        }
        else
        {
          printf("FT_SetFlowControl failed\n");
        }
      
        // Flush the FTDI's buffers
        if ((ft_status = FT_Purge(ft_handle, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
        ft_error_exit("FT_Purge", ft_status);
      
        // Create reader and writer threads.
        int pterr;
        sigset_t sig_set;
        (void)sigfillset(&sig_set);
        pthread_attr_t ptattr;
        if ((pterr = pthread_attr_init(&ptattr)))
          pthread_error_exit("pthread_attr_init", pterr);
        if ((pterr = pthread_attr_setdetachstate(&ptattr,
                             PTHREAD_CREATE_DETACHED)))
          pthread_error_exit("pthread_attr_setdetachstate", pterr);
        pthread_t reader_id, writer_id;
        if ((pterr = pthread_create(&reader_id, &ptattr, reader_func, NULL)))
        pthread_error_exit("pthread_create reader", pterr);
      
        // Now wait for a signal to terminate us
        int caught_sig;
        if (sigwait(&sig_set, &caught_sig))
        std_error_exit("sigwait");
      
        exit(0);
      }
      
      gcc -o SetEventNotification_separate_thread SetEventNotification_separate_thread.c -lpthread -lftd2xx -Wl,-rpath /usr/local/lib
      
      */
      
      #include <stdlib.h>
      #include <pthread.h>
      #include <stdio.h>
      #include <stdint.h>
      #include "../ftd2xx.h"
      
      static FT_HANDLE ft_handle;
      
      
      // Seems like this sort of stuff should have been provided by FTDI
      static const char *ft_errors[] =
      {
          [FT_OK] = "Success",
          [FT_INVALID_HANDLE] = "Invalid device handle",
          [FT_DEVICE_NOT_FOUND] = "Device not found",
          [FT_DEVICE_NOT_OPENED] = "Device not opened",
          [FT_IO_ERROR] = "Input/output error",
          [FT_INSUFFICIENT_RESOURCES] = "Insufficient resources",
          [FT_INVALID_PARAMETER] = "Invalid parameter",
          [FT_INVALID_BAUD_RATE] = "Invalid baud rate",
          [FT_DEVICE_NOT_OPENED_FOR_ERASE] = "Device not opened for erase",
          [FT_DEVICE_NOT_OPENED_FOR_WRITE] = "Device not opened for write",
          [FT_FAILED_TO_WRITE_DEVICE] = "Failed to write device",
          [FT_EEPROM_READ_FAILED] = "EEPROM read failed",
          [FT_EEPROM_WRITE_FAILED] = "EEPROM write failed",
          [FT_EEPROM_ERASE_FAILED] = "EEPROM erase failed",
          [FT_EEPROM_NOT_PRESENT] = "EEPROM not present",
          [FT_EEPROM_NOT_PROGRAMMED] = "EEPROM not programmed",
          [FT_INVALID_ARGS] = "Invalid argument",
          [FT_NOT_SUPPORTED] = "Not supported",
          [FT_OTHER_ERROR] = "Other error"
      };
      
      static const int num_ft_errors = sizeof(ft_errors) / sizeof(ft_errors[FT_OK]);
      static const char *ft_strerror(FT_STATUS ft_status)
      {
          if (ft_status < 0        // Should be impossible because it is unsigned
          || ft_status >= num_ft_errors
          || !ft_errors[ft_status])
          {
          return "Unknown error";
          }
          return ft_errors[ft_status];
      }
      
      static void ft_error_exit(const char *str, FT_STATUS ft_status)
      {
          if (str && *str)
          fprintf(stderr, "%s: %sn", str, ft_strerror(ft_status));
          else
          fprintf(stderr, "%sn", ft_strerror(ft_status));
          exit(1);
      }
      
      static void pthread_error_exit(const char *str, int err)
      {
          if (str && *str)
          fprintf(stderr, "%s: %sn", str, strerror(err));
          else
          fprintf(stderr, "%sn", strerror(err));
          exit(1);
      }
      
      static void std_error_exit(const char *str)
      {
          perror(str);
          exit(1);
      }
      
      // Reader thread function
      static void *reader_func(void *arg)
      {
        FT_STATUS ft_status;
        EVENT_HANDLE eh;
        DWORD chars_in_q;
        char buf[8192];
        int pterr;
      
      
      
        if ((pterr = pthread_mutex_init(&eh.eMutex, NULL)))
          pthread_error_exit("pthread_mutex_init", pterr);
        if ((pterr = pthread_cond_init(&eh.eCondVar, NULL)))
          pthread_error_exit("pthread_cond_init", pterr);
      
        if ((ft_status = FT_SetEventNotification(ft_handle, FT_EVENT_RXCHAR,
                             (PVOID)&eh)) != FT_OK)
        ft_error_exit("FT_SetEventNotification", ft_status);
      
        for (;;)
        {
          printf("at for: chars_in_q: %d\n", chars_in_q);
      
          if ((pterr = pthread_mutex_lock(&eh.eMutex))){
            pthread_error_exit("pthread_mutex_lock", pterr);
            printf("pthread_mutex_lock failed...\n");
          }
          printf("pthread_mutex_lock\n");
          if ((ft_status = FT_GetQueueStatus(ft_handle, &chars_in_q)) != FT_OK)
            ft_error_exit("FT_GetQueueStatus", ft_status);
          printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
      //    while (chars_in_q == 0)
      //    {
            printf("<<----------- SetEventNotification pthread_cond_wait --------------->>\n");
            if ((pterr = pthread_cond_wait(&eh.eCondVar, &eh.eMutex)))
              pthread_error_exit("pthread_cond_wait", pterr);
            printf("pthread_cond_wait\n");
            if ((ft_status = FT_GetQueueStatus(ft_handle,
                               &chars_in_q)) != FT_OK)
              ft_error_exit("FT_GetQueueStatus", ft_status);
            printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
      //    }
          if ((pterr = pthread_mutex_unlock(&eh.eMutex)))
            pthread_error_exit("pthread_mutex_unlock", pterr);
      
          printf("pthread_mutex_unlock\n");
      
          while (chars_in_q)
          {
            printf("at while (chars_in_q): chars_in_q: %d\n", chars_in_q);
      
            DWORD len_to_read, len_read;
            ssize_t len_written;
      
            len_to_read = (chars_in_q > sizeof(buf)) ? sizeof(buf) : chars_in_q;
      
            if ((ft_status = FT_Read(ft_handle, (LPVOID)buf,
                         len_to_read, &len_read)) != FT_OK)
              ft_error_exit("FT_Read", ft_status);
            if (!len_read)
            {
              fprintf(stderr, "FT_Read returned no data.n");
              exit(1);
            }
      
            len_written = printf("%s\n", buf);
            printf("len_to_read: %d\n", len_to_read);
            printf("len_read: %d\n", len_read);
      
            chars_in_q -= len_read;
          }
        }
      }
      
      int main(int argc, char *argv[])
      {
        FT_STATUS ft_status;
        DWORD devCount;
        DWORD devIndex = 0; // first device
        DWORD numDevices = 1;
        char serialNumber[64]; // more than enough room!
      
        const unsigned int baudrate = 8000000;
      
        FT_DEVICE_LIST_INFO_NODE * devInfo;
        devInfo = malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevices);
      
        ft_status = FT_CreateDeviceInfoList(&devCount);
      
        if(  ft_status != FT_OK)
        {
          printf("No devices connected!\n");
          exit(-1);
        }
      
        printf("Devices found: %d\n", devCount);
      
        ft_status = FT_ListDevices((PVOID)devIndex, serialNumber, FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
        if (  ft_status == FT_OK)
        {
          // FT_ListDevices OK, serial number is in serialNumber
          printf("Device Serial Number: %s\n", serialNumber);
        }
        else
        {
          // FT_ListDevices failed
        }
      
        ft_status = FT_OpenEx(serialNumber, FT_OPEN_BY_SERIAL_NUMBER, &ft_handle);
      
        printf("after calling FT_OpenEx\n");
      
        if (  ft_status == FT_OK)
        {
          // FT_OpenEx OK, ft_handle not null
          printf("FT_OpenEx succeeded\n");
        }
        else
        {
          printf("FT_OpenEx failed\n");
        }
      
          ft_status = FT_SetBaudRate(ft_handle, baudrate);
      
        if (  ft_status == FT_OK)
        {
          // FT_SetBaudRate OK
          printf("FT_SetBaudRate succeeded\n");
        }
        else
        {
          printf("FT_SetBaudRate failed\n");
        }
      
        ft_status = FT_SetFlowControl(ft_handle, FT_FLOW_RTS_CTS, 0, 0);
      
        if (  ft_status == FT_OK)
        {
          // FT_SetFlowControl OK
          printf("FT_SetFlowControl succeeded\n");
        }
        else
        {
          printf("FT_SetFlowControl failed\n");
        }
      
        // Flush the FTDI's buffers
        if ((ft_status = FT_Purge(ft_handle, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
        ft_error_exit("FT_Purge", ft_status);
      
        // Create reader and writer threads.
        int pterr;
        sigset_t sig_set;
        (void)sigfillset(&sig_set);
        pthread_attr_t ptattr;
        if ((pterr = pthread_attr_init(&ptattr)))
          pthread_error_exit("pthread_attr_init", pterr);
        if ((pterr = pthread_attr_setdetachstate(&ptattr,
                             PTHREAD_CREATE_DETACHED)))
          pthread_error_exit("pthread_attr_setdetachstate", pterr);
        pthread_t reader_id, writer_id;
        if ((pterr = pthread_create(&reader_id, &ptattr, reader_func, NULL)))
        pthread_error_exit("pthread_create reader", pterr);
      
        // Now wait for a signal to terminate us
        int caught_sig;
        if (sigwait(&sig_set, &caught_sig))
        std_error_exit("sigwait");
      
        exit(0);
      }
      

      它总是卡在pthread_cond_wait上。任何想法都将不胜感激。

1 个答案:

答案 0 :(得分:0)

再一次没有答案,但我不知道Mono是如何定义的 EventWaitHandle.SafeWaitHandle。

在FTDI for Linux(c)提供的示例中,这是定义

FT_HANDLE ftHandle;  
 FT_STATUS ftStatus; 
 EVENT_HANDLE eh; 
 DWORD EventMask; 

 ftStatus = FT_Open(0, &ftHandle); 
 if(ftStatus != FT_OK) { 
    // FT_Open failed 
    return; 
 } 

 pthread_mutex_init(&eh.eMutex, NULL); 
 pthread_cond_init(&eh.eCondVar, NULL); 

 EventMask = FT_EVENT_RXCHAR | FT_EVENT_MODEM_STATUS; 
 ftStatus = FT_SetEventNotification(ftHandle, EventMask, (PVOID)&eh); 

所以我想知道这是否与SafeWaitHandle

的定义有关