Enttec USBDMXProと通信しようとしています。主にDMXを受信します。
彼らはここでVisualC++バージョンをリリースしましたが、Obj-cに変換するために何をすべきかについて少し困惑しています。Enttecは、「Mac用のFTDIライブラリを使用してPROに話しかけ、D2XXプログラミングガイドを参照してデバイスを開いて話しかけます」と書いています。Objective-Cのサンプルアプリはありますか?Enttec DMX USB Proと通信する簡単な方法はありますか?
Enttec USBDMXProと通信しようとしています。主にDMXを受信します。
彼らはここでVisualC++バージョンをリリースしましたが、Obj-cに変換するために何をすべきかについて少し困惑しています。Enttecは、「Mac用のFTDIライブラリを使用してPROに話しかけ、D2XXプログラミングガイドを参照してデバイスを開いて話しかけます」と書いています。Objective-Cのサンプルアプリはありますか?Enttec DMX USB Proと通信する簡単な方法はありますか?
私は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アプリケーション内に配置できます。彼らは、ダウンロード可能なD2XXプログラマーズガイドで詳細に説明されている標準のFTDID2XXコマンドを使用しているように見えます。
これは、これらのデバイスの1つに接続するために使用される、アプリケーションの1つから持ち上げたコードです。
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で断続的なクラッシュを引き起こすことがわかりました。
上記のケース以外にも、FTDIがCライブラリで提供する他の機能についてはD2XXプログラミングガイドを参照してください。繰り返しになりますが、デバイスの製造元から提供されたサンプルから適切なコードに移動する必要があります。
同様の問題が発生しました(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);
}
これが他の誰かに役立つことを願っています!