neuralSPOT USB Library
This library simplifies the use of USB to create CDC and WebUSB Devices. It is used by ns-rpc to connect to the remote RPC server or client, and by the Vision and Image Classification examples to connect to WebUSB applications.
Creating a WebUSB Device
Creating a WebUSB can be done in a handful of instructions. See the Image Classification example for a application using this library.
Init Configs
uint8_t my_rx_ff_buf[4096];
uint8_t my_tx_ff_buf[4096];
// WebUSB URL
static ns_tusb_desc_webusb_url_t ic_url;
// WebUSB Config
static ns_usb_config_t webUsbConfig = {
.api = &ns_usb_V1_0_0,
.deviceType = NS_USB_VENDOR_DEVICE,
.rx_buffer = NULL,
.rx_bufferLength = 0,
.tx_buffer = NULL,
.tx_bufferLength = 0,
.rx_cb = NULL,
.tx_cb = NULL,
.service_cb = NULL,
.desc_url = &ic_url
};
In Main
webusb_register_msg_cb(msgReceived, NULL); // See below for incoming message handling
// instantiate the URL descriptor - this will be used by browser pop-up note
strcpy(ic_url.url, "ambiqai.github.io/web-ble-dashboards/ic_demo/");
ic_url.bDescriptorType = 3;
ic_url.bScheme = 1;
ic_url.bLength = 3 + sizeof(ic_url.url) - 1;
// Initialize USB
webUsbConfig.rx_buffer = my_rx_ff_buf;
webUsbConfig.rx_bufferLength = 4096;
webUsbConfig.tx_buffer = my_tx_ff_buf;
webUsbConfig.tx_bufferLength = 4096;
NS_TRY(ns_usb_init(&webUsbConfig, &usb_handle), "USB Init Failed\n");
WebUSB lets you send and receive messages across USB. The contents of the message is treated as a 'blob', and it is up to the application to decode that blob on both ends.
Sending a message
// USB Data sent to WebUSB client
typedef struct usb_data { // App-defined 'blob'
uint8_t type;
uint8_t length;
uint8_t classId;
uint8_t confidence;
uint8_t fps;
uint8_t joulesEstimate;
uint8_t cpuUtilization;
} usb_data_t;
void sendMessage(
uint8_t type, uint8_t classId, uint8_t confidence, uint8_t fps, uint8_t joulesEstimate,
uint8_t cpuUtilization) {
usb_data_t data = {
.type = type,
.length = sizeof(usb_data_t),
.classId = classId,
.confidence = confidence,
.fps = fps,
.joulesEstimate = joulesEstimate,
.cpuUtilization = cpuUtilization};
// Send the data to the WebUSB client as an array of bytes
webusb_send_data((uint8_t *)&data, sizeof(usb_data_t));
}
Receiving a message operates on the same principle with one important caveat: the sender must add a 2-byte header (0x0002) to tell the WebUSB driver how to route the packet.
Receiver
void msgReceived(const uint8_t *buffer, uint32_t length, void *args) {
// The message contains information about how to set the camera
ns_camera_adjust_settings(buffer[0], buffer[1], buffer[2]);
}
Sender (in Javascript)
function sendCameraMessage() {
console.log("sending camera message");
let cameraMessage = new Uint8Array(6);
// Send header
cameraMessage[0] = 0x00;
cameraMessage[1] = 0x02;
// Send values
cameraMessage[2] = contrastValue;
cameraMessage[3] = brightnessValue;
cameraMessage[4] = evValue;
port.send(cameraMessage);
}