Skip to content

Add a method to get a serial number from a device #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ include (FindOS)
include (SetupDirectories)

set (PROJECT_VER_MAJOR 0)
set (PROJECT_VER_MINOR 6)
set (PROJECT_VER_PATCH 4)
set (PROJECT_VER_MINOR 7)
set (PROJECT_VER_PATCH 0)
set (PROJECT_VER
"${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}")
set (PROJECT_APIVER
Expand Down
7 changes: 7 additions & 0 deletions examples/camtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libfreenect.h"

Expand Down Expand Up @@ -92,6 +93,12 @@ int main(int argc, char** argv)
return ret;
}

{
char* serial = freenect_get_device_serial(fn_dev);
if (serial) printf("Found device with serial %s\n", serial);
free(serial);
}

// Set depth and video modes.
ret = freenect_set_depth_mode(fn_dev, freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_MM));
if (ret < 0)
Expand Down
9 changes: 9 additions & 0 deletions include/libfreenect.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,15 @@ FREENECTAPI int freenect_open_device(freenect_context *ctx, freenect_device **de
*/
FREENECTAPI int freenect_open_device_by_camera_serial(freenect_context *ctx, freenect_device **dev, const char* camera_serial);

/**
* Gets a serial number for the device.
* The caller must free() the serial after use.
*
* @param dev
* @return an appropriate serial number, or NULL if none was found.
*/
FREENECTAPI char* freenect_get_device_serial(freenect_device* dev);

/**
* Closes a device that is currently open
*
Expand Down
13 changes: 13 additions & 0 deletions src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ FREENECTAPI int freenect_open_device_by_camera_serial(freenect_context *ctx, fre
return -1;
}

FREENECTAPI char* freenect_get_device_serial(freenect_device* dev)
{
if (dev == NULL) return NULL;

int res;

struct freenect_device_attributes attr;
res = fnusb_get_device_attributes(dev, &attr);
if (res != 0) return NULL;

return strdup(attr.camera_serial);
}

FREENECTAPI int freenect_close_device(freenect_device *dev)
{
freenect_context *ctx = dev->parent;
Expand Down
220 changes: 132 additions & 88 deletions src/usb_libusb10.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,92 @@ FN_INTERNAL libusb_device * fnusb_find_sibling_device(freenect_context* ctx, lib
return NULL;
}

FN_INTERNAL char* usb_get_serial(freenect_context* ctx, libusb_device* device, libusb_device_handle* handle, struct libusb_device_descriptor* desc)
{
if (ctx == NULL) return NULL;

if (device == NULL) {
if (handle == NULL) {
FN_WARNING("No handle or device for serial\n");
return NULL;
}
device = libusb_get_device(handle); // no need to free or unref
}

int res = 0;
struct libusb_device_descriptor localDesc;

if (desc == NULL) {
res = libusb_get_device_descriptor(device, &localDesc);
if (res != 0) {
FN_WARNING("Failed to get serial descriptor: %s\n", libusb_error_name(res));
return NULL;
}
desc = &localDesc;
}

// Verify that a serial number exists to query. If not, don't touch the device.
if (desc->iSerialNumber == 0) {
FN_WARNING("Device has no serial number\n");
return NULL;
}

libusb_device_handle* localHandle = NULL;

if (handle == NULL) {
res = libusb_open(device, &localHandle);
if (res != 0) {
FN_WARNING("Failed to open device for serial: %s\n", libusb_error_name(res));
return NULL;
}
handle = localHandle;
}

unsigned char serial[256]; // String descriptors are at most 256 bytes.
res = libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber, serial, sizeof(serial));

if (localHandle != NULL) {
libusb_close(localHandle);
}

if (res < 0) {
FN_WARNING("Failed to get serial: %s\n", libusb_error_name(res));
return NULL;
}

const char* const K4W_1473_SERIAL = "0000000000000000";
if (strncmp((const char*)serial, K4W_1473_SERIAL, 16) == 0) {
return NULL; // K4W and 1473 provide an empty serial; more easily handled as NULL.
}

return strndup((const char*)serial, sizeof(serial));
}

FN_INTERNAL int fnusb_get_device_attributes(freenect_device* dev, struct freenect_device_attributes* attributes)
{
freenect_context* ctx = dev->parent;

int res = 0;

char* serial = usb_get_serial(ctx, NULL, dev->usb_cam.dev, NULL);
if (serial == NULL)
{
char* audio_serial = usb_get_serial(ctx, NULL, dev->usb_audio.dev, NULL);
if (audio_serial) {
free(serial);
serial = audio_serial;
}
}

if (serial == NULL) {
return -1;
}

attributes->next = NULL;
attributes->camera_serial = serial;
return res;
}

FN_INTERNAL int fnusb_list_device_attributes(freenect_context *ctx, struct freenect_device_attributes** attribute_list)
{
*attribute_list = NULL; // initialize some return value in case the user is careless.
Expand All @@ -161,6 +247,7 @@ FN_INTERNAL int fnusb_list_device_attributes(freenect_context *ctx, struct freen
return (count >= INT_MIN) ? (int)count : -1;
}

int res = 0;
struct freenect_device_attributes** next_attr = attribute_list;

// Pass over the list. For each camera seen, if we already have a camera
Expand All @@ -173,79 +260,41 @@ FN_INTERNAL int fnusb_list_device_attributes(freenect_context *ctx, struct freen
libusb_device* camera_device = devs[i];

struct libusb_device_descriptor desc;
int res = libusb_get_device_descriptor (camera_device, &desc);
if (res < 0)
{
res = libusb_get_device_descriptor(camera_device, &desc);
if (res < 0) {
continue;
}

if (desc.idVendor == VID_MICROSOFT && (desc.idProduct == PID_NUI_CAMERA || desc.idProduct == PID_K4W_CAMERA))
{
// Verify that a serial number exists to query. If not, don't touch the device.
if (desc.iSerialNumber == 0)
{
continue;
}

libusb_device_handle *camera_handle;
res = libusb_open(camera_device, &camera_handle);
if (res != 0)
{
continue;
}

// Read string descriptor referring to serial number.
unsigned char serial[256]; // String descriptors are at most 256 bytes.
res = libusb_get_string_descriptor_ascii(camera_handle, desc.iSerialNumber, serial, 256);
libusb_close(camera_handle);
if (res < 0)
{
continue;
}
if (!fnusb_is_camera(desc)) {
continue;
}

// K4W and 1473 don't provide a camera serial; use audio serial instead.
const char* const K4W_1473_SERIAL = "0000000000000000";
if (strncmp((const char*)serial, K4W_1473_SERIAL, 16) == 0)
char* serial = usb_get_serial(ctx, camera_device, NULL, &desc);
if (serial == NULL)
{
libusb_device* audio_device = fnusb_find_sibling_device(ctx, camera_device, devs, count, &fnusb_is_audio);
if (audio_device != NULL)
{
libusb_device* audio_device = fnusb_find_sibling_device(ctx, camera_device, devs, count, &fnusb_is_audio);
if (audio_device != NULL)
{
struct libusb_device_descriptor audio_desc;
res = libusb_get_device_descriptor(audio_device, &audio_desc);
if (res != 0)
{
FN_WARNING("Failed to get audio serial descriptors of K4W or 1473 device: %s\n", libusb_error_name(res));
}
else
{
libusb_device_handle * audio_handle = NULL;
res = libusb_open(audio_device, &audio_handle);
if (res != 0)
{
FN_WARNING("Failed to open audio device for serial of K4W or 1473 device: %s\n", libusb_error_name(res));
}
else
{
res = libusb_get_string_descriptor_ascii(audio_handle, audio_desc.iSerialNumber, serial, 256);
libusb_close(audio_handle);
if (res <= 0)
{
FN_WARNING("Failed to get audio serial of K4W or 1473 device: %s\n", libusb_error_name(res));
}
}
}
char* audio_serial = usb_get_serial(ctx, audio_device, NULL, &desc);
if (audio_serial) {
free(serial);
serial = audio_serial;
}
}
}

// Add item to linked list.
struct freenect_device_attributes* current_attr = (struct freenect_device_attributes*)malloc(sizeof(struct freenect_device_attributes));
memset(current_attr, 0, sizeof(*current_attr));

current_attr->camera_serial = strdup((char*)serial);
*next_attr = current_attr;
next_attr = &(current_attr->next);
num_cams++;
if (serial == NULL) {
continue;
}

// Add item to linked list.
struct freenect_device_attributes* current_attr = (struct freenect_device_attributes*)malloc(sizeof(struct freenect_device_attributes));
memset(current_attr, 0, sizeof(*current_attr));

current_attr->camera_serial = serial;
*next_attr = current_attr;
next_attr = &(current_attr->next);
num_cams++;
}

libusb_free_device_list(devs, 1);
Expand Down Expand Up @@ -378,19 +427,29 @@ FN_INTERNAL int fnusb_keep_alive_led(freenect_context* ctx, libusb_device* audio
return res;
}

FN_INTERNAL void fnusb_reset_subdevice(fnusb_dev* dev, freenect_device* parent)
{
if (dev) {
if (dev->dev) {
libusb_release_interface(dev->dev, 0);
libusb_attach_kernel_driver(dev->dev, 0);
libusb_close(dev->dev);
dev->dev = NULL;
}
dev->parent = parent;
}
}

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;
fnusb_reset_subdevice(&dev->usb_cam, dev);
fnusb_reset_subdevice(&dev->usb_motor, dev);
fnusb_reset_subdevice(&dev->usb_audio, dev);

libusb_device **devs; // pointer to pointer of device, used to retrieve a list of devices
ssize_t count = libusb_get_device_list (dev->parent->usb.ctx, &devs); //get the list of devices
Expand Down Expand Up @@ -702,24 +761,9 @@ FN_INTERNAL int fnusb_open_subdevices(freenect_device *dev, int index)

FN_INTERNAL int fnusb_close_subdevices(freenect_device *dev)
{
if (dev->usb_cam.dev) {
libusb_release_interface(dev->usb_cam.dev, 0);
#ifndef _WIN32
libusb_attach_kernel_driver(dev->usb_cam.dev, 0);
#endif
libusb_close(dev->usb_cam.dev);
dev->usb_cam.dev = NULL;
}
if (dev->usb_motor.dev) {
libusb_release_interface(dev->usb_motor.dev, 0);
libusb_close(dev->usb_motor.dev);
dev->usb_motor.dev = NULL;
}
if (dev->usb_audio.dev) {
libusb_release_interface(dev->usb_audio.dev, 0);
libusb_close(dev->usb_audio.dev);
dev->usb_audio.dev = NULL;
}
fnusb_reset_subdevice(&dev->usb_cam, dev);
fnusb_reset_subdevice(&dev->usb_motor, dev);
fnusb_reset_subdevice(&dev->usb_audio, dev);
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/usb_libusb10.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ typedef struct {
} fnusb_isoc_stream;

int fnusb_num_devices(freenect_context *ctx);
int fnusb_get_device_attributes(freenect_device* dev, struct freenect_device_attributes* attributes);
int fnusb_list_device_attributes(freenect_context *ctx, struct freenect_device_attributes** attribute_list);

int fnusb_init(fnusb_ctx *ctx, freenect_usb_context *usb_ctx);
Expand Down