Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Linux/Mono上运行的FTDI D2XX C#NET包装器被触发的SetEventNotification似乎会使程序崩溃_C#_Linux_Mono_Ftdi_D2xx - Fatal编程技术网

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

在Linux/Mono上运行的FTDI D2XX C#NET包装器被触发的SetEventNotification似乎会使程序崩溃,c#,linux,mono,ftdi,d2xx,C#,Linux,Mono,Ftdi,D2xx,我正在将一个现有的、功能齐全的C#应用程序移植到Linux和Mono上,该应用程序在Windows上使用。 我已按照安装的说明进行操作。当检测到我们正在Linux上运行时,我们会在C#.NET包装中查找并加载Linux驱动程序,而不是Windows驱动程序 在完成这项工作之后,我们的许多应用程序代码仍然很好,但当在FT_event_RXCHAR事件上触发使用SetEventNotification函数设置的事件时,应用程序似乎崩溃了 C#应用程序的流程是: 设置与FTDI设备的通信 当FTDI设

我正在将一个现有的、功能齐全的C#应用程序移植到Linux和Mono上,该应用程序在Windows上使用。 我已按照安装的说明进行操作。当检测到我们正在Linux上运行时,我们会在C#.NET包装中查找并加载Linux驱动程序,而不是Windows驱动程序

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

C#应用程序的流程是:

  • 设置与FTDI设备的通信
  • 当FTDI设备提供新数据时,将通知SetEventNotification
  • Ping FTDI设备,让它知道我们准备好了,我们需要一些数据
  • 当收到新数据的通知(使用SetEventNotification)时,对其执行一些操作
  • 更详细一点:

    • 在Linux/Mono上,使用C#包装器进行读写似乎可以很好地工作
      • 首先使用写操作ping设备,然后成功执行以下读取操作
    • 使用D2XX程序员指南中提供的示例代码,在Linux上编写的C代码在使用SetEventNotification时不会崩溃
    • (显然)另一种选择是,在Linux/Mono上使用C#包装器读取所需的字节数,这似乎是合适的
    有几个问题:

  • 有没有人在Linux/Mono上使用过D2XX驱动程序的C#NET包装器并遇到过这个问题
  • C#包装器的SetEventNotification需要一个EventWaitHandle,然后它使用SafeWaitHandle检索本机操作系统句柄。问题可能就在这里吗
  • 非常感谢您提供的任何见解

    编辑:

    堆栈跟踪现在附着在下面

    我尝试采用轮询方法,但在执行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--debug./CT4USB.exe
    本机堆栈跟踪:
    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/libftd2x.so(+0x12f52)[0x7f324b9d1f52]
    /usr/local/lib/libftd2x.so(+0x134f1)[0x7f324b9d24f1]
    /usr/local/lib/libftd2x.so(处理器线程+0x21b)[0x7f324b9d29bd]
    /lib/x86_64-linux-gnu/libpthread.so.0(+0x8184)[0x7f325353184]
    /lib/x86_64-linux-gnu/libc.so.6(克隆+0x6d)[0x7f325325e37d]
    来自gdb的调试信息:
    [新LWP 5654]
    [新LWP 5653]
    [新LWP 5652]
    [新LWP 5645]
    [新LWP 5644]
    [新LWP 5643]
    [新LWP 5642]
    [新LWP 5641]
    [新LWP 5640]
    [新LWP 5639]
    [已启用使用libthread_db的线程调试]
    使用主机libthread_db library“/lib/x86_64-linux-gnu/libthread_db.so.1”。
    位于../sysdeps/unix/syscall template.S:81的nanosleep()中的0x00007f325358b9d
    81../sysdeps/unix/syscall template.S:没有这样的文件或目录。
    Id目标Id帧
    11线程0x7f32523ff700(LWP 5639)“mono”pthread_cond_wait@@GLIBC_2.3.2(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
    10线程0x7f3252a81700(LWP 5640)“终结器”sem_wait()位于../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
    9线程0x7f3253efa700(LWP 5641)“mono”时钟纳米睡眠(时钟id=1,标志=1,请求=0x7f3253ef9d80,rem=0x7f325326c974)位于../sysdeps/unix/sysv/linux/clock\u nanosleep.c:49
    8线程0x7f324bfff700(LWP 5642)“线程池工作”pthread_cond_timedwait@@GLIBC_2.3.2(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    7线程0x7f324bdfe700(LWP 5643)“线程池工作”pthread_cond_timedwait@@GLIBC_2.3.2(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    6线程0x7f324b9be700(LWP 5644)“线程池工作”0x00007f3253250fdd位于../sysdeps/unix/syscall template.S:81的轮询()中
    轮询()中的5个线程0x7f324b1bd700(LWP 5645)“线程池工作”0x00007f3253250fdd位于../sysdeps/unix/syscall template.S:81
    4线程0x7f324a7ff700(LWP 5652)“线程池工作”pthread_cond_timedwait@@GLIBC_2.3.2(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    3个线程0x7f3249ffe700(LWP 5653)“线程池工作”0x00007f3253538ed9位于../sysdeps/unix/sysv/linux/waitpid.c:40处的
    2线程0x7f32497fd700(LWP 5654)“线程池工作”pthread_cond_wait@@GLIBC_2.3.2(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
    *1个线程0x7f325405d7c0(LWP 5638)“mono”0x00007F325358B9D位于../sysdeps/unix/syscall template()的nanosleep()中。S:81
    螺纹11(螺纹0x7f32523ff700(LWP 5639)):
    #0 pthread_cond_wait@@GLIBC_2.3.2()位于../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
    #1 0x00000000005f9aec英寸??()
    #在pthread_create.c:312处的start_线程(arg=0x7f32523ff700)中有2个0x00007f3253531184
    #位于../sysdeps/unix/sysv/linux/x86_64/clone.S:111的clone()中的3 0x00007f325325e37d
    螺纹10(螺纹0x7f3252a81700(LWP 5640)):
    #0 sem_wait(),位于../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
    #1 0x000000000061de28在mono_sem_wait()中
    #2 0x00000000005a2076英寸??()
    #3 0x00000000005843d3英寸??()
    #4 0x0000000000624666英寸??()
    #在pthread_create.c:312处的start_线程(arg=0x7f3252a81700)中的5 0x00007f3253531184
    #位于../sysdeps/unix/sysv/linux/x86_64/clone.S:111的clone()中的6 0x00007f325325e37d
    螺纹9(螺纹0x7f3253efa700(LWP 5641)):
    #位于../sysdeps/unix/sysv/linux/clock\u nanosleep.c:49的0个时钟(时钟id=1,标志=1,请求=0x7f3253ef9d80,rem=0x7f325326c974)
    #1 0x00000000006122c8英寸??()
    #2 0x0000
    
    /*/*
    
    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);
    }
    
    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);