目标C - 与USB设备的通信FTDI(FTDI Communication with USB d

2019-07-17 13:56发布

我试图与Enttec USB DMX专业沟通。 主要接收DMX。

他们发布的Visual C ++版本在这里 ,但我对如何做才能转换为对象-有点难倒。 Enttec写道,“谈谈使用FTDI库的Mac PRO,并参考D2XX编程指南打开,跟我们的设备。” 任何例如,对于Objective-C的应用程式在那里? 是否存在与Enttec DMX USB Pro的沟通一个简单的方法?

Answer 1:

我已经做了在Mac上FTDI芯片工作显著量,这样我就可以在这里提供一些见解。 我用自己的USB转串口转换器的单通道和双通道的变体,它们都具有相同的行为方式。

FTDI既有自己的虚拟COM端口驱动程序,它代表连接到他们的芯片串行连接在系统上创建一个串行COM端口,和他们D2XX直接通信库。 你会希望与后者,这工作可以从他们的网站不同的平台进行下载 。

适用于Mac的D2XX库进来一个独立的名为.dylib(最近一次是libftd2xx.1.2.2.dylib)或他们最近开始出货新的静态库。 包括在包会,你需要(ftd2xx.h和WinTypes.h)以及相应的头文件。

在Xcode项目,添加名为.dylib为框架,链接,且该ftd2xx.h,WinTypes.h和ftd2xx.cfg文件添加到您的项目。 在您的副本捆绑的框架搭建阶段,确保libftd2xx.1.2.2.dylib和ftd2xx.cfg存在于这个阶段。 您可能还需要调整,这个库的预期,相对路径,以便它在您的应用程序包内的功能,所以你可能需要在命令行对其运行下面的命令:

install_name_tool -id @executable_path/../Frameworks/libftd2xx.1.2.2.dylib libftd2xx.1.2.2.dylib

将项目的所有配置正确,你将要导入的FTDI标题:

#import "ftd2xx.h"

并开始连接到您的串行设备。 你在你的问题链接例子有一个可下载的C ++示例,演示他们是如何传达到他们的设备。 你可以把整个几乎所有的使用存在的C代码,并把它放在你的Objective-C的应用程序中。 他们只是看起来是使用标准的FTDI D2XX命令,将对其进行详细的下载中描述D2XX程序员指南 。

这是一些代码,我从我的应用程序,用于连接到这些设备中的一个一个解除:

    DWORD numDevs = 0;
    // Grab the number of attached devices
    ftdiPortStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
    if (ftdiPortStatus != FT_OK)
    {
        NSLog(@"Electronics error: Unable to list devices");
        return;
    }

    // Find the device number of the electronics
    for (int currentDevice = 0; currentDevice < numDevs; currentDevice++)
    {
        char Buffer[64];
        ftdiPortStatus = FT_ListDevices((PVOID)currentDevice,Buffer,FT_LIST_BY_INDEX|FT_OPEN_BY_DESCRIPTION); 
        NSString *portDescription = [NSString stringWithCString:Buffer encoding:NSASCIIStringEncoding];
        if ( ([portDescription isEqualToString:@"FT232R USB UART"]) && (usbRelayPointer != NULL))
        {           
            // Open the communication with the USB device
            ftdiPortStatus = FT_OpenEx("FT232R USB UART",FT_OPEN_BY_DESCRIPTION,usbRelayPointer);
            if (ftdiPortStatus != FT_OK)
            {
                NSLog(@"Electronics error: Can't open USB relay device: %d", (int)ftdiPortStatus);
                return;
            }
            //Turn off bit bang mode
            ftdiPortStatus = FT_SetBitMode(*usbRelayPointer, 0x00,0);
            if (ftdiPortStatus != FT_OK)
            {
                NSLog(@"Electronics error: Can't set bit bang mode");
                return;
            }
            // Reset the device
            ftdiPortStatus = FT_ResetDevice(*usbRelayPointer);
            // Purge transmit and receive buffers
            ftdiPortStatus = FT_Purge(*usbRelayPointer, FT_PURGE_RX | FT_PURGE_TX);
            // Set the baud rate
            ftdiPortStatus = FT_SetBaudRate(*usbRelayPointer, 9600);
            // 1 s timeouts on read / write
            ftdiPortStatus = FT_SetTimeouts(*usbRelayPointer, 1000, 1000);      
            // Set to communicate at 8N1
            ftdiPortStatus = FT_SetDataCharacteristics(*usbRelayPointer, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); // 8N1
            // Disable hardware / software flow control
            ftdiPortStatus = FT_SetFlowControl(*usbRelayPointer, FT_FLOW_NONE, 0, 0);
            // Set the latency of the receive buffer way down (2 ms) to facilitate speedy transmission
            ftdiPortStatus = FT_SetLatencyTimer(*usbRelayPointer,2); 
            if (ftdiPortStatus != FT_OK)
            {
                NSLog(@"Electronics error: Can't set latency timer");
                return;
            }                   
        }
    }

断开相当简单:

        ftdiPortStatus = FT_Close(*electronicsPointer);
        *electronicsPointer = 0;
        if (ftdiPortStatus != FT_OK)
        {
            return;
        }

写串行设备则相当容易:

    __block DWORD bytesWrittenOrRead;
    unsigned char * dataBuffer = (unsigned char *)[command bytes];
    //[command getBytes:dataBuffer];
    runOnMainQueueWithoutDeadlocking(^{
        ftdiPortStatus = FT_Write(electronicsCommPort, dataBuffer, (DWORD)[command length], &bytesWrittenOrRead);
    });

    if((bytesWrittenOrRead < [command length]) || (ftdiPortStatus != FT_OK))
    {
        NSLog(@"Bytes written: %d, should be:%d, error: %d", bytesWrittenOrRead, (unsigned int)[command length], ftdiPortStatus);

        return NO;
    }

command是一个NSData实例, runOnMainQueueWithoutDeadlocking()仅仅是一个方便的功能我使用,以保证在块的执行在主队列 )。

你可以阅读使用类似下面的串行接口原始字节:

NSData *response = nil;
DWORD numberOfCharactersToRead = size;
__block DWORD bytesWrittenOrRead;

__block unsigned char *serialCommunicationBuffer = malloc(numberOfCharactersToRead);        

runOnMainQueueWithoutDeadlocking(^{
    ftdiPortStatus = FT_Read(electronicsCommPort, serialCommunicationBuffer, (DWORD)numberOfCharactersToRead, &bytesWrittenOrRead);
});

if ((bytesWrittenOrRead < numberOfCharactersToRead) || (ftdiPortStatus != FT_OK))
{
    free(serialCommunicationBuffer);
    return nil;
}

response = [[NSData alloc] initWithBytes:serialCommunicationBuffer length:numberOfCharactersToRead];
free(serialCommunicationBuffer);

在上述的结束, response将包含你从端口读取的字节中一个NSData实例。

另外,我建议你应该总是在主线程访问FTDI设备。 即使他们说,他们支持多线程访问,我发现,任何一种非主线程访问(甚至从单个线程保证排他性访问)导致Mac上间歇性崩溃。

除了我上面描述的情况,你可以咨询D2XX编程指南其他功能FTDI提供了他们的C库。 再次,你应该只需要到相应的代码已经由设备制造商提供给您的样品动过。



Answer 2:

我也陷入了类似的问题(试图写入使用Objective-C的EntTec打开DMX),没有任何成功。 以下@布拉德的伟大的答案后,我意识到,你还需要在每次发送DMX包时切换破发状态。

这是我在与帧之间的20毫秒的延迟将数据包发送一些测试代码回路的例子。

while (1) {

    FT_SetBreakOn(usbRelayPointer);
    FT_SetBreakOff(usbRelayPointer);

    ftdiPortStatus = FT_Write(usbRelayPointer, startCode, 1, &bytesWrittenOrRead);
    ftdiPortStatus = FT_Write(usbRelayPointer, dataBuffer, (DWORD)[command length], &bytesWrittenOrRead);
    usleep(20000);
}

希望这可以帮助别人那里!



文章来源: FTDI Communication with USB device - Objective C