2012-12-26 56 views
7

Tôi đang cố gắng liên lạc với EntX USB DMX Pro. Chủ yếu nhận DMX.Giao tiếp FTDI với thiết bị USB - Mục tiêu C

Họ phát hành phiên bản Visual C++ here, nhưng tôi hơi bối rối về những việc cần làm để chuyển đổi thành Obj-c. Enttec viết, "Nói chuyện với PRO bằng cách sử dụng thư viện FTDI cho Mac, và tham khảo hướng dẫn lập trình D2XX để mở và nói chuyện với thiết bị." Có ứng dụng ví dụ nào cho Objective-C không? Có cách nào dễ dàng để giao tiếp với EntX DMX USB Pro không?

+0

"Trình điều khiển" bạn đang nói về [có vẻ sẵn có tại trang FTDI Chip] (http://www.ftdichip.com/Drivers/VCP.htm) và tôi không biết bất kỳ mục tiêu nào " C "các ứng dụng mẫu cụ thể, nhưng nếu bạn có thể sử dụng bất kỳ mã mẫu MacOS nào sử dụng C hoặc C++, thì nó cũng sẽ hoạt động trong ứng dụng Objective C. –

+0

Vâng, tôi đã cố gắng tìm một mã mẫu MacOS trong C hoặc C++ .... – objectiveccoder001

+0

Không chắc chắn nếu nó giúp, nhưng có thể đáng xem [ofxDmx] (https://github.com/kylemcdonald/ofxDmx) hoặc khối kết dính [DMXusbPro] (https://github.com/q-depot/Cinder-DMXusbPro) –

Trả lời

25

Tôi đã thực hiện một số lượng đáng kể công việc với các chip FTDI trên máy Mac, vì vậy tôi có thể cung cấp một chút thông tin chi tiết tại đây. Tôi đã sử dụng các biến thể kênh đơn và kênh đôi của bộ chuyển đổi nối tiếp USB và tất cả chúng đều hoạt động theo cùng một cách.

FTDI có cả trình điều khiển cổng COM ảo, tạo cổng COM nối tiếp trên hệ thống của bạn đại diện cho kết nối nối tiếp được gắn với chip và thư viện truyền thông trực tiếp D2XX của chúng. Bạn sẽ muốn làm việc với cái sau, trong đó can be downloaded from their site for various platforms.

Thư viện D2XX dành cho máy Mac có một tệp .dylib độc lập (mới nhất là libftd2xx.1.2.2.dylib) hoặc một thư viện tĩnh mới mà chúng bắt đầu giao hàng gần đây. Bao gồm trong gói đó sẽ là các tập tin tiêu đề thích hợp bạn cần (ftd2xx.h và WinTypes.h) là tốt.

Trong dự án Xcode của bạn, thêm .dylib làm khuôn khổ để liên kết và thêm tệp ftd2xx.h, WinTypes.h và ftd2xx.cfg vào dự án của bạn. Trong giai đoạn xây dựng Bản dựng khung được sao chép của bạn, hãy đảm bảo rằng libftd2xx.1.2.2.dylib và ftd2xx.cfg có mặt trong giai đoạn đó. Bạn cũng có thể cần phải điều chỉnh đường dẫn tương đối mà thư viện này mong đợi, để thư viện hoạt động trong gói ứng dụng của bạn, vì vậy bạn có thể cần phải chạy lệnh sau dựa vào dòng lệnh:

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

Sau khi dự án được cấu hình đúng cách, bạn sẽ muốn nhập các tiêu đề FTDI:

#import "ftd2xx.h" 

và bắt đầu kết nối với thiết bị nối tiếp của bạn. Ví dụ bạn liên kết đến trong câu hỏi của bạn có mẫu C++ có thể tải xuống cho biết cách họ liên lạc với thiết bị của họ. Bạn có thể mang theo hầu như tất cả mã C được sử dụng ở đó và đặt nó trong ứng dụng Objective-C của bạn. Họ chỉ xem xét việc sử dụng các lệnh FTDI D2XX tiêu chuẩn, được mô tả chi tiết trong phạm vi có thể tải xuống D2XX Programmer's Guide.

Đây là một số mã mà tôi đã nâng lên từ một trong những ứng dụng của tôi, sử dụng để kết nối với một trong những thiết bị này:

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

Ngắt kết nối khá đơn giản:

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

Viết vào thiết bị nối tiếp sau đó khá dễ dàng:

__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 là một NSData và runOnMainQueueWithoutDeadlocking() chỉ đơn thuần là a convenience function I use to guarantee execution of a block on the main queue).

Bạn có thể đọc byte thô từ giao diện nối tiếp sử dụng giống như sau:

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

Vào cuối những điều trên, response sẽ là một ví dụ NSData chứa các byte bạn đã đọc từ cổng.

Ngoài ra, tôi khuyên bạn nên luôn truy cập thiết bị FTDI từ chuỗi chính. Mặc dù họ nói rằng họ hỗ trợ truy cập đa luồng, tôi đã tìm thấy rằng bất kỳ loại truy cập không chính-chủ (thậm chí đảm bảo truy cập độc quyền từ một chủ đề duy nhất) gây ra tai nạn liên tục trên máy Mac.

Ngoài các trường hợp tôi đã mô tả ở trên, bạn có thể tham khảo hướng dẫn lập trình D2XX cho các chức năng khác mà FTDI cung cấp trong thư viện C của chúng. Một lần nữa, bạn chỉ cần chuyển qua mã thích hợp từ các mẫu đã được nhà sản xuất thiết bị cung cấp cho bạn.

+0

WOW! Cảm ơn rất nhiều, Brad. Điều này cực kỳ hữu ích. +1 chắc chắn! Tôi thực sự đánh giá cao phản hồi – objectiveccoder001

+0

@ Brad: Thông tin thực sự tuyệt vời. Tôi đang cố gắng như vậy với J2DXX, iam có thể giao tiếp với thiết bị và lấy thông tin thiết bị và vân vân. Nhưng tôi chỉ bối rối vì tôi không thấy một phương pháp để nói trong đó khối của thẻ mifare tôi nên viết một dữ liệu hay như vậy ... api này sẽ không đọc hoặc ghi vào thẻ mifare phải không?, Nhưng chỉ dành cho thiết bị đọc –

+0

@inba - Tôi không biết MIFARE hoạt động như thế nào, nhưng ở trên chỉ là cách bạn gửi và nhận dữ liệu qua bộ chuyển đổi nối tiếp USB FTDI. Bạn sẽ cần gửi bất kỳ lệnh nào mà MIFARE cần một mình. –

0

Tôi đã gặp sự cố tương tự (cố gắng viết cho EntTec Open DMX bằng Objective-C), mà không thành công. Sau khi làm theo câu trả lời tuyệt vời của @ Brad, tôi nhận ra rằng bạn cũng cần phải chuyển đổi trạng thái BREAK mỗi khi bạn gửi gói DMX.

Dưới đây là ví dụ về vòng lặp của tôi trong một số mã thử nghiệm gửi gói tin có độ trễ 20 mili giây giữa các khung.

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

Hy vọng điều này sẽ giúp người khác ra khỏi đó!

Các vấn đề liên quan