int get_reply(libusb_device_handle* dev, freenect_context *ctx){ unsigned char buffer[512]; memset(buffer, 0, 512); int transferred = 0; int res = 0; res = libusb_bulk_transfer(dev, 0x81, buffer, 512, &transferred, 100); if (res != 0) { FN_ERROR("get_reply(): libusb_bulk_transfer failed: %d (transferred = %d)\n", res, transferred); } else if (transferred != 12) { FN_ERROR("get_reply(): weird - got %d bytes (expected 12)\n", transferred); } else { fn_alt_motor_reply reply; memcpy(&reply, buffer, sizeof(reply)); if (reply.magic != 0x0a6fe000) { FN_ERROR("Bad magic: %08X (expected 0A6FE000\n", reply.magic); res = -1; } //can't really do this as tag_seq is static. with two cameras this is not going to match. could put in as part of libusb_device but I don't think it really matters. // if (reply.tag != tag_next_ack) { // FN_ERROR("Reply tag out of order: expected %d, got %d\n", tag_next_ack, reply.tag); // res = -1; // } if (reply.status != 0) { FN_ERROR("reply status != 0: failure?\n"); res = -1; } tag_next_ack++; } return res; }
FREENECTAPI int freenect_process_events_timeout(freenect_context *ctx, struct timeval *timeout) { int res = fnusb_process_events_timeout(&ctx->usb, timeout); // Iterate over the devices in ctx. If any of them are flagged as freenect_device* dev = ctx->first; while(dev) { if (dev->usb_cam.device_dead) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,"USB camera marked dead, stopping streams" ); FN_ERROR("USB camera marked dead, stopping streams\n"); res = -1; freenect_stop_video(dev); freenect_stop_depth(dev); } #ifdef BUILD_AUDIO if (dev->usb_audio.device_dead) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,"USB audio marked dead, stopping streams" ); FN_ERROR("USB audio marked dead, stopping streams\n"); res = -1; // Or something else to tell the user that the device just vanished. freenect_stop_audio(dev); } #endif dev = dev->next; } return res; }
static int get_reply(fnusb_dev* dev) { freenect_context* ctx = dev->parent->parent; unsigned char dump[512]; bootloader_status_code buffer; int res; int transferred; res = fnusb_bulk(dev, 0x81, dump, 512, &transferred); if(res != 0 || transferred != sizeof(bootloader_status_code)) { FN_ERROR("Error reading reply: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)(sizeof(bootloader_status_code))); return res; } memcpy(&buffer, dump, sizeof(bootloader_status_code)); if(fn_le32(buffer.magic) != 0x0a6fe000) { FN_ERROR("Error reading reply: invalid magic %08X\n",buffer.magic); return -1; } if(fn_le32(buffer.tag) != dev->parent->audio_tag) { FN_ERROR("Error reading reply: non-matching tag number %08X (expected %08X)\n", buffer.tag, dev->parent->audio_tag); return -1; } if(fn_le32(buffer.status) != 0) { FN_ERROR("Notice reading reply: last uint32_t was nonzero: %d\n", buffer.status); } FN_INFO("Reading reply: "); int i; for(i = 0; i < transferred; ++i) { FN_INFO("%02X ", ((unsigned char*)(&buffer))[i]); } FN_INFO("\n"); return res; }
int freenect_update_tilt_state(freenect_device *dev) { freenect_context *ctx = dev->parent; #ifdef BUILD_AUDIO //if we have motor control via audio and fw is uploaded - call the alt function if( dev->motor_control_with_audio_enabled ){ return update_tilt_state_alt(dev); } #endif if(!(ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR)) return 0; uint8_t buf[10]; uint16_t ux, uy, uz; int ret = fnusb_control(&dev->usb_motor, 0xC0, 0x32, 0x0, 0x0, buf, 10); if (ret != 10) { FN_ERROR("Error in accelerometer reading, libusb_control_transfer returned %d\n", ret); return ret < 0 ? ret : -1; } ux = ((uint16_t)buf[2] << 8) | buf[3]; uy = ((uint16_t)buf[4] << 8) | buf[5]; uz = ((uint16_t)buf[6] << 8) | buf[7]; dev->raw_state.accelerometer_x = (int16_t)ux; dev->raw_state.accelerometer_y = (int16_t)uy; dev->raw_state.accelerometer_z = (int16_t)uz; dev->raw_state.tilt_angle = (int8_t)buf[8]; dev->raw_state.tilt_status = (freenect_tilt_status_code)buf[9]; return ret; }
int freenect_set_tilt_degs_alt(freenect_device *dev, int tilt_degrees) { freenect_context *ctx = dev->parent; if (tilt_degrees > 31 || tilt_degrees < -31) { FN_WARNING("set_tilt(): degrees %d out of safe range [-31, 31]\n", tilt_degrees); return -1; } fn_alt_motor_command cmd; cmd.magic = fn_le32(0x06022009); cmd.tag = fn_le32(tag_seq++); cmd.arg1 = fn_le32(0); cmd.cmd = fn_le32(0x803b); cmd.arg2 = (uint32_t)(fn_le32((int32_t)tilt_degrees)); int transferred = 0; int res = 0; unsigned char buffer[20]; memcpy(buffer, &cmd, 20); res = libusb_bulk_transfer(dev->usb_audio.dev, 0x01, buffer, 20, &transferred, 250); if (res != 0) { FN_ERROR("freenect_set_tilt_alt(): libusb_bulk_transfer failed: %d (transferred = %d)\n", res, transferred); return res; } return get_reply(dev->usb_audio.dev, ctx); }
FN_INTERNAL int fnusb_claim_camera(freenect_device* dev) { freenect_context *ctx = dev->parent; int ret = 0; #ifndef _WIN32 // todo: necessary? // Detach an existing kernel driver for the device ret = libusb_kernel_driver_active(dev->usb_cam.dev, 0); if (ret == 1) { ret = libusb_detach_kernel_driver(dev->usb_cam.dev, 0); if (ret < 0) { FN_ERROR("Failed to detach camera kernel driver: %s\n", libusb_error_name(ret)); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; return ret; } } #endif ret = libusb_claim_interface(dev->usb_cam.dev, 0); if (ret < 0) { FN_ERROR("Failed to claim camera interface: %s\n", libusb_error_name(ret)); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; return ret; } if (dev->usb_cam.PID == PID_K4W_CAMERA) { ret = libusb_set_interface_alt_setting(dev->usb_cam.dev, 0, 1); if (ret != 0) { FN_ERROR("Failed to set alternate interface #1 for K4W: %s\n", libusb_error_name(ret)); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; return ret; } } return ret; }
static void iso_callback(struct libusb_transfer *xfer) { int i; fnusb_isoc_stream *strm = (fnusb_isoc_stream*)xfer->user_data; if (strm->dead) { freenect_context *ctx = strm->parent->parent->parent; strm->dead_xfers++; FN_SPEW("EP %02x transfer complete, %d left\n", xfer->endpoint, strm->num_xfers - strm->dead_xfers); return; } switch(xfer->status) { case LIBUSB_TRANSFER_COMPLETED: // Normal operation. { uint8_t *buf = (uint8_t*)xfer->buffer; for (i=0; i<strm->pkts; i++) { strm->cb(strm->parent->parent, buf, xfer->iso_packet_desc[i].actual_length); buf += strm->len; } libusb_submit_transfer(xfer); break; } case LIBUSB_TRANSFER_NO_DEVICE: { // We lost the device we were talking to. This is a large problem, // and one that we should eventually come up with a way to // properly propagate up to the caller. freenect_context *ctx = strm->parent->parent->parent; FN_ERROR("USB device disappeared, cancelling stream :(\n"); strm->dead_xfers++; fnusb_stop_iso(strm->parent, strm); break; } case LIBUSB_TRANSFER_CANCELLED: { freenect_context *ctx = strm->parent->parent->parent; FN_SPEW("EP %02x transfer cancelled\n", xfer->endpoint); strm->dead_xfers++; break; } default: { // On other errors, resubmit the transfer - in particular, libusb // on OSX tends to hit random errors a lot. If we don't resubmit // the transfers, eventually all of them die and then we don't get // any more data from the Kinect. freenect_context *ctx = strm->parent->parent->parent; FN_WARNING("Isochronous transfer error: %d\n", xfer->status); libusb_submit_transfer(xfer); break; } } }
static int check_version_string(fnusb_dev* dev) { freenect_context* ctx = dev->parent->parent; bootloader_command bootcmd; memset(&bootcmd, 0, sizeof(bootcmd)); bootcmd.magic = fn_le32(0x06022009); bootcmd.tag = fn_le32(dev->parent->audio_tag); bootcmd.bytes = fn_le32(0x60); bootcmd.cmd = fn_le32(0); bootcmd.addr = fn_le32(0x15); unsigned char buffer[512]; int res; int transferred; FN_INFO("check_version_string(): About to send: "); dump_bl_cmd(ctx, bootcmd); // Send "get version string" command res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred); if(res != 0 || transferred != sizeof(bootcmd)) { FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)sizeof(bootcmd)); return -1; } // Read version string reply res = fnusb_bulk(dev, 0x81, buffer, 512, &transferred); if(res != 0 ) { FN_ERROR("Error reading version string: %d\ttransferred: %d (expected %d)\n", res, transferred, 0x60); return res; } FN_INFO("Read version string: "); int i; for(i = 0; i < transferred; ++i) { FN_INFO("%02X ", buffer[i]); } FN_INFO("\n"); // Read status code reply res = get_reply(dev); dev->parent->audio_tag++; return res; }
void InsertRecord() { FN_TRACE(); try { otl_nocommit_stream cStat(1, "insert into user(id, name) values(7, 'shi77')", m_sConn); } catch (otl_exception& e) { FN_ERROR("?, ?, ?, ?") << (char*)e.msg << e.stm_text << (char*)e.sqlstate << e.var_info; } }
void CreateTable() { FN_TRACE(); try { otl_nocommit_stream cStat(1, "drop table if exists user", m_sConn); otl_nocommit_stream cStat2(1, "create table user(id bigint(18), name varchar(64))", m_sConn); } catch (otl_exception& e) { FN_ERROR("?, ?, ?, ?") << (char*)e.msg << e.stm_text << (char*)e.sqlstate << e.var_info; } }
FREENECTAPI int freenect_open_device_by_camera_serial(freenect_context *ctx, freenect_device **dev, const char* camera_serial) { // This is implemented by listing the devices and seeing which index (if // any) has a camera with a matching serial number, and then punting to // freenect_open_device with that index. struct freenect_device_attributes* attrlist; struct freenect_device_attributes* item; int count = fnusb_list_device_attributes(&ctx->usb, &attrlist); if (count < 0) { FN_ERROR("freenect_open_device_by_camera_serial: Couldn't enumerate serial numbers\n"); return -1; } int index = 0; for(item = attrlist ; item != NULL; item = item->next , index++) { if (strlen(item->camera_serial) == strlen(camera_serial) && strcmp(item->camera_serial, camera_serial) == 0) { freenect_free_device_attributes(attrlist); return freenect_open_device(ctx, dev, index); } } freenect_free_device_attributes(attrlist); FN_ERROR("freenect_open_device_by_camera_serial: Couldn't find a device with serial %s\n", camera_serial); return -1; }
FREENECTAPI int freenect_close_device(freenect_device *dev) { freenect_context *ctx = dev->parent; int res; // stop streams, if active freenect_stop_depth(dev); freenect_stop_video(dev); res = fnusb_close_subdevices(dev); if (res < 0) { FN_ERROR("fnusb_close_subdevices failed: %d\n", res); return res; } freenect_device *last = NULL; freenect_device *cur = ctx->first; while (cur && cur != dev) { last = cur; cur = cur->next; } if (!cur) { FN_ERROR("device %p not found in linked list for this context!\n", dev); return -1; } if (last) last->next = cur->next; else ctx->first = cur->next; free(dev); return 0; }
FREENECTAPI int freenect_close_device(freenect_device *dev) { freenect_context *ctx = dev->parent; int res; if (dev->usb_cam.dev) { freenect_camera_teardown(dev); } res = fnusb_close_subdevices(dev); if (res < 0) { FN_ERROR("fnusb_close_subdevices failed: %d\n", res); return res; } freenect_device *last = NULL; freenect_device *cur = ctx->first; while (cur && cur != dev) { last = cur; cur = cur->next; } if (!cur) { FN_ERROR("device %p not found in linked list for this context!\n", dev); return -1; } if (last) last->next = cur->next; else ctx->first = cur->next; free(dev); return 0; }
int freenect_update_tilt_state(freenect_device *dev) { freenect_context *ctx = dev->parent; uint8_t buf[10]; uint16_t ux, uy, uz; int ret = fnusb_control(&dev->usb_motor, 0xC0, 0x32, 0x0, 0x0, buf, 10); if (ret != 10) { FN_ERROR("Error in accelerometer reading, libusb_control_transfer returned %d\n", ret); return ret < 0 ? ret : -1; } ux = ((uint16_t)buf[2] << 8) | buf[3]; uy = ((uint16_t)buf[4] << 8) | buf[5]; uz = ((uint16_t)buf[6] << 8) | buf[7]; dev->raw_state.accelerometer_x = (int16_t)ux; dev->raw_state.accelerometer_y = (int16_t)uy; dev->raw_state.accelerometer_z = (int16_t)uz; dev->raw_state.tilt_angle = (int8_t)buf[8]; dev->raw_state.tilt_status = (freenect_tilt_status_code)buf[9]; return ret; }
void SelectRecord() { FN_TRACE(); try { otl_nocommit_stream cStat(1, "select * from user", m_sConn); int nId; char szUser[64]; for (;;) { const bool bHasNext = cStat >> nId >> szUser; if (!bHasNext) { break; } FN_INFO("?, ?") << nId << szUser; } } catch (otl_exception& e) { FN_ERROR("?, ?, ?, ?") << (char*)e.msg << e.stm_text << (char*)e.sqlstate << e.var_info; } }
FREENECTAPI int freenect_open_device(freenect_context *ctx, freenect_device **dev, int index) { int res; freenect_device *pdev = (freenect_device*)malloc(sizeof(freenect_device)); if (!pdev){ __android_log_write(ANDROID_LOG_INFO, "Kinect","freenect_open_device: malloc failed\n"); return -1; } __android_log_write(ANDROID_LOG_INFO, "Kinect","freenect_open_device: malloc successful\n"); memset(pdev, 0, sizeof(*pdev)); pdev->parent = ctx; res = fnusb_open_subdevices(pdev, index); if (res < 0) { free(pdev); __android_log_write(ANDROID_LOG_INFO, "Kinect","freenect_open_device: fnusb_open_subdevices failed\n"); return res; } __android_log_write(ANDROID_LOG_INFO, "Kinect","freenect_open_device: fnusb_open_subdevices successed\n"); #ifdef BUILD_AUDIO if (pdev->usb_audio.dev) { res = fnusb_num_interfaces(&pdev->usb_audio); if (res == 1) { // Upload audio firmware, release devices, and reopen them res = upload_firmware(&pdev->usb_audio); if (res < 0) { FN_ERROR("upload_firmware failed: %d\n", res); free(pdev); return res; } res = fnusb_close_subdevices(pdev); if (res < 0) { FN_ERROR("fnusb_close_subdevices failed: %d\n", res); free(pdev); return res; } sleep(1); // Give time for the device to reenumerate before trying to open it res = fnusb_open_subdevices(pdev, index); if (res < 0) { free(pdev); return res; } } } #endif if (!ctx->first) { ctx->first = pdev; } else { freenect_device *prev = ctx->first; while (prev->next) prev = prev->next; prev->next = pdev; } *dev = pdev; return 0; }
int freenect_close_device(freenect_device *dev) { freenect_context *ctx = dev->parent; FN_ERROR("%s NOT IMPLEMENTED YET\n", __FUNCTION__); return 0; }
int fnusb_open_subdevices(freenect_device *dev, int index) { freenect_context *ctx = dev->parent; dev->usb_cam.parent = dev; dev->usb_cam.dev = NULL; dev->usb_motor.parent = dev; dev->usb_motor.dev = NULL; libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices ssize_t cnt = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices if (cnt < 0) return -1; int i = 0, nr_cam = 0, nr_mot = 0; int res; struct libusb_device_descriptor desc; for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; // Search for the camera if (!dev->usb_cam.dev && desc.idProduct == PID_NUI_CAMERA) { // If the index given by the user matches our camera index if (nr_cam == index) { res = libusb_open (devs[i], &dev->usb_cam.dev); if (res < 0 || !dev->usb_cam.dev) { FN_ERROR("Could not open camera: %d\n", res); dev->usb_cam.dev = NULL; break; } res = libusb_claim_interface (dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } else { nr_cam++; } } // Search for the motor if (!dev->usb_motor.dev && desc.idProduct == PID_NUI_MOTOR) { // If the index given by the user matches our camera index if (nr_mot == index) { res = libusb_open (devs[i], &dev->usb_motor.dev); if (res < 0 || !dev->usb_motor.dev) { FN_ERROR("Could not open motor: %d\n", res); dev->usb_motor.dev = NULL; break; } res = libusb_claim_interface (dev->usb_motor.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on motor: %d\n", res); libusb_close(dev->usb_motor.dev); dev->usb_motor.dev = NULL; break; } } else { nr_mot++; } } } libusb_free_device_list (devs, 1); // free the list, unref the devices in it if (dev->usb_cam.dev && dev->usb_motor.dev) { return 0; } else { if (dev->usb_cam.dev) { libusb_release_interface(dev->usb_cam.dev, 0); libusb_close(dev->usb_cam.dev); } if (dev->usb_motor.dev) { libusb_release_interface(dev->usb_motor.dev, 0); libusb_close(dev->usb_motor.dev); } return -1; } }
FN_INTERNAL int upload_firmware(fnusb_dev* dev) { freenect_context* ctx = dev->parent->parent; bootloader_command bootcmd; memset(&bootcmd, 0, sizeof(bootcmd)); bootcmd.magic = fn_le32(0x06022009); int res; int transferred; /* Search for firmware file (audios.bin) in the following places: * $LIBFREENECT_FIRMWARE_PATH * . * ${HOME}/.libfreenect * /usr/local/share/libfreenect * /usr/share/libfreenect */ const char* fw_filename = "/audios.bin"; int filenamelen = strlen(fw_filename); int i; int searchpathcount; FILE* fw = NULL; for(i = 0, searchpathcount = 5; !fw && i < searchpathcount; i++) { char* fwfile; int needs_free = 0; switch(i) { case 0: { char* envpath = getenv("LIBFREENECT_FIRMWARE_PATH"); if (!envpath) continue; int pathlen = strlen(envpath); fwfile = malloc(pathlen + filenamelen + 1); strcpy(fwfile, envpath); strcat(fwfile, fw_filename); needs_free = 1; } break; case 1: fwfile = "./audios.bin"; break; case 2: { // Construct $HOME/.libfreenect/ char* home = getenv("HOME"); if (!home) continue; int homelen = strlen(home); char* dotfolder = "/.libfreenect"; int locallen = strlen(dotfolder); fwfile = (char*)malloc(homelen + locallen + filenamelen + 1); strcpy(fwfile, home); strcat(fwfile, dotfolder); strcat(fwfile, fw_filename); needs_free = 1; } break; case 3: fwfile = "/usr/local/share/libfreenect/audios.bin"; break; case 4: fwfile = "/usr/share/libfreenect/audios.bin"; break; default: break; } FN_INFO("Trying to open %s as firmware...\n", fwfile); fw = fopen(fwfile, "rb"); if (needs_free) { free(fwfile); } } if (!fw) { FN_ERROR("upload_firmware: failed to find firmware file.\n"); return -errno; } // Now we have an open firmware file handle. uint32_t addr = 0x00080000; int read; unsigned char page[0x4000]; do { read = fread(page, 1, 0x4000, fw); if(read <= 0) { break; } bootcmd.tag = fn_le32(dev->parent->audio_tag); bootcmd.bytes = fn_le32(read); bootcmd.cmd = fn_le32(0x03); bootcmd.addr = fn_le32(addr); FN_INFO("About to send: "); dump_bl_cmd(ctx, bootcmd); // Send it off! res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred); if(res != 0 || transferred != sizeof(bootcmd)) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)(sizeof(bootcmd))); fclose(fw); return -1; } int bytes_sent = 0; while(bytes_sent < read) { int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent); res = fnusb_bulk(dev, 1, &page[bytes_sent], to_send, &transferred); if(res != 0 || transferred != to_send) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send); fclose(fw); return -1; } bytes_sent += to_send; } res = get_reply(dev); addr += (uint32_t)read; dev->parent->audio_tag++; } while (read > 0); fclose(fw); fw = NULL; bootcmd.tag = fn_le32(dev->parent->audio_tag); bootcmd.bytes = fn_le32(0); bootcmd.cmd = fn_le32(0x04); bootcmd.addr = fn_le32(0x00080030); dump_bl_cmd(ctx, bootcmd); res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred); if(res != 0 || transferred != sizeof(bootcmd)) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(bootcmd)); return -1; } res = get_reply(dev); dev->parent->audio_tag++; FN_INFO("Firmware successfully uploaded and launched. Device will disconnect and reenumerate.\n"); return 0; }
int fnusb_open_subdevices(freenect_device *dev, int index) { freenect_context *ctx = dev->parent; dev->usb_cam.parent = dev; dev->usb_cam.dev = NULL; dev->usb_motor.parent = dev; dev->usb_motor.dev = NULL; #ifdef BUILD_AUDIO dev->usb_audio.parent = dev; dev->usb_audio.dev = NULL; #endif libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices ssize_t cnt = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices if (cnt < 0) return -1; int i = 0, nr_cam = 0, nr_mot = 0; #ifdef BUILD_AUDIO int nr_audio = 0; #endif int res; struct libusb_device_descriptor desc; for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; // Search for the camera if ((ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA) && !dev->usb_cam.dev && desc.idProduct == PID_NUI_CAMERA) { // If the index given by the user matches our camera index if (nr_cam == index) { res = libusb_open (devs[i], &dev->usb_cam.dev); if (res < 0 || !dev->usb_cam.dev) { FN_ERROR("Could not open camera: %d\n", res); dev->usb_cam.dev = NULL; break; } #ifndef _WIN32 // Detach an existing kernel driver for the device res = libusb_kernel_driver_active(dev->usb_cam.dev, 0); if (res == 1) { res = libusb_detach_kernel_driver(dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not detach kernel driver for camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } #endif res = libusb_claim_interface (dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } else { nr_cam++; } } // Search for the motor if ((ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR) && !dev->usb_motor.dev && desc.idProduct == PID_NUI_MOTOR) { // If the index given by the user matches our camera index if (nr_mot == index) { res = libusb_open (devs[i], &dev->usb_motor.dev); if (res < 0 || !dev->usb_motor.dev) { FN_ERROR("Could not open motor: %d\n", res); dev->usb_motor.dev = NULL; break; } res = libusb_claim_interface (dev->usb_motor.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on motor: %d\n", res); libusb_close(dev->usb_motor.dev); dev->usb_motor.dev = NULL; break; } } else { nr_mot++; } } #ifdef BUILD_AUDIO // TODO: check that the firmware has already been loaded; if not, upload firmware. // Search for the audio if ((ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO) && !dev->usb_audio.dev && desc.idProduct == PID_NUI_AUDIO) { // If the index given by the user matches our audio index if (nr_audio == index) { res = libusb_open (devs[i], &dev->usb_audio.dev); if (res < 0 || !dev->usb_audio.dev) { FN_ERROR("Could not open audio: %d\n", res); dev->usb_audio.dev = NULL; break; } res = libusb_claim_interface (dev->usb_audio.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on audio: %d\n", res); libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; break; } // Using the device handle that we've claimed, see if this // device has already uploaded firmware (has 2 interfaces). If // not, save the serial number (by reading the appropriate // descriptor), upload the firmware, and then enter a loop // waiting for a device with the same serial number to // reappear. int num_interfaces = fnusb_num_interfaces(&dev->usb_audio); if (num_interfaces == 1) { // Read the serial number from the string descriptor and save it. unsigned char string_desc[256]; // String descriptors are at most 256 bytes res = libusb_get_string_descriptor_ascii(dev->usb_audio.dev, desc.iSerialNumber, string_desc, 256); if (res < 0) { FN_ERROR("Failed to retrieve serial number for audio device in bootloader state\n"); break; } char* audio_serial = strdup((char*)string_desc); FN_SPEW("Uploading firmware to audio device in bootloader state.\n"); res = upload_firmware(&dev->usb_audio); if (res < 0) { FN_ERROR("upload_firmware failed: %d\n", res); break; } libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; // Wait for the device to reappear. int loops = 0; for (loops = 0; loops < 10; loops++) { // Loop for at most 10 tries. FN_SPEW("Try %d: Looking for new audio device matching serial %s\n", loops, audio_serial); // Scan devices. libusb_device **new_dev_list; int dev_index; ssize_t num_new_devs = libusb_get_device_list(ctx->usb.ctx, &new_dev_list); for (dev_index = 0; dev_index < num_new_devs; ++dev_index) { struct libusb_device_descriptor new_dev_desc; int r; r = libusb_get_device_descriptor (new_dev_list[dev_index], &new_dev_desc); if (r < 0) continue; // If this dev is a Kinect audio device, open device, read serial, and compare. if (new_dev_desc.idVendor == VID_MICROSOFT && new_dev_desc.idProduct == PID_NUI_AUDIO) { FN_SPEW("Matched VID/PID!\n"); libusb_device_handle* new_dev_handle; // Open device r = libusb_open(new_dev_list[dev_index], &new_dev_handle); if (r < 0) continue; // Read serial r = libusb_get_string_descriptor_ascii(new_dev_handle, new_dev_desc.iSerialNumber, string_desc, 256); if (r < 0) { FN_SPEW("Lost new audio device while fetching serial number.\n"); libusb_close(new_dev_handle); continue; } // Compare to expected serial if (r == strlen(audio_serial) && strcmp((char*)string_desc, audio_serial) == 0) { // We found it! r = libusb_claim_interface(new_dev_handle, 0); if (r != 0) { // Ouch, found the device but couldn't claim the interface. FN_SPEW("Device with serial %s reappeared but couldn't claim interface 0\n", audio_serial); libusb_close(new_dev_handle); continue; } // Save the device handle. dev->usb_audio.dev = new_dev_handle; // Verify that we've actually found a device running the right firmware. if (fnusb_num_interfaces(&dev->usb_audio) != 2) { FN_SPEW("Opened audio with matching serial but too few interfaces.\n"); dev->usb_audio.dev = NULL; libusb_close(new_dev_handle); continue; } break; } else { FN_SPEW("Got serial %s, expected serial %s\n", (char*)string_desc, audio_serial); } } } libusb_free_device_list(new_dev_list, 1); // If we found the right device, break out of this loop. if (dev->usb_audio.dev) break; // Sleep for a second to give the device more time to reenumerate. sleep(1); } free(audio_serial); } } else { nr_audio++; } } #endif } libusb_free_device_list (devs, 1); // free the list, unref the devices in it // Check that each subdevice is either opened or not enabled. if ( (dev->usb_cam.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA)) && (dev->usb_motor.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR)) #ifdef BUILD_AUDIO && (dev->usb_audio.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO)) #endif ) { return 0; } else { if (dev->usb_cam.dev) { libusb_release_interface(dev->usb_cam.dev, 0); libusb_close(dev->usb_cam.dev); } if (dev->usb_motor.dev) { libusb_release_interface(dev->usb_motor.dev, 0); libusb_close(dev->usb_motor.dev); } #ifdef BUILD_AUDIO if (dev->usb_audio.dev) { libusb_release_interface(dev->usb_audio.dev, 0); libusb_close(dev->usb_audio.dev); } #endif return -1; } }
static void iso_callback(struct libusb_transfer *xfer) { int i; fnusb_isoc_stream *strm = (fnusb_isoc_stream*)xfer->user_data; freenect_context *ctx = strm->parent->parent->parent; if (strm->dead) { strm->dead_xfers++; FN_SPEW("EP %02x transfer complete, %d left\n", xfer->endpoint, strm->num_xfers - strm->dead_xfers); return; } switch(xfer->status) { case LIBUSB_TRANSFER_COMPLETED: // Normal operation. { uint8_t *buf = (uint8_t*)xfer->buffer; for (i=0; i<strm->pkts; i++) { strm->cb(strm->parent->parent, buf, xfer->iso_packet_desc[i].actual_length); buf += strm->len; } int res; res = libusb_submit_transfer(xfer); if (res != 0) { FN_ERROR("iso_callback(): failed to resubmit transfer after successful completion: %d\n", res); strm->dead_xfers++; if (res == LIBUSB_ERROR_NO_DEVICE) { strm->parent->device_dead = 1; } } break; } case LIBUSB_TRANSFER_NO_DEVICE: { // We lost the device we were talking to. This is a large problem, // and one that we should eventually come up with a way to // properly propagate up to the caller. if(!strm->parent->device_dead) { FN_ERROR("USB device disappeared, cancelling stream %02x :(\n", xfer->endpoint); } strm->dead_xfers++; strm->parent->device_dead = 1; break; } case LIBUSB_TRANSFER_CANCELLED: { if(strm->dead) { FN_SPEW("EP %02x transfer cancelled\n", xfer->endpoint); } else { // This seems to be a libusb bug on OSX - instead of completing // the transfer with LIBUSB_TRANSFER_NO_DEVICE, the transfers // simply come back cancelled by the OS. We can detect this, // though - the stream should be marked dead if we're // intentionally cancelling transfers. if(!strm->parent->device_dead) { FN_ERROR("Got cancelled transfer, but we didn't request it - device disconnected?\n"); } strm->parent->device_dead = 1; } strm->dead_xfers++; break; } default: { // On other errors, resubmit the transfer - in particular, libusb // on OSX tends to hit random errors a lot. If we don't resubmit // the transfers, eventually all of them die and then we don't get // any more data from the Kinect. FN_WARNING("Isochronous transfer error: %d\n", xfer->status); int res; res = libusb_submit_transfer(xfer); if (res != 0) { FN_ERROR("Isochronous transfer resubmission failed after unknown error: %d\n", res); strm->dead_xfers++; if (res == LIBUSB_ERROR_NO_DEVICE) { strm->parent->device_dead = 1; } } break; } } }
FN_INTERNAL int fnusb_open_subdevices(freenect_device *dev, int index) { freenect_context *ctx = dev->parent; dev->device_does_motor_control_with_audio = 0; dev->motor_control_with_audio_enabled = 0; dev->usb_cam.parent = dev; dev->usb_cam.dev = NULL; dev->usb_motor.parent = dev; dev->usb_motor.dev = NULL; #ifdef BUILD_AUDIO dev->usb_audio.parent = dev; dev->usb_audio.dev = NULL; #endif libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices ssize_t cnt = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices if (cnt < 0) return -1; int i = 0, nr_cam = 0, nr_mot = 0; #ifdef BUILD_AUDIO int nr_audio = 0; #endif int res; struct libusb_device_descriptor desc; for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; res = 0; // Search for the camera if ((ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA) && !dev->usb_cam.dev && (desc.idProduct == PID_NUI_CAMERA || desc.idProduct == PID_K4W_CAMERA)) { // If the index given by the user matches our camera index if (nr_cam == index) { res = libusb_open (devs[i], &dev->usb_cam.dev); if (res < 0 || !dev->usb_cam.dev) { FN_ERROR("Could not open camera: %d\n", res); dev->usb_cam.dev = NULL; break; } if (desc.idProduct == PID_K4W_CAMERA || desc.bcdDevice != fn_le32(267)) { freenect_device_flags requested_devices = ctx->enabled_subdevices; // Not the old kinect so we only set up the camera ctx->enabled_subdevices = FREENECT_DEVICE_CAMERA; ctx->zero_plane_res = 334; dev->device_does_motor_control_with_audio = 1; //lets also set the LED ON //this keeps the camera alive for some systems which get freezes if( desc.idProduct == PID_K4W_CAMERA ){ freenect_extra_keep_alive(PID_K4W_AUDIO); }else{ freenect_extra_keep_alive(PID_NUI_AUDIO); } #ifdef BUILD_AUDIO //for newer devices we need to enable the audio device for motor control //we only do this though if motor has been requested. if ((requested_devices & FREENECT_DEVICE_MOTOR) && (requested_devices & FREENECT_DEVICE_AUDIO) == 0) { ctx->enabled_subdevices = (freenect_device_flags)(ctx->enabled_subdevices | FREENECT_DEVICE_AUDIO); } #endif }else{ /* The good old kinect that tilts and tweets */ ctx->zero_plane_res = 322; } #ifndef _WIN32 // Detach an existing kernel driver for the device res = libusb_kernel_driver_active(dev->usb_cam.dev, 0); if (res == 1) { res = libusb_detach_kernel_driver(dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not detach kernel driver for camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } #endif res = libusb_claim_interface (dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } if(desc.idProduct == PID_K4W_CAMERA){ res = libusb_set_interface_alt_setting(dev->usb_cam.dev, 0, 1); if (res != 0) { FN_ERROR("Failed to set alternate interface #1 for K4W: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } } else { nr_cam++; } } } if(ctx->enabled_subdevices == FREENECT_DEVICE_CAMERA || res < 0) cnt = 0; // Search for the motor for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; if ((ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR) && !dev->usb_motor.dev && desc.idProduct == PID_NUI_MOTOR) { // If the index given by the user matches our camera index if (nr_mot == index) { res = libusb_open (devs[i], &dev->usb_motor.dev); if (res < 0 || !dev->usb_motor.dev) { FN_ERROR("Could not open motor: %d\n", res); dev->usb_motor.dev = NULL; break; } res = libusb_claim_interface (dev->usb_motor.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on motor: %d\n", res); libusb_close(dev->usb_motor.dev); dev->usb_motor.dev = NULL; break; } } else { nr_mot++; } } #ifdef BUILD_AUDIO // TODO: check that the firmware has already been loaded; if not, upload firmware. // Search for the audio if ((ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO) && !dev->usb_audio.dev && (desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct))) { // If the index given by the user matches our audio index if (nr_audio == index) { res = libusb_open (devs[i], &dev->usb_audio.dev); if (res < 0 || !dev->usb_audio.dev) { FN_ERROR("Could not open audio: %d\n", res); dev->usb_audio.dev = NULL; break; } res = libusb_claim_interface (dev->usb_audio.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on audio: %d\n", res); libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; break; } // Using the device handle that we've claimed, see if this // device has already uploaded firmware (has 2 interfaces). If // not, save the serial number (by reading the appropriate // descriptor), upload the firmware, and then enter a loop // waiting for a device with the same serial number to // reappear. int num_interfaces = fnusb_num_interfaces(&dev->usb_audio); if( num_interfaces >= 2 ){ if( dev->device_does_motor_control_with_audio ){ dev->motor_control_with_audio_enabled = 1; } }else{ // Read the serial number from the string descriptor and save it. unsigned char string_desc[256]; // String descriptors are at most 256 bytes res = libusb_get_string_descriptor_ascii(dev->usb_audio.dev, desc.iSerialNumber, string_desc, 256); if (res < 0) { FN_ERROR("Failed to retrieve serial number for audio device in bootloader state\n"); break; } char* audio_serial = strdup((char*)string_desc); FN_SPEW("Uploading firmware to audio device in bootloader state.\n"); // Check if we can load from memory - otherwise load from disk if( desc.idProduct == PID_NUI_AUDIO && ctx->fn_fw_nui_ptr && ctx->fn_fw_nui_size > 0){ FN_SPEW("loading firmware from memory\n"); res = upload_firmware_from_memory(&dev->usb_audio, ctx->fn_fw_nui_ptr, ctx->fn_fw_nui_size); } else if( desc.idProduct == PID_K4W_AUDIO && ctx->fn_fw_k4w_ptr && ctx->fn_fw_k4w_size > 0 ){ FN_SPEW("loading firmware from memory\n"); res = upload_firmware_from_memory(&dev->usb_audio, ctx->fn_fw_k4w_ptr, ctx->fn_fw_k4w_size); } else{ res = upload_firmware(&dev->usb_audio, "audios.bin"); } if (res < 0) { FN_ERROR("upload_firmware failed: %d\n", res); break; } libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; // Wait for the device to reappear. int loops = 0; for (loops = 0; loops < 10; loops++) { // Loop for at most 10 tries. FN_SPEW("Try %d: Looking for new audio device matching serial %s\n", loops, audio_serial); // Scan devices. libusb_device **new_dev_list; int dev_index; ssize_t num_new_devs = libusb_get_device_list(ctx->usb.ctx, &new_dev_list); for (dev_index = 0; dev_index < num_new_devs; ++dev_index) { struct libusb_device_descriptor new_dev_desc; int r; r = libusb_get_device_descriptor (new_dev_list[dev_index], &new_dev_desc); if (r < 0) continue; // If this dev is a Kinect audio device, open device, read serial, and compare. if (new_dev_desc.idVendor == VID_MICROSOFT && (new_dev_desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct))) { FN_SPEW("Matched VID/PID!\n"); libusb_device_handle* new_dev_handle; // Open device r = libusb_open(new_dev_list[dev_index], &new_dev_handle); if (r < 0) continue; // Read serial r = libusb_get_string_descriptor_ascii(new_dev_handle, new_dev_desc.iSerialNumber, string_desc, 256); if (r < 0) { FN_SPEW("Lost new audio device while fetching serial number.\n"); libusb_close(new_dev_handle); continue; } // Compare to expected serial if (r == strlen(audio_serial) && strcmp((char*)string_desc, audio_serial) == 0) { // We found it! r = libusb_claim_interface(new_dev_handle, 0); if (r != 0) { // Ouch, found the device but couldn't claim the interface. FN_SPEW("Device with serial %s reappeared but couldn't claim interface 0\n", audio_serial); libusb_close(new_dev_handle); continue; } // Save the device handle. dev->usb_audio.dev = new_dev_handle; // Verify that we've actually found a device running the right firmware. num_interfaces = fnusb_num_interfaces(&dev->usb_audio); if( num_interfaces >= 2 ){ if( dev->device_does_motor_control_with_audio ){ dev->motor_control_with_audio_enabled = 1; } }else{ FN_SPEW("Opened audio with matching serial but too few interfaces.\n"); dev->usb_audio.dev = NULL; libusb_close(new_dev_handle); continue; } break; } else { FN_SPEW("Got serial %s, expected serial %s\n", (char*)string_desc, audio_serial); } } } libusb_free_device_list(new_dev_list, 1); // If we found the right device, break out of this loop. if (dev->usb_audio.dev) break; // Sleep for a second to give the device more time to reenumerate. sleep(1); } free(audio_serial); } } else { nr_audio++; } } #endif } libusb_free_device_list (devs, 1); // free the list, unref the devices in it // Check that each subdevice is either opened or not enabled. if ( (dev->usb_cam.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA)) && (dev->usb_motor.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR)) #ifdef BUILD_AUDIO && (dev->usb_audio.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO)) #endif ) { return 0; } else { if (dev->usb_cam.dev) { libusb_release_interface(dev->usb_cam.dev, 0); libusb_close(dev->usb_cam.dev); } else { FN_ERROR("Failed to open camera subdevice or it is not disabled."); } if (dev->usb_motor.dev) { libusb_release_interface(dev->usb_motor.dev, 0); libusb_close(dev->usb_motor.dev); } else { FN_ERROR("Failed to open motor subddevice or it is not disabled."); } #ifdef BUILD_AUDIO if (dev->usb_audio.dev) { libusb_release_interface(dev->usb_audio.dev, 0); libusb_close(dev->usb_audio.dev); } else { FN_ERROR("Failed to open audio subdevice or it is not disabled."); } #endif return -1; } }
FN_INTERNAL int fnusb_open_subdevices(freenect_device *dev, int index) { freenect_context *ctx = dev->parent; dev->device_does_motor_control_with_audio = 0; dev->motor_control_with_audio_enabled = 0; dev->usb_cam.parent = dev; dev->usb_cam.dev = NULL; dev->usb_motor.parent = dev; dev->usb_motor.dev = NULL; dev->usb_audio.parent = dev; dev->usb_audio.dev = NULL; libusb_device **devs; // pointer to pointer of device, used to retrieve a list of devices ssize_t cnt = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices if (cnt < 0) return -1; int i = 0, nr_cam = 0, nr_mot = 0; int nr_audio = 0; int res; struct libusb_device_descriptor desc; for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; res = 0; // Search for the camera if ((ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA) && !dev->usb_cam.dev && (desc.idProduct == PID_NUI_CAMERA || desc.idProduct == PID_K4W_CAMERA)) { // If the index given by the user matches our camera index if (nr_cam == index) { dev->usb_cam.VID = desc.idVendor; dev->usb_cam.PID = desc.idProduct; res = libusb_open (devs[i], &dev->usb_cam.dev); if (res < 0 || !dev->usb_cam.dev) { FN_ERROR("Could not open camera: %d\n", res); dev->usb_cam.dev = NULL; break; } if (desc.idProduct == PID_K4W_CAMERA || desc.bcdDevice != fn_le32(267)) { freenect_device_flags requested_devices = ctx->enabled_subdevices; // Not the 1414 kinect so remove the motor flag, this should preserve the audio flag if set ctx->enabled_subdevices = (freenect_device_flags)(ctx->enabled_subdevices & ~FREENECT_DEVICE_MOTOR); ctx->zero_plane_res = 334; dev->device_does_motor_control_with_audio = 1; // set the LED for non 1414 devices to keep the camera alive for some systems which get freezes libusb_device * audioDevice = fnusb_find_connected_audio_device(devs[i], devs, cnt); if (audioDevice != NULL) { libusb_device_handle * audioHandle = NULL; res = libusb_open(audioDevice, &audioHandle); if (res != 0) { FN_ERROR("Failed to set the LED of K4W or 1473 device: %d\n", res); } else { // we need to do this as it is possible that the device was not closed properly in a previous session // if we don't do this and the device wasn't closed properly - it can cause infinite hangs on LED and TILT functions libusb_reset_device(audioHandle); libusb_close(audioHandle); res = libusb_open(audioDevice, &audioHandle); if (res == 0) { res = libusb_claim_interface(audioHandle, 0); if (res != 0) { FN_ERROR("Unable to claim interface %d\n", res); } else { fnusb_set_led_alt(audioHandle, ctx, LED_GREEN); libusb_release_interface(audioHandle, 0); } libusb_close(audioHandle); } } } // for newer devices we need to enable the audio device for motor control // we only do this though if motor has been requested. if ((requested_devices & FREENECT_DEVICE_MOTOR) && (requested_devices & FREENECT_DEVICE_AUDIO) == 0) { ctx->enabled_subdevices = (freenect_device_flags)(ctx->enabled_subdevices | FREENECT_DEVICE_AUDIO); } } else { // The good old kinect that tilts and tweets ctx->zero_plane_res = 322; } res = fnusb_claim_camera(dev); if (res < 0) { break; } } else { nr_cam++; } } } if (ctx->enabled_subdevices == FREENECT_DEVICE_CAMERA || res < 0) cnt = 0; // Search for the motor for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; if ((ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR) && !dev->usb_motor.dev && desc.idProduct == PID_NUI_MOTOR) { // If the index given by the user matches our camera index if (nr_mot == index) { dev->usb_motor.VID = desc.idVendor; dev->usb_motor.PID = desc.idProduct; res = libusb_open (devs[i], &dev->usb_motor.dev); if (res < 0 || !dev->usb_motor.dev) { FN_ERROR("Could not open motor: %d\n", res); dev->usb_motor.dev = NULL; break; } res = libusb_claim_interface (dev->usb_motor.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on motor: %d\n", res); libusb_close(dev->usb_motor.dev); dev->usb_motor.dev = NULL; break; } } else { nr_mot++; } } // Search for the audio if ((ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO) && !dev->usb_audio.dev && (desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct))) { // If the index given by the user matches our audio index if (nr_audio == index) { dev->usb_audio.VID = desc.idVendor; dev->usb_audio.PID = desc.idProduct; res = libusb_open (devs[i], &dev->usb_audio.dev); if (res < 0 || !dev->usb_audio.dev) { FN_ERROR("Could not open audio: %d\n", res); dev->usb_audio.dev = NULL; break; } res = libusb_claim_interface (dev->usb_audio.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on audio: %d\n", res); libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; break; } // Using the device handle that we've claimed, see if this // device has already uploaded firmware (has 2 interfaces). // If not, save the serial number (by reading the appropriate // descriptor), upload the firmware, and then enter a loop // waiting for a device with the same serial number to // reappear. int num_interfaces = fnusb_num_interfaces(&dev->usb_audio); if (num_interfaces >= 2) { if (dev->device_does_motor_control_with_audio) { dev->motor_control_with_audio_enabled = 1; } } else { // Read the serial number from the string descriptor and save it. unsigned char string_desc[256]; // String descriptors are at most 256 bytes res = libusb_get_string_descriptor_ascii(dev->usb_audio.dev, desc.iSerialNumber, string_desc, 256); if (res < 0) { FN_ERROR("Failed to retrieve serial number for audio device in bootloader state\n"); break; } char* audio_serial = strdup((char*)string_desc); FN_SPEW("Uploading firmware to audio device in bootloader state.\n"); // Check if we can load from memory - otherwise load from disk if (desc.idProduct == PID_NUI_AUDIO && ctx->fn_fw_nui_ptr && ctx->fn_fw_nui_size > 0) { FN_SPEW("loading firmware from memory\n"); res = upload_firmware_from_memory(&dev->usb_audio, ctx->fn_fw_nui_ptr, ctx->fn_fw_nui_size); } else if (desc.idProduct == PID_K4W_AUDIO && ctx->fn_fw_k4w_ptr && ctx->fn_fw_k4w_size > 0) { FN_SPEW("loading firmware from memory\n"); res = upload_firmware_from_memory(&dev->usb_audio, ctx->fn_fw_k4w_ptr, ctx->fn_fw_k4w_size); } else { res = upload_firmware(&dev->usb_audio, "audios.bin"); } if (res < 0) { FN_ERROR("upload_firmware failed: %d\n", res); break; } libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; // Wait for the device to reappear. int loops = 0; for (loops = 0; loops < 10; loops++) { FN_SPEW("Try %d: Looking for new audio device matching serial %s\n", loops, audio_serial); // Scan devices. libusb_device **new_dev_list; int dev_index; ssize_t num_new_devs = libusb_get_device_list(ctx->usb.ctx, &new_dev_list); for (dev_index = 0; dev_index < num_new_devs; ++dev_index) { struct libusb_device_descriptor new_dev_desc; int r; r = libusb_get_device_descriptor (new_dev_list[dev_index], &new_dev_desc); if (r < 0) continue; // If this dev is a Kinect audio device, open device, read serial, and compare. if (new_dev_desc.idVendor == VID_MICROSOFT && (new_dev_desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct))) { FN_SPEW("Matched VID/PID!\n"); libusb_device_handle* new_dev_handle; // Open device r = libusb_open(new_dev_list[dev_index], &new_dev_handle); if (r < 0) continue; // Read serial r = libusb_get_string_descriptor_ascii(new_dev_handle, new_dev_desc.iSerialNumber, string_desc, 256); if (r < 0) { FN_SPEW("Lost new audio device while fetching serial number.\n"); libusb_close(new_dev_handle); continue; } // Compare to expected serial if (r == strlen(audio_serial) && strcmp((char*)string_desc, audio_serial) == 0) { // We found it! r = libusb_claim_interface(new_dev_handle, 0); if (r != 0) { // Ouch, found the device but couldn't claim the interface. FN_SPEW("Device with serial %s reappeared but couldn't claim interface 0\n", audio_serial); libusb_close(new_dev_handle); continue; } // Save the device handle. dev->usb_audio.dev = new_dev_handle; // Verify that we've actually found a device running the right firmware. num_interfaces = fnusb_num_interfaces(&dev->usb_audio); if (num_interfaces >= 2) { if (dev->device_does_motor_control_with_audio) { dev->motor_control_with_audio_enabled = 1; } } else { FN_SPEW("Opened audio with matching serial but too few interfaces.\n"); dev->usb_audio.dev = NULL; libusb_close(new_dev_handle); continue; } break; } else { FN_SPEW("Got serial %s, expected serial %s\n", (char*)string_desc, audio_serial); } } } libusb_free_device_list(new_dev_list, 1); // If we found the right device, break out of this loop. if (dev->usb_audio.dev) break; // Sleep for a second to give the device more time to reenumerate. sleep(1); } free(audio_serial); } } else { nr_audio++; } } } libusb_free_device_list (devs, 1); // free the list, unref the devices in it if ((dev->usb_cam.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA)) && (dev->usb_motor.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR))) //&& (dev->usb_audio.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO))) { // Each requested subdevice is open. // Except audio, which may fail if firmware is missing (or because it hates us). return 0; } if (dev->usb_cam.dev != NULL) { libusb_release_interface(dev->usb_cam.dev, 0); libusb_close(dev->usb_cam.dev); } else { FN_ERROR("Failed to open camera subdevice or it is not disabled."); } if (dev->usb_motor.dev != NULL) { libusb_release_interface(dev->usb_motor.dev, 0); libusb_close(dev->usb_motor.dev); } else { FN_ERROR("Failed to open motor subddevice or it is not disabled."); } if (dev->usb_audio.dev != NULL) { libusb_release_interface(dev->usb_audio.dev, 0); libusb_close(dev->usb_audio.dev); } else { FN_ERROR("Failed to open audio subdevice or it is not disabled."); } return -1; }
FN_INTERNAL int upload_firmware(fnusb_dev* dev) { freenect_context* ctx = dev->parent->parent; bootloader_command bootcmd; memset(&bootcmd, 0, sizeof(bootcmd)); bootcmd.magic = fn_le32(0x06022009); int res; int transferred; /* Search for firmware file (audios.bin) in the following places: * $LIBFREENECT_FIRMWARE_PATH * . * ${HOME}/.libfreenect * /usr/local/share/libfreenect * /usr/share/libfreenect */ const char* fw_filename = "/audios.bin"; int filenamelen = strlen(fw_filename); int i; int searchpathcount; FILE* fw = NULL; for(i = 0, searchpathcount = 5; !fw && i < searchpathcount; i++) { char* fwfile; int needs_free = 0; switch(i) { case 0: { char* envpath = getenv("LIBFREENECT_FIRMWARE_PATH"); if (!envpath) continue; int pathlen = strlen(envpath); fwfile = malloc(pathlen + filenamelen + 1); strcpy(fwfile, envpath); strcat(fwfile, fw_filename); needs_free = 1; } break; case 1: fwfile = "./audios.bin"; break; case 2: { // Construct $HOME/.libfreenect/ char* home = getenv("HOME"); if (!home) continue; int homelen = strlen(home); char* dotfolder = "/.libfreenect"; int locallen = strlen(dotfolder); fwfile = (char*)malloc(homelen + locallen + filenamelen + 1); strcpy(fwfile, home); strcat(fwfile, dotfolder); strcat(fwfile, fw_filename); needs_free = 1; } break; case 3: fwfile = "/usr/local/share/libfreenect/audios.bin"; break; case 4: fwfile = "/usr/share/libfreenect/audios.bin"; break; default: break; } FN_INFO("Trying to open %s as firmware...\n", fwfile); fw = fopen(fwfile, "rb"); if (needs_free) { free(fwfile); } } if (!fw) { FN_ERROR("upload_firmware: failed to find firmware file.\n"); return -errno; } // Now we have an open firmware file handle. firmware_header fwheader; int read = 0; read = fread(&fwheader, 1, sizeof(firmware_header), fw); if (read != sizeof(firmware_header)) { FN_ERROR("upload_firmware: firmware image too small, has no header?\n"); fclose(fw); return -errno; } // The file is serialized as little endian. fwheader.magic = fn_le32(fwheader.magic); fwheader.ver_major = fn_le16(fwheader.ver_major); fwheader.ver_minor = fn_le16(fwheader.ver_minor); fwheader.ver_release = fn_le16(fwheader.ver_release); fwheader.ver_patch = fn_le16(fwheader.ver_patch); fwheader.base_addr = fn_le32(fwheader.base_addr); fwheader.size = fn_le32(fwheader.size); fwheader.entry_addr = fn_le32(fwheader.entry_addr); FN_INFO("Found firmware image:\n"); FN_INFO("\tmagic %08X\n", fwheader.magic); FN_INFO("\tversion %02d.%02d.%02d.%02d\n", fwheader.ver_major, fwheader.ver_minor, fwheader.ver_release, fwheader.ver_patch); FN_INFO("\tbase address 0x%08x\n", fwheader.base_addr); FN_INFO("\tsize 0x%08x\n", fwheader.size); FN_INFO("\tentry point 0x%08x\n", fwheader.entry_addr); rewind(fw); uint32_t addr = fwheader.base_addr; unsigned char page[0x4000]; int total_bytes_sent = 0; do { size_t block_size = (0x4000 > fwheader.size - total_bytes_sent) ? fwheader.size - total_bytes_sent : 0x4000; read = fread(page, 1, block_size, fw); if(read <= 0) { break; } bootcmd.tag = fn_le32(dev->parent->audio_tag); bootcmd.bytes = fn_le32(read); bootcmd.cmd = fn_le32(0x03); bootcmd.addr = fn_le32(addr); FN_INFO("About to send: "); dump_bl_cmd(ctx, bootcmd); // Send it off! res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred); if(res != 0 || transferred != sizeof(bootcmd)) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)(sizeof(bootcmd))); fclose(fw); return -1; } int bytes_sent = 0; while(bytes_sent < read) { int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent); res = fnusb_bulk(dev, 1, &page[bytes_sent], to_send, &transferred); if(res != 0 || transferred != to_send) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send); fclose(fw); return -1; } bytes_sent += to_send; total_bytes_sent += to_send; } res = get_reply(dev); addr += (uint32_t)read; dev->parent->audio_tag++; } while (read > 0); fclose(fw); fw = NULL; if (total_bytes_sent != fwheader.size) { FN_ERROR("upload_firmware: firmware image declared %d bytes, but file only contained %d bytes\n", fwheader.size, total_bytes_sent); return -1; } bootcmd.tag = fn_le32(dev->parent->audio_tag); bootcmd.bytes = fn_le32(0); bootcmd.cmd = fn_le32(0x04); bootcmd.addr = fn_le32(fwheader.entry_addr); dump_bl_cmd(ctx, bootcmd); res = fnusb_bulk(dev, 1, (unsigned char*)&bootcmd, sizeof(bootcmd), &transferred); if(res != 0 || transferred != sizeof(bootcmd)) { FN_ERROR("upload_firmware(): Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(bootcmd)); return -1; } res = get_reply(dev); dev->parent->audio_tag++; FN_INFO("Firmware successfully uploaded and launched. Device will disconnect and reenumerate.\n"); return 0; }
FN_INTERNAL int upload_cemd_data(fnusb_dev* dev) { // Now we upload the CEMD data. freenect_context* ctx = dev->parent->parent; cemdloader_command cemdcmd; memset(&cemdcmd, 0, sizeof(cemdcmd)); cemdcmd.magic = fn_le32(0x06022009); cemdcmd.tag = fn_le32(dev->parent->audio_tag); cemdcmd.arg1 = fn_le32(0); cemdcmd.cmd = fn_le32(0x00000133); cemdcmd.arg2 = fn_le32(0x00064014); // This is the length of the CEMD data. FN_INFO("Starting CEMD data upload:\n"); int res; int transferred; res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred); if(res != 0 || transferred != sizeof(cemdcmd)) { FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(cemdcmd)); return -1; } res = get_reply(dev); dev->parent->audio_tag++; const char* cemd_filename = "cemd_data.bin"; FILE* cf = fopen(cemd_filename, "r"); if(cf == NULL) { FN_ERROR("upload_cemd_data: Failed to open %s: error %d", cemd_filename, errno); return errno; } uint32_t addr = 0x00000000; int read = 0; unsigned char page[0x4000]; do { read = fread(page, 1, 0x4000, cf); if(read <= 0) { break; } //LOG(""); cemdcmd.tag = fn_le32(dev->parent->audio_tag); cemdcmd.arg1 = fn_le32(read); cemdcmd.cmd = fn_le32(0x134); cemdcmd.arg2 = fn_le32(addr); FN_INFO("About to send: "); dump_cemd_cmd(ctx, cemdcmd); // Send it off! res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred); if(res != 0 || transferred != sizeof(cemdcmd)) { FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, (int)sizeof(cemdcmd)); return -1; } int bytes_sent = 0; while(bytes_sent < read) { int to_send = (read - bytes_sent > 512 ? 512 : read - bytes_sent); res = fnusb_bulk(dev, 1, &page[bytes_sent], to_send, &transferred); if(res != 0 || transferred != to_send) { FN_ERROR("Error: res: %d\ttransferred: %d (expected %d)\n",res, transferred, to_send); return -1; } bytes_sent += to_send; } res = get_reply(dev); addr += (uint32_t)read; dev->parent->audio_tag++; } while (read > 0); fclose(cf); cf = NULL; cemdcmd.tag = fn_le32(dev->parent->audio_tag); cemdcmd.arg1 = fn_le32(0); // bytes = 0 cemdcmd.cmd = fn_le32(0x135); cemdcmd.arg2 = fn_le32(0x00064000); // mimicing the USB logs. This is the # of bytes of actual CEMD data after the 20-byte CEMD header. FN_INFO("Finishing CEMD data upload...\n"); res = fnusb_bulk(dev, 1, (unsigned char*)&cemdcmd, sizeof(cemdcmd), &transferred); if(res != 0 || transferred != sizeof(cemdcmd)) { FN_ERROR("upload_cemd_data(): Error: res: %d\ttransferred: %d (expected %d)\n", res, transferred, (int)sizeof(cemdcmd)); return -1; } res = get_reply(dev); dev->parent->audio_tag++; FN_INFO("CEMD data uploaded successfully.\n"); return 0; }
FREENECTAPI int freenect_open_device(freenect_context *ctx, freenect_device **dev, int index) { int res; freenect_device *pdev = (freenect_device*)malloc(sizeof(freenect_device)); if (!pdev) return -1; memset(pdev, 0, sizeof(*pdev)); pdev->parent = ctx; res = fnusb_open_subdevices(pdev, index); if (res < 0) { free(pdev); return res; } #ifdef BUILD_AUDIO if (pdev->usb_audio.dev) { res = fnusb_num_interfaces(&pdev->usb_audio); if (res == 1) { // Upload audio firmware, release devices, and reopen them res = upload_firmware(&pdev->usb_audio); if (res < 0) { FN_ERROR("upload_firmware failed: %d\n", res); free(pdev); return res; } res = fnusb_close_subdevices(pdev); if (res < 0) { FN_ERROR("fnusb_close_subdevices failed: %d\n", res); free(pdev); return res; } sleep(1); // Give time for the device to reenumerate before trying to open it res = fnusb_open_subdevices(pdev, index); if (res < 0) { free(pdev); return res; } } } #endif if (!ctx->first) { ctx->first = pdev; } else { freenect_device *prev = ctx->first; while (prev->next) prev = prev->next; prev->next = pdev; } *dev = pdev; // Do device-specific initialization if (pdev->usb_cam.dev) { if (freenect_camera_init(pdev) < 0) { return -1; } } return 0; }
int fnusb_open_subdevices(freenect_device *dev, int index) { freenect_context *ctx = dev->parent; dev->usb_cam.parent = dev; dev->usb_cam.dev = NULL; dev->usb_motor.parent = dev; dev->usb_motor.dev = NULL; #ifdef BUILD_AUDIO dev->usb_audio.parent = dev; dev->usb_audio.dev = NULL; #endif libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices ssize_t cnt = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices if (cnt < 0) return -1; int i = 0, nr_cam = 0, nr_mot = 0; #ifdef BUILD_AUDIO int nr_audio = 0; #endif int res; struct libusb_device_descriptor desc; for (i = 0; i < cnt; i++) { int r = libusb_get_device_descriptor (devs[i], &desc); if (r < 0) continue; if (desc.idVendor != VID_MICROSOFT) continue; // Search for the camera if ((ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA) && !dev->usb_cam.dev && desc.idProduct == PID_NUI_CAMERA) { // If the index given by the user matches our camera index if (nr_cam == index) { res = libusb_open (devs[i], &dev->usb_cam.dev); if (res < 0 || !dev->usb_cam.dev) { FN_ERROR("Could not open camera: %d\n", res); dev->usb_cam.dev = NULL; break; } #ifndef _WIN32 // Detach an existing kernel driver for the device res = libusb_kernel_driver_active(dev->usb_cam.dev, 0); if (res == 1) { res = libusb_detach_kernel_driver(dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not detach kernel driver for camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } #endif res = libusb_claim_interface (dev->usb_cam.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on camera: %d\n", res); libusb_close(dev->usb_cam.dev); dev->usb_cam.dev = NULL; break; } } else { nr_cam++; } } // Search for the motor if ((ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR) && !dev->usb_motor.dev && desc.idProduct == PID_NUI_MOTOR) { // If the index given by the user matches our camera index if (nr_mot == index) { res = libusb_open (devs[i], &dev->usb_motor.dev); if (res < 0 || !dev->usb_motor.dev) { FN_ERROR("Could not open motor: %d\n", res); dev->usb_motor.dev = NULL; break; } res = libusb_claim_interface (dev->usb_motor.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on motor: %d\n", res); libusb_close(dev->usb_motor.dev); dev->usb_motor.dev = NULL; break; } } else { nr_mot++; } } #ifdef BUILD_AUDIO // TODO: check that the firmware has already been loaded; if not, upload firmware. // Search for the audio if ((ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO) && !dev->usb_audio.dev && desc.idProduct == PID_NUI_AUDIO) { // If the index given by the user matches our audio index if (nr_audio == index) { res = libusb_open (devs[i], &dev->usb_audio.dev); if (res < 0 || !dev->usb_audio.dev) { FN_ERROR("Could not open audio: %d\n", res); dev->usb_audio.dev = NULL; break; } res = libusb_claim_interface (dev->usb_audio.dev, 0); if (res < 0) { FN_ERROR("Could not claim interface on audio: %d\n", res); libusb_close(dev->usb_audio.dev); dev->usb_audio.dev = NULL; break; } } else { nr_audio++; } } #endif } libusb_free_device_list (devs, 1); // free the list, unref the devices in it // Check that each subdevice is either opened or not enabled. if ( (dev->usb_cam.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_CAMERA)) && (dev->usb_motor.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_MOTOR)) #ifdef BUILD_AUDIO && (dev->usb_audio.dev || !(ctx->enabled_subdevices & FREENECT_DEVICE_AUDIO)) #endif ) { return 0; } else { if (dev->usb_cam.dev) { libusb_release_interface(dev->usb_cam.dev, 0); libusb_close(dev->usb_cam.dev); } if (dev->usb_motor.dev) { libusb_release_interface(dev->usb_motor.dev, 0); libusb_close(dev->usb_motor.dev); } #ifdef BUILD_AUDIO if (dev->usb_audio.dev) { libusb_release_interface(dev->usb_audio.dev, 0); libusb_close(dev->usb_audio.dev); } #endif return -1; } }
int freenect_shutdown(freenect_context *ctx) { FN_ERROR("%s NOT IMPLEMENTED YET\n", __FUNCTION__); return 0; }