I've got a compound USB + CDC device I built using a PIC32 microcontroller, and I'm trying to connect to the device and send some data to the CDC data interface endpoint from my Mac.
I know the circuit works 100%, as the device registers as both a HID joystick, and I'm able to connect to the device using Zoc terminal, on /dev/tty.usbmodemfa132. I can send commands with Zoc, and see my MCU responding to these commands by blinking some LEDs on the circuit.
I'm running this on Mac OS X Mavericks, but had the same problem with a similar example I gave up on, a few weeks ago on Mountain Lion.
My code looks like follows:
// Includes -----------------------------------------------------------------------------------------------------------
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#include <unistd.h>
// 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);
}
I'm getting the following error output:
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
Is there a way I can release the USB device from the other process, freeing it up so I can claim it?
Is there an alternative way I can connect to /dev/tty.usbmodemfa132 to send and receive data to the CDC interface on the USB device?
An alternative to libusb perhaps?
printf("Unable to claim interface: %s\n", libusb_error_name(result));
to get more info about the error. – Rhenium