我正在尝试与 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/