Skip to content

Commit

Permalink
Added support for USB control transfer
Browse files Browse the repository at this point in the history
Device.controlTransfer(bytesToRead, bmRequestType, bRequest, 0, 0, function(data) {}) works as expected.
data will be a node.js buffer object which makes byte manipulation easy.
I update the Kinect example to read the accelerometer axes from the device (taken from ladyada.net/leran/diykinect).
  • Loading branch information
Christopher Klein committed Mar 24, 2012
1 parent 7b78e10 commit 59d3d99
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Makefile
@@ -1,5 +1,5 @@
make:
node-waf configure clean build; node tests/node-usb-test.js
node-waf -v configure clean build; node tests/node-usb-test.js

debug:
node-waf configure --debug=true clean build; node tests/node-usb-test.js
Expand Down
18 changes: 18 additions & 0 deletions examples/kinect/kinect.js
Expand Up @@ -46,6 +46,7 @@ http.createServer(function(req, res) {
req.on('data', function(data) { incomingBody += data; });
req.on('end', function() {
var postData = qs.parse(incomingBody);
var bulkOutput = "<strong>no data</strong>";

switch (req.url) {
case '/updateLed':
Expand Down Expand Up @@ -77,6 +78,22 @@ console.log("Angle set to " + angle);
console.log(" + Angle set");
});

break;
case '/getCoordinates':
motor.controlTransfer(10 /* read 10 bytes */, 0xC0 /* bmRequestType */, 0x32 /* bRequest */, 0, 0, function(data) {
for (var i = 0; i < 10; i++) {
console.log("buffer[" + i + "]: " + data[i])
}
console.log("Accelerometer axis:")
var x = ((data[2] << 8) | data[3]), y = ((data[4] << 8) | data[5]), z = ((data[6] << 8) | data[7])
x = (x + Math.pow(2,15)) % Math.pow(2,16) - Math.pow(2,15)
y = (y + Math.pow(2,15)) % Math.pow(2,16) - Math.pow(2,15)
z = (z + Math.pow(2,15)) % Math.pow(2,16) - Math.pow(2,15)

console.log(" X:" + x)
console.log(" Y:" + y)
console.log(" Z:" + z)
})
break;
}
});
Expand All @@ -91,6 +108,7 @@ console.log("Angle set to " + angle);
html += "</select><input type='submit' value='change color' /></form>";
html += "<form method='post' action='updateAngle'>";
html += "Set angle (-31 - +31) <input type='text' name='angle' size='2' /><input type='submit' value='change angle'/></form>";
html += "<a href='/getCoordinates'>Retrieve coordinates from Kinect via control transfer</a>";
html += "</body></html>";

res.write(html);
Expand Down
50 changes: 38 additions & 12 deletions src/bindings.h
Expand Up @@ -76,22 +76,25 @@
} \
VARNAME->callback = Persistent<Function>::New(callback);

#define EIO_HANDLE_ERROR(VARNAME) \
if(VARNAME->errsource) { \
Handle<Object> error = Object::New(); \
error->Set(V8SYM("error_source"), V8STR(VARNAME->errsource)); \
error->Set(V8SYM("error_code"), Uint32::New(VARNAME->errcode)); \
Local<Value> argv[1]; \
argv[0] = Local<Value>::New(scope.Close(error)); \
TryCatch try_catch; \
VARNAME->callback->Call(Context::GetCurrent()->Global(), 1, argv); \
if (try_catch.HasCaught()) { \
FatalException(try_catch); \
} \
}

#define EIO_AFTER(VARNAME, SELF) \
uv_unref(uv_default_loop()); \
if (!VARNAME->callback.IsEmpty()) { \
HandleScope scope; \
Handle<Object> error = Object::New(); \
if(VARNAME->errsource) { \
error->Set(V8SYM("error_source"), V8STR(VARNAME->errsource)); \
} \
error->Set(V8SYM("error_code"), Uint32::New(VARNAME->errcode)); \
Local<Value> argv[1]; \
argv[0] = Local<Value>::New(scope.Close(error)); \
TryCatch try_catch; \
VARNAME->callback->Call(Context::GetCurrent()->Global(), 1, argv); \
if (try_catch.HasCaught()) { \
FatalException(try_catch); \
} \
EIO_HANDLE_ERROR(VARNAME) \
VARNAME->callback.Dispose(); \
}\
delete req;\
Expand All @@ -100,6 +103,28 @@
#define TRANSFER_REQUEST_FREE(STRUCT, SELF)\
EIO_CAST(STRUCT, transfer_req)\
EIO_AFTER(transfer_req, SELF)\
free(transfer_req);

#define TRANSFER_REQUEST_FREE_WITH_DATA(STRUCT, SELF)\
EIO_CAST(STRUCT, transfer_req)\
uv_unref(uv_default_loop()); \
if (!transfer_req->callback.IsEmpty()) { \
HandleScope scope; \
EIO_HANDLE_ERROR(transfer_req) \
if (!transfer_req->errsource) {\
Buffer *result = Buffer::New((char *)transfer_req->data, transfer_req->bytesTransferred); \
Local<Value> argv[1]; \
argv[0] = Local<Value>::New(result->handle_); \
TryCatch try_catch; \
transfer_req->callback->Call(Context::GetCurrent()->Global(), 1, argv); \
if (try_catch.HasCaught()) { \
FatalException(try_catch); \
} \
}\
transfer_req->callback.Dispose(); \
}\
delete req;\
transfer_req->SELF->Unref();\
free(transfer_req);\

#define INIT_TRANSFER_CALL(MINIMUM_ARG_LENGTH, CALLBACK_ARG_IDX, TIMEOUT_ARG_IDX) \
Expand Down Expand Up @@ -222,6 +247,7 @@ namespace NodeUsb {
err = "Unknown error";
break;
}

// convert err to const char* with help of c_str()
obj->Set(NODE_PSYMBOL("msg"), String::New(err.c_str()));
return e;
Expand Down
9 changes: 6 additions & 3 deletions src/device.cc
Expand Up @@ -391,13 +391,16 @@ namespace NodeUsb {
Device * self = ct_req->device;
libusb_device_handle * handle = self->device_container->handle;

ct_req->errcode = libusb_control_transfer(handle, ct_req->bmRequestType, ct_req->bRequest, ct_req->wValue, ct_req->wIndex, ct_req->data, ct_req->wLength, ct_req->timeout);
if (ct_req->errcode < LIBUSB_SUCCESS) {
ct_req->bytesTransferred = libusb_control_transfer(handle, ct_req->bmRequestType, ct_req->bRequest, ct_req->wValue, ct_req->wIndex, ct_req->data, ct_req->wLength, ct_req->timeout);

if (ct_req->bytesTransferred < LIBUSB_SUCCESS) {
ct_req->errcode = ct_req->bytesTransferred;
ct_req->bytesTransferred = 0;
ct_req->errsource = "controlTransfer";
}
}

void Device::EIO_After_ControlTransfer(uv_work_t *req) {
TRANSFER_REQUEST_FREE(control_transfer_request, device)
TRANSFER_REQUEST_FREE_WITH_DATA(control_transfer_request, device)
}
}
1 change: 1 addition & 0 deletions src/device.h
Expand Up @@ -13,6 +13,7 @@ namespace NodeUsb {
struct nodeusb_transfer:device_request {
unsigned char *data;
unsigned int timeout;
uint16_t bytesTransferred;
};

struct control_transfer_request:nodeusb_transfer {
Expand Down
16 changes: 9 additions & 7 deletions src/node_usb.h
@@ -1,23 +1,25 @@
#ifndef SRC_NODE_USB_H
#define SRC_NODE_USB_H

#include <libusb.h>
#include <v8.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <iostream>

#include <stdio.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <cstdlib>

#include <libusb.h>
#include <v8.h>

#include <node.h>
#include <node_version.h>
#include <node_buffer.h>
#include <uv.h>
#include <uv-private/ev.h>
#include <cstring>
#include <string>
#include <cstdlib>

#define NODE_USB_VERSION "0.1"

Expand Down
2 changes: 1 addition & 1 deletion usb.js
@@ -1,7 +1,7 @@
/**
* Expose complete node-usb binding to node.js
*/
var binding = require("usb_bindings");
var binding = require("./usb_bindings");

exports.create = function() {
var usbInstance = new binding.Usb();
Expand Down
6 changes: 3 additions & 3 deletions wscript
Expand Up @@ -28,7 +28,7 @@ def build(bld):
obj.target = 'usb_bindings'
obj.source = './src/node_usb.cc ./src/usb.cc ./src/device.cc ./src/interface.cc ./src/endpoint.cc'
obj.includes = bld.env['CPPPATH_USB10']
obj.lib = bld.env['LIB_USB10']
obj.uselib = ["USB10"]
obj.name = "node-usb"
obj.defines = ['NODE_USB_REVISION="' + REVISION + '"']

Expand All @@ -38,5 +38,5 @@ def build(bld):
def shutdown():
t = 'usb_bindings.node';

if exists('build/default/' + t) and not exists(t):
symlink('build/default/' + t, t)
if exists('build/Release/' + t) and not exists(t):
symlink('build/Release/' + t, t)

0 comments on commit 59d3d99

Please sign in to comment.