objective-c - FTDI 与 USB 设备的通信 - Objective C

标签 objective-c ftdi dmx512

我正在尝试与 Enttec USB DMX Pro 进行通信。主要接收DMX。

他们发布了 Visual C++ 版本 here ,但我对如何转换为 Obj-c 有点困惑。 Enttec 写道,“使用适用于 Mac 的 FTDI 库与 PRO 对话,并引用 D2XX 编程指南打开并与设备对话。”那里有 Objective-C 的示例应用程序吗?有没有一种简单的方法可以与 Enttec DMX USB Pro 进行通信?

最佳答案

我已经在 Mac 上对 FTDI 芯片进行了大量工作,因此我可以在这里提供一些见解。我使用过他们的 USB 串行转换器的单 channel 和双 channel 变体,它们的行为方式都相同。

FTDI 有他们的虚拟 COM 端口驱动程序,它在您的系统上创建一个串行 COM 端口,代表连接到他们芯片的串行连接,还有他们的 D2XX 直接通信库。您将要使用后者,即 can be downloaded from their site for various platforms .

用于 Mac 的 D2XX 库以独立的 .dylib(最新的是 libftd2xx.1.2.2.dylib)或他们最近开始发布的新静态库提供。该包中还包含您需要的相应头文件(ftd2xx.h 和 WinTypes.h)。

在您的 Xcode 项目中,添加 .dylib 作为要链接的框架,并将 ftd2xx.h、WinTypes.h 和 ftd2xx.cfg 文件添加到您的项目中。在您的 Copy Bundled Frameworks 构建阶段,确保 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 header :

#import "ftd2xx.h"

并开始连接到您的串行设备。您在问题中链接到的示例有一个可下载的 C++ 示例,显示了它们如何与设备通信。您可以将那里使用的几乎所有 C 代码都带过来,并将其放入您的 Objective-C 应用程序中。他们只是看起来正在使用标准的 FTDI D2XX 命令,这些命令在可下载的 D2XX Programmer's Guide 中有详细描述。 .

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

    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() 只是 a convenience function I use to guarantee execution of a block on the main queue )。

您可以使用如下方式从串行接口(interface)读取原始字节:

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 库中提供的其他函数。同样,您应该只需要从您的设备制造商提供给您的示例中移出适当的代码。

关于objective-c - FTDI 与 USB 设备的通信 - Objective C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14035084/

相关文章:

java - 将大于 127 的值存储在字节数组中

iphone - 每30秒UILocalNotification

ios - Objective-C中基于触摸的图像处理

c++ - 通过 D2XX 库或 OPENCV 捕获相机(USB)

c++ - 共享库和静态库的用法区别

Delphi UDPClient 示例 -> ArtNet 通信和解析器

ios - 如何为禁用用户交互的 subview 实现 longPressGestureRecognizer?

objective-c - 如何统计一个cocoa应用程序的启动时间?

c++ - Unresolved external 错误 - 使用 FTD2XX.h 的 Visual C++

c++ - Arduino ISR—— vector 的多种定义