File webusb_controller.c
File List > neuralSPOT > neuralspot > ns-usb > src > overrides > webusb_controller.c
Go to the documentation of this file
//*****************************************************************************
//
//*****************************************************************************
//*****************************************************************************
//
// ${copyright}
//
// This is part of revision ${version} of the AmbiqSuite Development Package.
//
//*****************************************************************************
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "webusb_controller.h"
#include "usb_descriptors.h"
#include "ns_usb.h"
#include "tusb.h"
#include "am_util_debug.h"
#include "ns_ambiqsuite_harness.h"
//--------------------------------------------------------------------+
// Structure definitions
//--------------------------------------------------------------------+
typedef struct {
webusb_rx_cb rx_msg_cb;
webusb_rx_cb rx_raw_cb;
void *rx_msg_param;
void *rx_raw_param;
} webusb_parameter_t;
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
#define BYTES_TO_UINT16(n, p) \
{ n = (((uint16_t)(p)[0] << 8) + (uint16_t)(p)[1]); }
#define BSTREAM_TO_UINT16(n, p) \
{ \
BYTES_TO_UINT16(n, p); \
p += 2; \
}
// Microsoft OS 2.0 compatible descriptor
#define DESC_MS_OS_20 7
#define WEBUSB_REQUEST_SET_CONTROL_LINE_STATE 0x22
#define REWRIT_NUMBER 40 // allow for long blocks to be sent in parts
// The max of USB2.0 bulk type packet size is 512 in High Speed.
static uint8_t rx_buf[512];
// WebUSB connections status
static bool webusb_connected = false;
static webusb_parameter_t webusb_parameter = {
.rx_msg_cb = NULL,
.rx_raw_cb = NULL,
.rx_msg_param = NULL,
.rx_raw_param = NULL,
};
// The type of frame received via WebUSB
enum {
RX_INVALID = 0,
RX_ACORE_MSG = 1, // Audio core message
RX_RAW_DATA = 2, // Raw data
};
// ****************************************************************************
//
//
// Further note: Armlink laughs in the face of this attempt to keep weak functions.
// It may or may not include them based on some internal whimsical logic. See
// neuralspot_toolchainmk to see how we work around this.
// ****************************************************************************
// volatile const void *pTUSB_WeakFcnPointers[] = {
// (void *)tud_mount_cb,
// #ifndef TUSB_ADDED_FUNCTIONS
// (void *)tud_umount_cb,
// #endif
// (void *)tud_suspend_cb, (void *)tud_resume_cb, (void *)tud_vendor_rx_cb,
// };
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void) { webusb_connected = false; }
#ifndef TUSB_ADDED_FUNCTIONS
// Invoked when device is unmounted
void tud_umount_cb(void) { webusb_connected = false; }
#endif
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en) {
(void)remote_wakeup_en;
webusb_connected = false;
}
// Invoked when usb bus is resumed
void tud_resume_cb(void) { webusb_connected = false; }
// Invoked when received new data
void tud_vendor_rx_cb(uint8_t itf) {
(void)itf;
uint32_t bytes_rx = 0;
// check whether the remain size of RX ring-buffer is zero
while (tud_vendor_available()) {
uint16_t frame_header = 0;
uint8_t *p = rx_buf;
bytes_rx = tud_vendor_read(rx_buf, sizeof(rx_buf));
// The size of frame header is 2.
BSTREAM_TO_UINT16(frame_header, p);
// Skip frame header, then transfer buffer to callback function
switch (frame_header) {
case RX_ACORE_MSG:
if (webusb_parameter.rx_msg_cb) {
webusb_parameter.rx_msg_cb(
p, bytes_rx - sizeof(frame_header), webusb_parameter.rx_msg_param);
}
break;
case RX_RAW_DATA:
if (webusb_parameter.rx_raw_cb) {
webusb_parameter.rx_raw_cb(
p, bytes_rx - sizeof(frame_header), webusb_parameter.rx_raw_param);
}
break;
default:
ns_lp_printf("Error: Unsupported type of Rx Frame Header: %d\n", frame_header);
break;
}
}
}
//--------------------------------------------------------------------+
// WebUSB use vendor class
//--------------------------------------------------------------------+
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage
// (setup/data/ack) return false to stall control endpoint (e.g unsupported
// request)
bool tud_vendor_control_xfer_cb(
uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
ns_tusb_desc_webusb_url_t * desc_url = ns_get_desc_url();
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case VENDOR_REQUEST_WEBUSB:
// match vendor request in BOS descriptor
// Get landing page url
return tud_control_xfer(
rhport, request, (void *)(uintptr_t)desc_url, desc_url->bLength);
case VENDOR_REQUEST_MICROSOFT:
if (request->wIndex == DESC_MS_OS_20) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, desc_ms_os_20 + 8, 2);
return tud_control_xfer(
rhport, request, (void *)(uintptr_t)desc_ms_os_20, total_len);
} else {
return false;
}
default:
break;
}
break;
case TUSB_REQ_TYPE_CLASS:
if (request->bRequest == WEBUSB_REQUEST_SET_CONTROL_LINE_STATE) {
// Receive the webusb line state
if (request->wValue != 0) {
webusb_connected = true;
} else {
webusb_connected = false;
}
// response with status OK
return tud_control_status(rhport, request);
}
break;
default:
break;
}
// stall unknown request
return false;
}
uint32_t webusb_send_data(uint8_t *buf, uint32_t bufsize) {
uint32_t bytes_tx = 0;
uint32_t bufremain = bufsize;
// Print first 20 bytes of buffer
// ns_lp_printf("Sending %d bytes: ", bufsize);
// for (int i = 0; i < 5; i++) {
// ns_lp_printf("0x%02x ", buf[i]);
// }
// ns_lp_printf("\n");
if (webusb_connected && buf) {
int i = 0;
do {
// When buf can't be written all at once, write again
// until the upper limit of rewrite numbers is reached or buf is
// written all.
if (i == REWRIT_NUMBER) {
ns_lp_printf("Warning: The number of rewriting is over %d\n", i);
break;
}
// bytes_tx = tud_vendor_write_pkt((void *)(buf + bufsize - bufremain), bufremain);
bytes_tx = tud_vendor_write((void *)(buf + bufsize - bufremain), bufremain);
// tud_vendor_write_flush();
// ns_lp_printf("Sent %d of %d bytes\n", bytes_tx, bufsize);
bufremain -= bytes_tx;
i++;
} while (bufremain);
}
if (bufremain) {
// Collects the amount of data that has not been written
}
return bufsize - bufremain;
}
// void webusb_task(void) { tud_task(); }
// void webusb_init(void) {
// // init tinyusb
// tusb_init();
// }
void webusb_register_msg_cb(webusb_rx_cb cb, void *param) {
webusb_parameter.rx_msg_cb = cb;
webusb_parameter.rx_msg_param = param;
}
void webusb_register_raw_cb(webusb_rx_cb cb, void *param) {
webusb_parameter.rx_raw_cb = cb;
webusb_parameter.rx_raw_param = param;
}