2012-12-26 20 views
7

Sto provando a comunicare con Enttec USB DMX Pro. Principalmente ricevendo DMX.Comunicazione FTDI con dispositivo USB - Obiettivo C

Hanno rilasciato una versione di Visual C++ here, ma sono un po 'perplesso su cosa fare per convertire in Obj-c. Enttec scrive "Parla al PRO usando la libreria FTDI per Mac e consulta la guida alla programmazione D2XX per aprire e parlare con il dispositivo." Esistono app di esempio per Objective-C? C'è un modo semplice per comunicare con Enttec DMX USB Pro?

+0

I "driver" di cui parli [sembrano disponibili sul sito FTDI Chip] (http://www.ftdichip.com/Drivers/VCP.htm) e non conosco alcun "Obiettivo" C "app di esempio specifiche, ma se è possibile qualsiasi codice di esempio MacOS che utilizza C o C++, dovrebbe funzionare anche all'interno di un'app Objective C. –

+0

Sì, stavo cercando di trovare un codice di esempio MacOS in C o C++ .... – objectiveccoder001

+0

Non sono sicuro che sia d'aiuto, ma potrebbe valere la pena dare un'occhiata a [ofxDmx] (https://github.com/kylemcdonald/ofxDmx) o il blocco cinder [DMXusbPro] (https://github.com/q-depot/Cinder-DMXusbPro) –

risposta

25

Ho svolto una notevole quantità di lavoro con i chip FTDI sul Mac, quindi posso fornire una piccola panoramica qui. Ho usato le varianti a canale singolo e doppio canale dei loro convertitori USB-seriale, e si comportano tutti allo stesso modo.

FTDI dispone sia dei driver Virtual COM Port che creano una porta COM seriale sul sistema che rappresenta la connessione seriale collegata al proprio chip, sia le loro librerie di comunicazione diretta D2XX. Vorresti lavorare con quest'ultimo, che è can be downloaded from their site for various platforms.

Le librerie D2XX per Mac sono disponibili in versione standalone .dylib (l'ultima è libftd2xx.1.2.2.dylib) o una nuova libreria statica che hanno iniziato la spedizione di recente. In questo pacchetto sono inclusi anche i file di intestazione appropriati (ftd2xx.h e WinTypes.h).

Nel progetto Xcode, aggiungere il .dylib come framework da collegare e aggiungere i file ftd2xx.h, WinTypes.h e ftd2xx.cfg al progetto. Nella fase di compilazione Copia gruppi combinati, assicurarsi che libftd2xx.1.2.2.dylib e ftd2xx.cfg siano presenti in quella fase. Potrebbe anche essere necessario per regolare il percorso relativo che questa libreria si aspetta, in modo che esso possa funzionare all'interno del vostro pacco app, quindi potrebbe essere necessario eseguire il seguente comando su di esso dalla riga di comando:

install_name_tool -id @executable_path/../Frameworks/libftd2xx.1.2.2.dylib libftd2xx.1.2.2.dylib 

Una volta che il progetto è tutto configurato correttamente, ti consigliamo di importare le intestazioni FTDI:

#import "ftd2xx.h" 

e iniziare a connettersi ai dispositivi seriali. L'esempio a cui ti colleghi nella tua domanda ha un campione C++ scaricabile che mostra come comunicano con il loro dispositivo. Puoi trasferire quasi tutto il codice C utilizzato e metterlo all'interno della tua applicazione Objective-C. Sembra che stiano usando i comandi standard FTDI D2XX, descritti dettagliatamente nel download D2XX Programmer's Guide.

Questo è un codice che ho sollevato da una delle mie applicazioni, utilizzato per la connessione a uno di questi dispositivi:

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

disconnessione è abbastanza semplice:

 ftdiPortStatus = FT_Close(*electronicsPointer); 
     *electronicsPointer = 0; 
     if (ftdiPortStatus != FT_OK) 
     { 
      return; 
     } 

Scrivendo al dispositivo seriale è quindi abbastanza facile:

__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 è un NSData istanza e runOnMainQueueWithoutDeadlocking() è semplicemente a convenience function I use to guarantee execution of a block on the main queue).

Si può leggere di byte non elaborati dalla interfaccia seriale usando qualcosa come il seguente:

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

Al termine di cui sopra, response sarà un'istanza NSData contenente i byte che hai letto dal porto.

Inoltre, suggerirei di accedere sempre al dispositivo FTDI dal thread principale. Anche se dicono che supportano l'accesso multithread, ho scoperto che ogni tipo di accesso non-main-thread (anche gli accessi esclusivi garantiti da un singolo thread) causano arresti intermittenti sul Mac.

Oltre ai casi descritti sopra, è possibile consultare la guida alla programmazione D2XX per le altre funzioni fornite da FTDI nella propria libreria C. Di nuovo, dovresti semplicemente spostare il codice appropriato dagli esempi che ti sono stati forniti dal produttore del tuo dispositivo.

+0

WOW! Grazie mille, Brad. Questo è incredibilmente utile. +1 di sicuro! Apprezzo molto la risposta – objectiveccoder001

+0

@ Brad: informazioni davvero fantastiche. Sto provando lo stesso con J2DXX, iam in grado di comunicare con il dispositivo e recuperare le informazioni sul dispositivo e così via. Ma sono solo perplesso perché non vedo un metodo per dire in quale blocco della scheda mifare dovrei scrivere un dato o così via ... questa api non leggerà o scriverà sulla scheda mifare, giusto? solo per il dispositivo di lettura –

+0

@inba - Non ho idea di come funzioni MIFARE, ma quanto sopra è solo come si inviano e si ricevono i dati tramite i convertitori USB-seriale FTDI. Avrai bisogno di inviare qualsiasi comando di cui MIFARE ha bisogno da solo. –

0

Ero in esecuzione in un problema simile (cercando di scrivere su EntTec Open DMX utilizzando Objective-C), senza alcun successo. Dopo aver seguito l'ottima risposta di @ Brad, mi sono reso conto che è necessario alternare lo stato BREAK ogni volta che si invia un pacchetto DMX.

Ecco un esempio del mio ciclo in qualche codice di test che invia pacchetti con un ritardo di 20 millisecondi tra i frame.

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

Spero che questo aiuti qualcun altro là fuori!

Problemi correlati