Skip to content

Commit

Permalink
Restructured files for easier developing
Browse files Browse the repository at this point in the history
- bindings.cc removed
- every class in NodeUsb namespace has their own .h and .cc file
- added callback handling USB packet submission
  • Loading branch information
Christopher Klein committed Nov 18, 2010
1 parent 886de4c commit af227af
Show file tree
Hide file tree
Showing 13 changed files with 894 additions and 826 deletions.
737 changes: 0 additions & 737 deletions src/bindings.cc

This file was deleted.

148 changes: 62 additions & 86 deletions src/bindings.h
Expand Up @@ -16,104 +16,80 @@
#define DEBUG(str)
#endif

namespace NodeUsb {
class Usb : public EventEmitter {
public:
static void Initalize(Handle<Object> target);
Usb();
~Usb();

protected:
// members
bool is_initalized;
int num_devices;
libusb_device **devices;
// internal methods
int Init();
#define THROW_BAD_ARGS(fail) return ThrowException(Exception::TypeError(V8STR(fail)));
#define THROW_NOT_YET return ThrowException(Exception::TypeError(String::Concat(String::New(__FUNCTION__), String::New("not yet supported"))));
#define CHECK_USB(r, scope) \
if (r < LIBUSB_SUCCESS) { \
return scope.Close(ThrowException(errno_exception(r)));\
}

// V8 getter
static Handle<Value> IsLibusbInitalizedGetter(Local<String> property, const AccessorInfo &info);

// exposed to V8
static Handle<Value> New(const Arguments& args);
static Handle<Value> GetDeviceList(const Arguments& args);
static Handle<Value> Refresh(const Arguments& args);
static Handle<Value> Close(const Arguments& args);
};
#define LOCAL(type, varname, ref) \
HandleScope scope;\
type *varname = OBJUNWRAP<type>(ref);

class Device : public EventEmitter {
public:
// called from outside to initalize V8 class template
static void Initalize(Handle<Object> target);
static Persistent<FunctionTemplate> constructor_template;
Device(libusb_device*);
~Device();

protected:
// members
struct libusb_device *device;
struct libusb_device_descriptor device_descriptor;
struct libusb_config_descriptor *config_descriptor;
namespace NodeUsb {
static inline Local<Value> errno_exception(int errorno) {
Local<Value> e = Exception::Error(String::NewSymbol(strerror(errorno)));
Local<Object> obj = e->ToObject();
std::string err = "";

obj->Set(NODE_PSYMBOL("errno"), Integer::New(errorno));
// taken from pyusb
switch (errorno) {
case LIBUSB_ERROR_IO:
err = "Input/output error";
break;
case LIBUSB_ERROR_INVALID_PARAM:
err = "Invalid parameter";
break;
case LIBUSB_ERROR_ACCESS:
err = "Access denied (insufficient permissions)";
break;
case LIBUSB_ERROR_NO_DEVICE:
err = "No such device (it may have been disconnected)";
break;
case LIBUSB_ERROR_NOT_FOUND:
err = "Entity not found";
break;
case LIBUSB_ERROR_BUSY:
err = "Resource busy";
break;
case LIBUSB_ERROR_TIMEOUT:
err = "Operation timed out";
break;
case LIBUSB_ERROR_OVERFLOW:
err = "Overflow";
break;
case LIBUSB_ERROR_PIPE:
err = "Pipe error";
break;
case LIBUSB_ERROR_INTERRUPTED:
err = "System call interrupted (perhaps due to signal)";
break;
case LIBUSB_ERROR_NO_MEM:
err = "Insufficient memory";
break;
case LIBUSB_ERROR_NOT_SUPPORTED:
err = "Operation not supported or unimplemented on this platform";
break;
default:
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;
}

// V8 getter
static Handle<Value> BusNumberGetter(Local<String> property, const AccessorInfo &info);
static Handle<Value> DeviceAddressGetter(Local<String> property, const AccessorInfo &info);

// exposed to V8
static Handle<Value> New(const Arguments& args);
static Handle<Value> Close(const Arguments& args);
static Handle<Value> Reset(const Arguments& args);
static Handle<Value> GetConfigDescriptor(const Arguments& args);
static Handle<Value> GetDeviceDescriptor(const Arguments& args);
};

class Interface : public EventEmitter {
public:
static void Initalize(Handle<Object> target);
static Persistent<FunctionTemplate> constructor_template;
Interface(libusb_device*, libusb_interface_descriptor*);
~Interface();

protected:
// members
struct libusb_device *device;
struct libusb_device_handle *handle;
struct libusb_interface_descriptor *descriptor;
// V8 getter
static Handle<Value> IsKernelDriverActiveGetter(Local<String> property, const AccessorInfo &info);
// exposed to V8
static Handle<Value> New(const Arguments& args);
};

class Callback {
public:
static void DispatchAsynchronousUsbTransfer(libusb_transfer *transfer);
};

class Endpoint : public EventEmitter {
public:
static void Initalize(Handle<Object> target);
static Persistent<FunctionTemplate> constructor_template;
// Dispatcher / callback handler must be static
Endpoint(libusb_device*, libusb_endpoint_descriptor*);
~Endpoint();
protected:
// members
struct libusb_device *device;
struct libusb_device_handle *handle;
struct libusb_endpoint_descriptor *descriptor;
int endpoint_type;
int transfer_type;

int FillTransferStructure(libusb_transfer *_transfer, unsigned char *_buffer, void *_user_data, uint32_t _timeout, unsigned int num_iso_packets = 0);

// v8 getter
static Handle<Value> EndpointTypeGetter(Local<String> property, const AccessorInfo &info);
static Handle<Value> TransferTypeGetter(Local<String> property, const AccessorInfo &info);
// exposed to V8
static Handle<Value> New(const Arguments& args);
static Handle<Value> Write(const Arguments& args);

};
}
#endif
202 changes: 202 additions & 0 deletions src/device.cc
@@ -0,0 +1,202 @@
#include "bindings.h"
#include "device.h"
#include "interface.h"
#include "endpoint.h"

namespace NodeUsb {
/** constructor template is needed for creating new Device objects from outside */
Persistent<FunctionTemplate> Device::constructor_template;

/**
* @param device.busNumber integer
* @param device.deviceAddress integer
*/
void Device::Initalize(Handle<Object> target) {
DEBUG("Entering...")
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(Device::New);

// Constructor
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(String::NewSymbol("Device"));
Device::constructor_template = Persistent<FunctionTemplate>::New(t);

Local<ObjectTemplate> instance_template = t->InstanceTemplate();

// Constants
// no constants at the moment

// Properties
instance_template->SetAccessor(V8STR("deviceAddress"), Device::DeviceAddressGetter);
instance_template->SetAccessor(V8STR("busNumber"), Device::BusNumberGetter);

// Bindings to nodejs
NODE_SET_PROTOTYPE_METHOD(t, "reset", Device::Reset);
NODE_SET_PROTOTYPE_METHOD(t, "getDeviceDescriptor", Device::GetDeviceDescriptor);
NODE_SET_PROTOTYPE_METHOD(t, "getConfigDescriptor", Device::GetConfigDescriptor);

// Make it visible in JavaScript
target->Set(String::NewSymbol("Device"), t->GetFunction());
DEBUG("Leave")
}

Device::Device(libusb_device* _device) {
DEBUG("Assigning libusb_device structure to self")
device = _device;
config_descriptor = NULL;
}

Device::~Device() {
DEBUG("Device object destroyed")
}

Handle<Value> Device::New(const Arguments& args) {
HandleScope scope;
DEBUG("New Device object created")

// need libusb_device structure as first argument
if (args.Length() <= 0 || !args[0]->IsExternal()) {
THROW_BAD_ARGS("Device::New argument is invalid. Must be external!")
}

Local<External> refDevice = Local<External>::Cast(args[0]);

// cast local reference to local libusb_device structure
libusb_device *libusbDevice = static_cast<libusb_device*>(refDevice->Value());

// create new Device object
Device *device = new Device(libusbDevice);

// wrap created Device object to v8
device->Wrap(args.This());

return args.This();
}

/**
* @return integer
*/
Handle<Value> Device::BusNumberGetter(Local<String> property, const AccessorInfo &info) {
LOCAL(Device, self, info.Holder())
uint8_t bus_number = libusb_get_bus_number(self->device);

return scope.Close(Integer::New(bus_number));
}

/**
* @return integer
*/
Handle<Value> Device::DeviceAddressGetter(Local<String> property, const AccessorInfo &info) {
LOCAL(Device, self, info.Holder())
uint8_t address = libusb_get_device_address(self->device);

return scope.Close(Integer::New(address));
}

Handle<Value> Device::Reset(const Arguments& args) {
HandleScope scope;
THROW_NOT_YET
return scope.Close(True());
}


// TODO: Read-Only
#define LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(name) \
r->Set(V8STR(#name), Integer::New((*self->config_descriptor).name));

/**
* Returns configuration descriptor structure
*/
Handle<Value> Device::GetConfigDescriptor(const Arguments& args) {
// make local value reference to first parameter
Local<External> refDevice = Local<External>::Cast(args[0]);

LOCAL(Device, self, args.This())
CHECK_USB(libusb_get_active_config_descriptor(self->device, &(self->config_descriptor)), scope)
Local<Object> r = Object::New();

LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(bLength)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(bDescriptorType)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(wTotalLength)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(bNumInterfaces)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(bConfigurationValue)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(iConfiguration)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(bmAttributes)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(MaxPower)
LIBUSB_CONFIG_DESCRIPTOR_STRUCT_TO_V8(extra_length)

Local<Array> interfaces = Array::New();

// iterate interfaces
for (int i = 0; i < (*self->config_descriptor).bNumInterfaces; i++) {
libusb_interface interface_container = (*self->config_descriptor).interface[i];

for (int j = 0; j < interface_container.num_altsetting; j++) {
libusb_interface_descriptor interface_descriptor = interface_container.altsetting[j];

Local<Value> args_new_interface[2] = {
External::New(self->device),
External::New(&interface_descriptor),
};

// create new object instance of class NodeUsb::Interface
Persistent<Object> js_interface(Interface::constructor_template->GetFunction()->NewInstance(2, args_new_interface));
Local<Array> endpoints = Array::New();

// interate endpoints
for (int k = 0; k < interface_descriptor.bNumEndpoints; k++) {
libusb_endpoint_descriptor endpoint_descriptor = interface_descriptor.endpoint[k];

Local<Value> args_new_endpoint[2] = {
External::New(self->device),
External::New(&endpoint_descriptor),
};

// create new object instance of class NodeUsb::Endpoint
Persistent<Object> js_endpoint(Endpoint::constructor_template->GetFunction()->NewInstance(2, args_new_endpoint));
endpoints->Set(k, js_endpoint);
}

js_interface->Set(V8STR("endpoints"), endpoints);
interfaces->Set(i, js_interface);
}
}

r->Set(V8STR("interfaces"), interfaces);
// free it
libusb_free_config_descriptor(self->config_descriptor);

return scope.Close(r);
}

// TODO: Read-Only
#define LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(name) \
r->Set(V8STR(#name), Integer::New(self->device_descriptor.name));

/**
* Returns the device descriptor of current device
* @return object
*/
Handle<Value> Device::GetDeviceDescriptor(const Arguments& args) {
LOCAL(Device, self, args.This())
CHECK_USB(libusb_get_device_descriptor(self->device, &(self->device_descriptor)), scope)
Local<Object> r = Object::New();

LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bLength)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bDescriptorType)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bcdUSB)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bDeviceClass)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bDeviceSubClass)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bDeviceProtocol)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bMaxPacketSize0)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(idVendor)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(idProduct)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bcdDevice)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(iManufacturer)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(iProduct)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(iSerialNumber)
LIBUSB_DEVICE_DESCRIPTOR_STRUCT_TO_V8(bNumConfigurations)

return scope.Close(r);
}
}

0 comments on commit af227af

Please sign in to comment.