2012-12-26 159 views
7

我正在嘗試與Enttec USB DMX Pro進行通信。主要接收DMX。FTDI與USB設備通信 - 目標C

他們發佈了一個Visual C++版本here,但我有點難以應付如何轉換爲Obj-c。 Enttec寫道:「使用適用於Mac的FTDI庫與PRO交談,並參考D2XX編程指南打開並與設備對話。」 Objective-C的任何示例應用程序都在那裏?有沒有一種簡單的方法與Enttec DMX USB Pro進行通信?

+0

您所說的「司機」[看起來可以在FTDI Chip站點上找到](http://www.ftdichip.com/Drivers/VCP.htm),我不知道任何「目標C「特定的示例應用程序,但是如果您可以使用任何使用C或C++的MacOS示例代碼,那麼它們也應該可以在Objective C應用程序中使用。 –

+0

是的,我試圖找到一個在C或C++的MacOS示例代碼.... – objectiveccoder001

+0

不知道它是否有幫助,但可能值得看看[ofxDmx](https://github.com/kylemcdonald/ofxDmx)或[DMXusbPro](https://github.com/q-depot/Cinder-DMXusbPro)煤渣塊 –

回答

25

我在Mac上用FTDI芯片做了大量的工作,所以我可以在這裏提供一點見解。我已經使用了他們的USB串行轉換器的單通道和雙通道變體,並且它們的行爲都是一樣的。

FTDI有兩個虛擬串口驅動程序,它們會在系統上創建串行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上導致間歇性崩潰。

除上述情況外,您可以參考D2DI編程指南瞭解FTDI在C庫中提供的其他函數。同樣,您只需要從設備製造商提供給您的樣本中移除適當的代碼即可。

+0

WOW!非常感謝,布拉德。這非常有幫助。肯定+1!我真的很感謝回覆 – objectiveccoder001

+0

@Brad:真的很棒的信息。我正在嘗試與J2DXX相同,iam能夠與設備進行通信並檢索設備信息等。但我只是感到困惑,因爲我沒有看到一種方法來說明mifare卡的哪個區塊應該寫入數據等等...這個api不會讀取或寫入mifare卡嗎?只是讀取器設備 – 2013-02-14 17:03:53

+0

@inba - 我不知道MIFARE是如何工作的,但以上只是您如何通過FTDI USB串行轉換器發送和接收數據。您將需要自行發送MIFARE需要的任何命令。 –

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); 
} 

希望這可以幫助別人!

相關問題