FTDI USB Device Communication - Target C

I am trying to communicate with Enttec USB DMX Pro. Mostly DMX reception.

They released a version of Visual C ++ here , but I'm a bit puzzled by what needs to be done to convert to Obj-c. Enttec writes: "Talk to PRO using the FTDI library for Mac and refer to the D2XX programming guide to open and talk to the device." Any sample applications for Objective-C? Is there an easy way to communicate with Enttec DMX USB Pro?

+7
source share
2 answers

I did a lot of work with FTDI chips on Mac, so I can give a little info here. I used single-channel and two-channel versions of my USB-serial converters, and they all behave the same.

FTDI has both its virtual COM port drivers, which create a serial COM port on your system, representing the serial connection connected to their chip and their direct D2XX libraries. You will want to work with the latter, which can be downloaded from your site for various platforms .

D2XX libraries for Mac come in standalone .dylib format (the last of which is libftd2xx.1.2.2.dylib) or the new static library that they started sending recently. The appropriate header files (ftd2xx.h and WinTypes.h) are included in this package.

In your Xcode project, add .dylib as the framework for the connection and add the files ftd2xx.h, WinTypes.h and ftd2xx.cfg to your project. In the Copy Bundled Frameworks build phase, make sure libftd2xx.1.2.2.dylib and ftd2xx.cfg are present in this phase. You may also need to configure the relative path that this library expects to function in your application bundle, so you may need to run the following command on the command line:

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

Once your project is set up correctly, you will want to import FTDI headers:

 #import "ftd2xx.h" 

and start connecting to your serial devices. The example you refer to in your question has a downloadable C ++ sample that shows how they exchange data with their device. You can use almost all of the C code used there and put it in your Objective-C application. They just want to use the standard FTDI D2XX commands, which are detailed in the downloadable D2XX Programmer Guide .

This is the code I shot from one of my applications used to connect to one of these devices:

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

Disabling is pretty simple:

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

Recording to a serial device is quite simple:

  __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 is an instance of NSData, and runOnMainQueueWithoutDeadlocking() is just a convenience function that I use to guarantee the execution of a block in the main queue ).

You can read the raw bytes from the serial interface using something like the following:

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

At the end of the above, response will be an instance of NSData containing the bytes that you read from the port.

In addition, I suggest that you always access the FTDI device from the main stream. Despite the fact that they say they support multi-threaded access, I found that any access to the non-main thread (even guaranteed exclusive access from one thread) causes intermittent crashes on the Mac.

In addition to the cases described above, you can refer to the D2XX programming guide for other functions provided by FTDI in their C library. Again, you just need to move the appropriate code from the samples that were provided to you by the manufacturer of your device.

+25
source

I had a similar problem (trying to write to EntTec Open DMX using Objective-C) without any success. After @Brad's successful reply, I realized that you also need to switch the BREAK state every time you send a DMX packet.

Here is an example of my loop in some test code that sends packets with a delay of 20 milliseconds between frames.

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

Hope this helps someone else!

0
source

All Articles