我正在尝试与Enttec USB DMX Pro进行通信。主要是接收DMX。
他们发布了一个Visual C ++版本here,但我对如何转换为Obj-c感到有点困惑。 Enttec写道,“使用适用于Mac的FTDI库与PRO交谈,并参考D2XX编程指南打开并与设备通信。” Objective-C的所有示例应用程序都在那里?有没有简单的方法与Enttec DMX USB Pro进行通信?
答案 0 :(得分:25)
我在Mac上使用FTDI芯片做了大量工作,所以我可以在这里提供一点见解。我使用了USB串行转换器的单通道和双通道变体,它们的行为方式相同。
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标题:
#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)。
您可以使用以下内容从串行接口读取原始字节:
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库中提供的其他功能。同样,您只需要移动设备制造商提供给您的样本中的相应代码。
答案 1 :(得分:0)
我遇到了类似的问题(尝试使用Objective-C写入EntTec Open DMX),但没有任何成功。按照@Brad的好答案,我意识到每次发送DMX数据包时都需要切换BREAK状态。
以下是我在某些测试代码中循环的示例,该代码在帧之间发送延迟为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);
}
希望这可以帮助其他人!