无法在Mac OS X上声明使用C + libusb的USB接口

我有一个使用PIC32微控制器构建的复合USB + CDC设备,我正在尝试连接到设备并从Mac发送一些数据到CDC数据接口端点。

我知道电路工作100%,因为设备注册为HID操纵杆,我能够使用Zoc终端连接到设备,在/dev/tty.usbmodemfa132。 我可以用Zoc发送命令,看到我的MCU通过闪烁电路上的一些LED来响应这些命令。

我是在Mac OS X Mavericks上运行的,但几周前在Mountain Lion上我放弃了类似的例子。

我的代码如下所示:

// Includes ----------------------------------------------------------------------------------------------------------- #include  #include  #include  #include  #include  // Defines ------------------------------------------------------------------------------------------------------------ #define VID 0x04d8 #define PID 0x005e #define CDC_DATA_INTERFACE_ID 2 // Function Declarations ---------------------------------------------------------------------------------------------- void print_device(libusb_device *device); void send(libusb_context *usb_context, uint16_t vid, uint16_t pid); // Function Definitions ----------------------------------------------------------------------------------------------- /** * main */ int main(int argc, char **argv) { libusb_device **usb_devices = NULL; libusb_context *usb_context = NULL; ssize_t device_count = 0; bool debug_enabled = false; int c; // Collect command line attributes while ( (c = getopt(argc, argv, "d")) != -1) { switch (c) { case 'd': debug_enabled = true; break; } } // Initialize USB context int result = libusb_init(&usb_context); if(result < 0) { printf("Unable to initialise libusb!"); return EXIT_FAILURE; } // Turn debug mode on/off if(debug_enabled) { libusb_set_debug(usb_context, 3); } // Get USB device list device_count = libusb_get_device_list(usb_context, &usb_devices); if(device_count < 0) { puts("Unable to retrieve USB device list!"); } // Iterate and print devices puts("VID PID Manufacturer Name\n------ ------ -------------------"); for (int i = 0; i < device_count; i++) { print_device(usb_devices[i]); } // Attempt to send data send(usb_context, VID, PID); // Cleanup and exit libusb_free_device_list(usb_devices, 1); libusb_exit(usb_context); return EXIT_SUCCESS; } /** * print_device */ void print_device(libusb_device *device) { struct libusb_device_descriptor device_descriptor; struct libusb_device_handle *device_handle = NULL; // Get USB device descriptor int result = libusb_get_device_descriptor(device, &device_descriptor); if (result < 0) { printf("Failed to get device descriptor!"); } // Only print our devices if(VID == device_descriptor.idVendor && PID == device_descriptor.idProduct) { // Print VID & PID printf("0x%04x 0x%04x", device_descriptor.idVendor, device_descriptor.idProduct); } else { return; } // Attempt to open the device int open_result = libusb_open(device, &device_handle); if (open_result < 0) { libusb_close(device_handle); return; } // Print the device manufacturer string char manufacturer[256] = " "; if (device_descriptor.iManufacturer) { libusb_get_string_descriptor_ascii(device_handle, device_descriptor.iManufacturer, (unsigned char *)manufacturer, sizeof(manufacturer)); printf(" %s", manufacturer); } puts(""); libusb_close(device_handle); } /** * send */ void send(libusb_context *usb_context, uint16_t vid, uint16_t pid) { libusb_device_handle *device_handle; device_handle = libusb_open_device_with_vid_pid(usb_context, vid, pid); if (device_handle == NULL) { puts("Unable to open device by VID & PID!"); return; } puts("Device successfully opened"); unsigned char *data = (unsigned char *)"test"; if (libusb_kernel_driver_active(device_handle, CDC_DATA_INTERFACE_ID)) { puts("Kernel driver active"); if (libusb_detach_kernel_driver(device_handle, CDC_DATA_INTERFACE_ID)) { puts("Kernel driver detached"); } } else { puts("Kernel driver doesn't appear to be active"); } int result = libusb_claim_interface(device_handle, CDC_DATA_INTERFACE_ID); if (result < 0) { puts("Unable to claim interface!"); libusb_close(device_handle); return; } puts("Interface claimed"); int written = 0; result = libusb_bulk_transfer(device_handle, (3 | LIBUSB_ENDPOINT_OUT), data, 4, &written, 0); if (result == 0 && written == 4) { puts("Send success"); } else { puts("Send failed!"); } result = libusb_release_interface(device_handle, CDC_DATA_INTERFACE_ID); if (result != 0) { puts("Unable to release interface!"); } libusb_close(device_handle); } 

我收到以下错误输出:

 libusb: 0.828223 error [darwin_open] USBDeviceOpen: another process has device opened for exclusive access libusb: 0.828241 info [darwin_open] device open for access Device successfully opened Kernel driver doesn't appear to be active libusb: 0.828641 error [darwin_claim_interface] USBInterfaceOpen: another process has device opened for exclusive access Unable to claim interface! libusb: 0.828766 info [event_thread_main] thread exiting 

有没有办法可以从其他进程中释放USB设备,将其释放,以便我可以声明它?

有没有其他方法可以连接到/dev/tty.usbmodemfa132来发送和接收USB设备上的CDC接口的数据?

也许是libusb的替代品?

那就对了。 虽然libusb似乎在Linux中无所不能,但您无法使用它连接到Mac OS X上的USB CDC接口,因为AppleUSBCDCACM驱动程序已声明该接口。

你应该做的是使用人们连接到串口的标准方式。 这将更容易,因为您不必担心端点和批量传输等。 下面是我为基于CDC的产品编写的一些示例跨平台C代码,它连接到COM端口以读取和写入一些数据( 源 )。 它使用标准函数openreadwrite

 // Uses POSIX functions to send and receive data from a Maestro. // NOTE: You must change the 'const char * device' line below. #include  #include  #include  #ifdef _WIN32 #define O_NOCTTY 0 #else #include  #endif // Gets the position of a Maestro channel. // See the "Serial Servo Commands" section of the user's guide. int maestroGetPosition(int fd, unsigned char channel) { unsigned char command[] = {0x90, channel}; if(write(fd, command, sizeof(command)) == -1) { perror("error writing"); return -1; } unsigned char response[2]; if(read(fd,response,2) != 2) { perror("error reading"); return -1; } return response[0] + 256*response[1]; } // Sets the target of a Maestro channel. // See the "Serial Servo Commands" section of the user's guide. // The units of 'target' are quarter-microseconds. int maestroSetTarget(int fd, unsigned char channel, unsigned short target) { unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F}; if (write(fd, command, sizeof(command)) == -1) { perror("error writing"); return -1; } return 0; } int main() { // Open the Maestro's virtual COM port. const char * device = "\\\\.\\USBSER000"; // Windows, "\\\\.\\COM6" also works //const char * device = "/dev/ttyACM0"; // Linux //const char * device = "/dev/cu.usbmodem00034567"; // Mac OS X int fd = open(device, O_RDWR | O_NOCTTY); if (fd == -1) { perror(device); return 1; } #ifndef _WIN32 struct termios options; tcgetattr(fd, &options); options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); options.c_oflag &= ~(ONLCR | OCRNL); tcsetattr(fd, TCSANOW, &options); #endif int position = maestroGetPosition(fd, 0); printf("Current position is %d.\n", position); int target = (position < 6000) ? 7000 : 5000; printf("Setting target to %d (%d us).\n", target, target/4); maestroSetTarget(fd, 0, target); close(fd); return 0; } 

如果您想使用Apple FTDI串行驱动程序也能识别的某些USB设备,您可以先卸载驱动程序:

 sudo kextunload -b com.apple.driver.AppleUSBFTDI 

之后你可以通过libusb正常使用它。

对于被识别为串行设备的其他设备,您可能需要卸载其他一些驱动程序。