Skip to content

Instantly share code, notes, and snippets.

@avtolstoy
Last active May 26, 2016 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avtolstoy/083b6ea8ca9188c0742e9aee2d516b9b to your computer and use it in GitHub Desktop.
Save avtolstoy/083b6ea8ca9188c0742e9aee2d516b9b to your computer and use it in GitHub Desktop.
/*
******************************************************************************
* Copyright (c) 2015 Particle Industries, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
*/
#include "application.h"
#include "deviceid_hal.h"
uint8_t handleVendorRequest(HAL_USB_SetupRequest* req);
STARTUP(HAL_USB_Set_Vendor_Request_Callback(&handleVendorRequest, NULL));
Serial1LogHandler dbg(57600, LOG_LEVEL_ALL);
/*
* Use usbtool (https://github.com/avtolstoy/usbtool) to test requests.
*
* IN requests are Device -> Host (if wLength != 0, the data will be transmitted from device to the host)
* OUT requests are Host -> Device (if wLength != 0, the data will be transmitted from host to device)
* $ ./usbtool -v <VID> -p <PID> control <"in"|"out"> vendor device <bRequest> <wValue> <wIndex>
*
* REQUEST_GET_DEVICE_ID:
* $ ./usbtool -v 0x2b04 -p 0xc006 control in vendor device 0 0 0
*
* REQUST_GET_DEVICE_ID as string (wValue = 1):
* $ ./usbtool -b -v 0x2b04 -p 0xc006 control in vendor device 0 1 0
*
* REQUEST_ENTER_MODE ENTER_MODE_DFU:
* $ ./usbtool -v 0x2b04 -p 0xc006 control out vendor device 1 0 1
*
* Transfer some data to the device
* $ ./usbtool -d 0x00,0x01,0x02,0x03,0x04,0x05,0x06 -v 0x2b04 -p 0xc006 control out vendor device 10 10 10
* 0000004559 app: application.cpp:113, handleVendorRequest(): INFO: Request Host->Dev bmRequestType=0x40 bRequest=0xa wValue=0xa wIndex=0xa wLength=0x6
* 0000004559 app: application.cpp:120, handleVendorRequest(): INFO: Request data=000102040506
*/
enum SetupRequest {
REQUEST_GET_DEVICE_ID = 0x00,
REQUEST_ENTER_MODE = 0x01,
#if Wiring_WiFi
REQUEST_GET_WIFI_PARAMETER = 0x02,
REQUEST_SET_WIFI_PARAMETER = 0x03,
#endif
#if Wiring_Cellular
REQUEST_GET_CELLULAR_PARAMETER = 0x05,
#endif
};
enum EnterMode {
ENTER_MODE_SAFE_MODE = 0x00,
ENTER_MODE_DFU = 0x01,
ENTER_MODE_YMODEM = 0x02,
};
#if Wiring_WiFi
enum WifiParameter {
WIFI_PARAMETER_SSID = 0x00,
WIFI_PARAMETER_MAC_ADDRESS = 0x01,
};
#endif
#if Wiring_Cellular
enum CellularParameter {
CELLULAR_PARAMETER_IMEI = 0x00,
CELLULAR_PARAMETER_ICCID = 0x01,
};
#endif
/* executes once at startup */
void setup() {
Serial.begin(9600);
}
/* executes continuously after setup() runs */
void loop() {
Serial.println("Alive");
delay(1000);
}
inline void concat_nibble(String& result, uint8_t nibble)
{
char hex_digit = nibble + 48;
if (57 < hex_digit)
hex_digit += 39;
result.concat(hex_digit);
}
String bytes2hex(const uint8_t* buf, unsigned len)
{
String result;
for (unsigned i = 0; i < len; ++i)
{
concat_nibble(result, (buf[i] >> 4));
concat_nibble(result, (buf[i] & 0xF));
}
return result;
}
// Will be called from USB interrupt handler
uint8_t handleVendorRequest(HAL_USB_SetupRequest* req) {
INFO("Request %s bmRequestType=0x%x bRequest=0x%x wValue=0x%x wIndex=0x%x wLength=0x%x", req->bmRequestType & 0x80 ? "Dev->Host" : "Host->Dev",
req->bmRequestType, req->bRequest, req->wValue,
req->wIndex, req->wLength);
// Direction = OUT (Host -> Device)
if (!req->bmRequestTypeDirection && req->wLength > 0) {
// Host->Device
INFO("Request data=%s", bytes2hex(req->data, req->wLength).c_str());
}
if (req->data) {
memset(req->data, 0, HAL_USB_SETUP_REQUEST_MAX_DATA);
}
uint8_t ret = 0;
// OUT (Host -> Device) requests
if (!req->bmRequestTypeDirection) {
switch(req->bRequest) {
case REQUEST_ENTER_MODE: {
switch(req->wIndex) {
case ENTER_MODE_SAFE_MODE:
System.enterSafeMode();
break;
case ENTER_MODE_DFU:
System.dfu();
break;
case ENTER_MODE_YMODEM:
// ?
break;
default:
ret = 0;
break;
}
}
break;
default:
ret = 1;
break;
}
} else {
// IN (Device -> Host) requests
switch (req->bRequest) {
case REQUEST_GET_DEVICE_ID:
if (req->data) {
if (req->wValue == 1) {
String id = System.deviceID();
strncpy((char*)req->data, id.c_str(), req->wLength);
req->wLength = id.length() + 1;
} else {
HAL_device_ID(req->data, req->wLength);
req->wLength = 12;
}
}
break;
#if Wiring_WiFi
case REQUEST_GET_WIFI_PARAMETER: {
switch(req->wIndex) {
case WIFI_PARAMETER_MAC_ADDRESS:
if (req->data) {
WiFi.macAddress(req->data);
req->wLength = 6;
}
break;
case WIFI_PARAMETER_SSID:
if (req->data) {
strncpy((char*)req->data, WiFi.SSID(), req->wLength);
req->wLength = strlen(WiFi.SSID()) + 1;
}
break;
default:
ret = 1;
break;
}
}
break;
#endif // Wiring_WiFi
#if Wiring_Cellular
case REQUEST_GET_CELLULAR_PARAMETER: {
CellularDevice dev;
cellular_device_info(&dev, NULL);
switch(req->wIndex) {
case CELLULAR_PARAMETER_IMEI:
if (req->data)
strncpy((char*)req->data, dev.imei, req->wLength);
req->wLength = strlen(dev.imei) + 1;
break;
case CELLULAR_PARAMETER_ICCID:
if (req->data)
strncpy((char*)req->data, dev.iccid, req->wLength);
req->wLength = strlen(dev.iccid) + 1;
break;
default:
ret = 1;
break;
}
}
break;
#endif // Wiring_Cellular
default:
ret = 1;
break;
}
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment